UNPKG

31.4 kBJavaScriptView Raw
1/*
2Copyright (c) 2020-present NAVER Corp.
3name: @egjs/imready
4license: MIT
5author: NAVER Corp.
6repository: https://github.com/naver/egjs-imready
7version: 1.1.4
8*/
9'use strict';
10
11var Component = require('@egjs/component');
12
13/*! *****************************************************************************
14Copyright (c) Microsoft Corporation.
15
16Permission to use, copy, modify, and/or distribute this software for any
17purpose with or without fee is hereby granted.
18
19THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
20REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
21AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
22INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
23LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
24OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
25PERFORMANCE OF THIS SOFTWARE.
26***************************************************************************** */
27
28/* global Reflect, Promise */
29var extendStatics = function (d, b) {
30 extendStatics = Object.setPrototypeOf || {
31 __proto__: []
32 } instanceof Array && function (d, b) {
33 d.__proto__ = b;
34 } || function (d, b) {
35 for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p];
36 };
37
38 return extendStatics(d, b);
39};
40
41function __extends(d, b) {
42 extendStatics(d, b);
43
44 function __() {
45 this.constructor = d;
46 }
47
48 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
49}
50var __assign = function () {
51 __assign = Object.assign || function __assign(t) {
52 for (var s, i = 1, n = arguments.length; i < n; i++) {
53 s = arguments[i];
54
55 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
56 }
57
58 return t;
59 };
60
61 return __assign.apply(this, arguments);
62};
63function __spreadArrays() {
64 for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
65
66 for (var r = Array(s), k = 0, i = 0; i < il; i++) for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) r[k] = a[j];
67
68 return r;
69}
70
71/*
72egjs-imready
73Copyright (c) 2020-present NAVER Corp.
74MIT license
75*/
76var isWindow = typeof window !== "undefined";
77var ua = isWindow ? window.navigator.userAgent : "";
78var SUPPORT_COMPUTEDSTYLE = isWindow ? !!("getComputedStyle" in window) : false;
79var IS_IE = /MSIE|Trident|Windows Phone|Edge/.test(ua);
80var SUPPORT_ADDEVENTLISTENER = isWindow ? !!("addEventListener" in document) : false;
81var WIDTH = "width";
82var HEIGHT = "height";
83
84function getAttribute(el, name) {
85 return el.getAttribute(name) || "";
86}
87function toArray(arr) {
88 return [].slice.call(arr);
89}
90function hasSizeAttribute(target, prefix) {
91 if (prefix === void 0) {
92 prefix = "data-";
93 }
94
95 return !!target.getAttribute(prefix + "width");
96}
97function hasLoadingAttribute(target) {
98 return "loading" in target && target.getAttribute("loading") === "lazy";
99}
100function hasSkipAttribute(target, prefix) {
101 if (prefix === void 0) {
102 prefix = "data-";
103 }
104
105 return !!target.getAttribute(prefix + "skip");
106}
107function addEvent(element, type, handler) {
108 if (SUPPORT_ADDEVENTLISTENER) {
109 element.addEventListener(type, handler, false);
110 } else if (element.attachEvent) {
111 element.attachEvent("on" + type, handler);
112 } else {
113 element["on" + type] = handler;
114 }
115}
116function removeEvent(element, type, handler) {
117 if (element.removeEventListener) {
118 element.removeEventListener(type, handler, false);
119 } else if (element.detachEvent) {
120 element.detachEvent("on" + type, handler);
121 } else {
122 element["on" + type] = null;
123 }
124}
125function innerWidth(el) {
126 return getSize(el, "Width");
127}
128function innerHeight(el) {
129 return getSize(el, "Height");
130}
131function getStyles(el) {
132 return (SUPPORT_COMPUTEDSTYLE ? window.getComputedStyle(el) : el.currentStyle) || {};
133}
134
135function getSize(el, name) {
136 var size = el["client" + name] || el["offset" + name];
137 return parseFloat(size || getStyles(el)[name.toLowerCase()]) || 0;
138}
139
140function getContentElements(element, tags, prefix) {
141 var skipElements = toArray(element.querySelectorAll(__spreadArrays(["[" + prefix + "skip] [" + prefix + "width]"], tags.map(function (tag) {
142 return ["[" + prefix + "skip] " + tag, tag + "[" + prefix + "skip]", "[" + prefix + "width] " + tag].join(", ");
143 })).join(", ")));
144 return toArray(element.querySelectorAll("[" + prefix + "width], " + tags.join(", "))).filter(function (el) {
145 return skipElements.indexOf(el) === -1;
146 });
147}
148
149/*
150egjs-imready
151Copyright (c) 2020-present NAVER Corp.
152MIT license
153*/
154var elements = [];
155function addAutoSizer(element, prefix) {
156 !elements.length && addEvent(window, "resize", resizeAllAutoSizers);
157 element.__PREFIX__ = prefix;
158 elements.push(element);
159 resize(element);
160}
161function removeAutoSizer(element, prefix) {
162 var index = elements.indexOf(element);
163
164 if (index < 0) {
165 return;
166 }
167
168 var fixed = getAttribute(element, prefix + "fixed");
169 delete element.__PREFIX__;
170 element.style[fixed === HEIGHT ? WIDTH : HEIGHT] = "";
171 elements.splice(index, 1);
172 !elements.length && removeEvent(window, "resize", resizeAllAutoSizers);
173}
174
175function resize(element, prefix) {
176 if (prefix === void 0) {
177 prefix = "data-";
178 }
179
180 var elementPrefix = element.__PREFIX__ || prefix;
181 var dataWidth = parseInt(getAttribute(element, "" + elementPrefix + WIDTH), 10) || 0;
182 var dataHeight = parseInt(getAttribute(element, "" + elementPrefix + HEIGHT), 10) || 0;
183 var fixed = getAttribute(element, elementPrefix + "fixed");
184
185 if (fixed === HEIGHT) {
186 var size = innerHeight(element) || dataHeight;
187 element.style[WIDTH] = dataWidth / dataHeight * size + "px";
188 } else {
189 var size = innerWidth(element) || dataWidth;
190 element.style[HEIGHT] = dataHeight / dataWidth * size + "px";
191 }
192}
193
194function resizeAllAutoSizers() {
195 elements.forEach(function (element) {
196 resize(element);
197 });
198}
199
200var Loader =
201/*#__PURE__*/
202function (_super) {
203 __extends(Loader, _super);
204
205 function Loader(element, options) {
206 if (options === void 0) {
207 options = {};
208 }
209
210 var _this = _super.call(this) || this;
211
212 _this.isReady = false;
213 _this.isPreReady = false;
214 _this.hasDataSize = false;
215 _this.hasLoading = false;
216 _this.isSkip = false;
217
218 _this.onCheck = function (e) {
219 _this.clear();
220
221 if (e && e.type === "error") {
222 _this.onError(_this.element);
223 } // I'm pre-ready and ready!
224
225
226 var withPreReady = !_this.hasDataSize && !_this.hasLoading;
227
228 _this.onReady(withPreReady);
229 };
230
231 _this.options = __assign({
232 prefix: "data-"
233 }, options);
234 _this.element = element;
235 var prefix = _this.options.prefix;
236 _this.hasDataSize = hasSizeAttribute(element, prefix);
237 _this.isSkip = hasSkipAttribute(element, prefix);
238 _this.hasLoading = hasLoadingAttribute(element);
239 return _this;
240 }
241
242 var __proto = Loader.prototype;
243
244 __proto.check = function () {
245 if (this.isSkip || !this.checkElement()) {
246 // I'm Ready
247 this.onAlreadyReady(true);
248 return false;
249 }
250
251 if (this.hasDataSize) {
252 addAutoSizer(this.element, this.options.prefix);
253 }
254
255 if (this.hasDataSize || this.hasLoading) {
256 // I'm Pre Ready
257 this.onAlreadyPreReady();
258 } // Wati Pre Ready, Ready
259
260
261 return true;
262 };
263
264 __proto.addEvents = function () {
265 var _this = this;
266
267 var element = this.element;
268 this.constructor.EVENTS.forEach(function (name) {
269 addEvent(element, name, _this.onCheck);
270 });
271 };
272
273 __proto.clear = function () {
274 var _this = this;
275
276 var element = this.element;
277 this.constructor.EVENTS.forEach(function (name) {
278 removeEvent(element, name, _this.onCheck);
279 });
280 this.removeAutoSizer();
281 };
282
283 __proto.destroy = function () {
284 this.clear();
285 this.off();
286 };
287
288 __proto.removeAutoSizer = function () {
289 if (this.hasDataSize) {
290 // I'm already ready.
291 var prefix = this.options.prefix;
292 removeAutoSizer(this.element, prefix);
293 }
294 };
295
296 __proto.onError = function (target) {
297 this.trigger("error", {
298 element: this.element,
299 target: target
300 });
301 };
302
303 __proto.onPreReady = function () {
304 if (this.isPreReady) {
305 return;
306 }
307
308 this.isPreReady = true;
309 this.trigger("preReady", {
310 element: this.element,
311 hasLoading: this.hasLoading,
312 isSkip: this.isSkip
313 });
314 };
315
316 __proto.onReady = function (withPreReady) {
317 if (this.isReady) {
318 return;
319 }
320
321 withPreReady = !this.isPreReady && withPreReady;
322
323 if (withPreReady) {
324 this.isPreReady = true;
325 }
326
327 this.removeAutoSizer();
328 this.isReady = true;
329 this.trigger("ready", {
330 element: this.element,
331 withPreReady: withPreReady,
332 hasLoading: this.hasLoading,
333 isSkip: this.isSkip
334 });
335 };
336
337 __proto.onAlreadyError = function (target) {
338 var _this = this;
339
340 setTimeout(function () {
341 _this.onError(target);
342 });
343 };
344
345 __proto.onAlreadyPreReady = function () {
346 var _this = this;
347
348 setTimeout(function () {
349 _this.onPreReady();
350 });
351 };
352
353 __proto.onAlreadyReady = function (withPreReady) {
354 var _this = this;
355
356 setTimeout(function () {
357 _this.onReady(withPreReady);
358 });
359 };
360
361 Loader.EVENTS = [];
362 return Loader;
363}(Component);
364
365var ElementLoader =
366/*#__PURE__*/
367function (_super) {
368 __extends(ElementLoader, _super);
369
370 function ElementLoader() {
371 return _super !== null && _super.apply(this, arguments) || this;
372 }
373
374 var __proto = ElementLoader.prototype;
375
376 __proto.setHasLoading = function (hasLoading) {
377 this.hasLoading = hasLoading;
378 };
379
380 __proto.check = function () {
381 if (this.isSkip) {
382 // I'm Ready
383 this.onAlreadyReady(true);
384 return false;
385 }
386
387 if (this.hasDataSize) {
388 addAutoSizer(this.element, this.options.prefix);
389 this.onAlreadyPreReady();
390 } else {
391 // has not data size
392 this.trigger("requestChildren");
393 }
394
395 return true;
396 };
397
398 __proto.checkElement = function () {
399 return true;
400 };
401
402 __proto.destroy = function () {
403 this.clear();
404 this.trigger("requestDestroy");
405 this.off();
406 };
407
408 __proto.onAlreadyPreReady = function () {
409 // has data size
410 _super.prototype.onAlreadyPreReady.call(this);
411
412 this.trigger("reqeustReadyChildren");
413 };
414
415 ElementLoader.EVENTS = [];
416 return ElementLoader;
417}(Loader);
418
419/**
420 * @alias eg.ImReady
421 * @extends eg.Component
422 */
423
424var ImReadyManager =
425/*#__PURE__*/
426function (_super) {
427 __extends(ImReadyManager, _super);
428 /**
429 * @param - ImReady's options
430 */
431
432
433 function ImReadyManager(options) {
434 if (options === void 0) {
435 options = {};
436 }
437
438 var _this = _super.call(this) || this;
439
440 _this.readyCount = 0;
441 _this.preReadyCount = 0;
442 _this.totalCount = 0;
443 _this.totalErrorCount = 0;
444 _this.isPreReadyOver = true;
445 _this.elementInfos = [];
446 _this.options = __assign({
447 loaders: {},
448 prefix: "data-"
449 }, options);
450 return _this;
451 }
452 /**
453 * Checks whether elements are in the ready state.
454 * @ko 엘리먼트가 준비 상태인지 체크한다.
455 * @elements - Elements to check ready status. <ko> 준비 상태를 체크할 엘리먼트들.</ko>
456 * @example
457 * ```html
458 * <div>
459 * <img src="./1.jpg" data-width="1280" data-height="853" style="width:100%"/>
460 * <img src="./2.jpg" data-width="1280" data-height="853"/>
461 * <img src="ERR" data-width="1280" data-height="853"/>
462 * </div>
463 * ```
464 * ## Javascript
465 * ```js
466 * import ImReady from "@egjs/imready";
467 *
468 * const im = new ImReady(); // umd: eg.ImReady
469 * im.check(document.querySelectorAll("img")).on({
470 * preReadyElement: e => {
471 * // 1, 3
472 * // 2, 3
473 * // 3, 3
474 * console.log(e.preReadyCount, e.totalCount),
475 * },
476 * });
477 * ```
478 */
479
480
481 var __proto = ImReadyManager.prototype;
482
483 __proto.check = function (elements) {
484 var _this = this;
485
486 var prefix = this.options.prefix;
487 this.clear();
488 this.elementInfos = toArray(elements).map(function (element, index) {
489 var loader = _this.getLoader(element, {
490 prefix: prefix
491 });
492
493 loader.check();
494 loader.on("error", function (e) {
495 _this.onError(index, e.target);
496 }).on("preReady", function (e) {
497 var info = _this.elementInfos[index];
498 info.hasLoading = e.hasLoading;
499 info.isSkip = e.isSkip;
500
501 var isPreReady = _this.checkPreReady(index);
502
503 _this.onPreReadyElement(index);
504
505 isPreReady && _this.onPreReady();
506 }).on("ready", function (_a) {
507 var withPreReady = _a.withPreReady,
508 hasLoading = _a.hasLoading,
509 isSkip = _a.isSkip;
510 var info = _this.elementInfos[index];
511 info.hasLoading = hasLoading;
512 info.isSkip = isSkip;
513
514 var isPreReady = withPreReady && _this.checkPreReady(index);
515
516 var isReady = _this.checkReady(index); // Pre-ready and ready occur simultaneously
517
518
519 withPreReady && _this.onPreReadyElement(index);
520
521 _this.onReadyElement(index);
522
523 isPreReady && _this.onPreReady();
524 isReady && _this.onReady();
525 });
526 return {
527 loader: loader,
528 element: element,
529 hasLoading: false,
530 hasError: false,
531 isPreReady: false,
532 isReady: false,
533 isSkip: false
534 };
535 });
536 var length = this.elementInfos.length;
537 this.totalCount = length;
538
539 if (!length) {
540 setTimeout(function () {
541 _this.onPreReady();
542
543 _this.onReady();
544 });
545 }
546
547 return this;
548 };
549 /**
550 * Gets the total count of elements to be checked.
551 * @ko 체크하는 element의 총 개수를 가져온다.
552 */
553
554
555 __proto.getTotalCount = function () {
556 return this.totalCount;
557 };
558 /**
559 * Whether the elements are all pre-ready. (all sizes are known)
560 * @ko 엘리먼트들이 모두 사전 준비가 됐는지 (사이즈를 전부 알 수 있는지) 여부.
561 */
562
563
564 __proto.isPreReady = function () {
565 return this.elementInfos.every(function (info) {
566 return info.isPreReady;
567 });
568 };
569 /**
570 * Whether the elements are all ready.
571 * @ko 엘리먼트들이 모두 준비가 됐는지 여부.
572 */
573
574
575 __proto.isReady = function () {
576 return this.elementInfos.every(function (info) {
577 return info.isReady;
578 });
579 };
580 /**
581 * Whether an error has occurred in the elements in the current state.
582 * @ko 현재 상태에서 엘리먼트들이 에러가 발생했는지 여부.
583 */
584
585
586 __proto.hasError = function () {
587 return this.totalErrorCount > 0;
588 };
589 /**
590 * Clears events of elements being checked.
591 * @ko 체크 중인 엘리먼트들의 이벤트를 해제 한다.
592 */
593
594
595 __proto.clear = function () {
596 this.isPreReadyOver = false;
597 this.totalCount = 0;
598 this.preReadyCount = 0;
599 this.readyCount = 0;
600 this.totalErrorCount = 0;
601 this.elementInfos.forEach(function (info) {
602 if (!info.isReady && info.loader) {
603 info.loader.destroy();
604 }
605 });
606 this.elementInfos = [];
607 };
608 /**
609 * Destory all events.
610 * @ko 모든 이벤트를 해제 한다.
611 */
612
613
614 __proto.destroy = function () {
615 this.clear();
616 this.off();
617 };
618
619 __proto.getLoader = function (element, options) {
620 var _this = this;
621
622 var tagName = element.tagName.toLowerCase();
623 var loaders = this.options.loaders;
624 var tags = Object.keys(loaders);
625
626 if (loaders[tagName]) {
627 return new loaders[tagName](element, options);
628 }
629
630 var loader = new ElementLoader(element, options);
631 var children = toArray(element.querySelectorAll(tags.join(", ")));
632 loader.setHasLoading(children.some(function (el) {
633 return hasLoadingAttribute(el);
634 }));
635 var withPreReady = false;
636 var childrenImReady = this.clone().on("error", function (e) {
637 loader.onError(e.target);
638 }).on("ready", function () {
639 loader.onReady(withPreReady);
640 });
641 loader.on("requestChildren", function () {
642 // has not data size
643 var contentElements = getContentElements(element, tags, _this.options.prefix);
644 childrenImReady.check(contentElements).on("preReady", function (e) {
645 withPreReady = e.isReady;
646
647 if (!withPreReady) {
648 loader.onPreReady();
649 }
650 });
651 }).on("reqeustReadyChildren", function () {
652 // has data size
653 // loader call preReady
654 // check only video, image elements
655 childrenImReady.check(children);
656 }).on("requestDestroy", function () {
657 childrenImReady.destroy();
658 });
659 return loader;
660 };
661
662 __proto.clone = function () {
663 return new ImReadyManager(__assign({}, this.options));
664 };
665
666 __proto.checkPreReady = function (index) {
667 this.elementInfos[index].isPreReady = true;
668 ++this.preReadyCount;
669
670 if (this.preReadyCount < this.totalCount) {
671 return false;
672 }
673
674 return true;
675 };
676
677 __proto.checkReady = function (index) {
678 this.elementInfos[index].isReady = true;
679 ++this.readyCount;
680
681 if (this.readyCount < this.totalCount) {
682 return false;
683 }
684
685 return true;
686 };
687
688 __proto.onError = function (index, target) {
689 var info = this.elementInfos[index];
690 info.hasError = true;
691 /**
692 * An event occurs if the image, video fails to load.
693 * @ko 이미지, 비디오가 로딩에 실패하면 이벤트가 발생한다.
694 * @event eg.ImReady#error
695 * @param {eg.ImReady.OnError} e - The object of data to be sent to an event <ko>이벤트에 전달되는 데이터 객체</ko>
696 * @param {HTMLElement} [e.element] - The element with error images.<ko>오류난 이미지가 있는 엘리먼트</ko>
697 * @param {number} [e.index] - The item's index with error images. <ko>오류난 이미지가 있는 엘리먼트의 인덱스</ko>
698 * @param {HTMLElement} [e.target] - Error image target in element <ko>엘리먼트의 오류난 이미지 타겟</ko>
699 * @param {number} [e.errorCount] - The number of elements with errors <ko>에러가 있는 엘리먼트들의 개수</ko>
700 * @param {number} [e.totalErrorCount] - The total number of targets with errors <ko>에러가 있는 타겟들의 총 개수</ko>
701 * @example
702 * ```html
703 * <div>
704 * <img src="./1.jpg" data-width="1280" data-height="853" style="width:100%"/>
705 * <img src="./2.jpg"/>
706 * <img src="ERR"/>
707 * </div>
708 * ```
709 * ## Javascript
710 * ```js
711 * import ImReady from "@egjs/imready";
712 *
713 * const im = new ImReady(); // umd: eg.ImReady
714 * im.check([document.querySelector("div")]).on({
715 * error: e => {
716 * // <div>...</div>, 0, <img src="ERR"/>
717 * console.log(e.element, e.index, e.target),
718 * },
719 * });
720 * ```
721 */
722
723 this.trigger("error", {
724 element: info.element,
725 index: index,
726 target: target,
727 errorCount: this.getErrorCount(),
728 totalErrorCount: ++this.totalErrorCount
729 });
730 };
731
732 __proto.onPreReadyElement = function (index) {
733 var info = this.elementInfos[index];
734 /**
735 * An event occurs when the element is pre-ready (when the loading attribute is applied or the size is known)
736 * @ko 해당 엘리먼트가 사전 준비되었을 때(loading 속성이 적용되었거나 사이즈를 알 수 있을 때) 이벤트가 발생한다.
737 * @event eg.ImReady#preReadyElement
738 * @param {eg.ImReady.OnPreReadyElement} e - The object of data to be sent to an event <ko>이벤트에 전달되는 데이터 객체</ko>
739 * @param {HTMLElement} [e.element] - The pre-ready element.<ko>사전 준비된 엘리먼트</ko>
740 * @param {number} [e.index] - The index of the pre-ready element. <ko>사전 준비된 엘리먼트의 인덱스</ko>
741 * @param {number} [e.preReadyCount] - Number of elements pre-ready <ko>사전 준비된 엘리먼트들의 개수</ko>
742 * @param {number} [e.readyCount] - Number of elements ready <ko>준비된 엘리먼트들의 개수</ko>
743 * @param {number} [e.totalCount] - Total number of elements <ko>엘리먼트들의 총 개수</ko>
744 * @param {boolean} [e.isPreReady] - Whether all elements are pre-ready <ko>모든 엘리먼트가 사전 준비가 끝났는지 여부</ko>
745 * @param {boolean} [e.isReady] - Whether all elements are ready <ko>모든 엘리먼트가 준비가 끝났는지 여부</ko>
746 * @param {boolean} [e.hasLoading] - Whether the loading attribute has been applied <ko>loading 속성이 적용되었는지 여부</ko>
747 * @param {boolean} [e.isSkip] - Whether the check is omitted due to skip attribute <ko>skip 속성으로 인하여 체크가 생략됐는지 여부</ko>
748 * @example
749 * ```html
750 * <div>
751 * <img src="./1.jpg" data-width="1280" data-height="853" style="width:100%"/>
752 * <img src="./2.jpg" data-width="1280" data-height="853"/>
753 * <img src="ERR" data-width="1280" data-height="853"/>
754 * </div>
755 * ```
756 * ## Javascript
757 * ```js
758 * import ImReady from "@egjs/imready";
759 *
760 * const im = new ImReady(); // umd: eg.ImReady
761 * im.check(document.querySelectorAll("img")).on({
762 * preReadyElement: e => {
763 * // 1, 3
764 * // 2, 3
765 * // 3, 3
766 * console.log(e.preReadyCount, e.totalCount),
767 * },
768 * });
769 * ```
770 */
771
772 this.trigger("preReadyElement", {
773 element: info.element,
774 index: index,
775 preReadyCount: this.preReadyCount,
776 readyCount: this.readyCount,
777 totalCount: this.totalCount,
778 isPreReady: this.isPreReady(),
779 isReady: this.isReady(),
780 hasLoading: info.hasLoading,
781 isSkip: info.isSkip
782 });
783 };
784
785 __proto.onPreReady = function () {
786 this.isPreReadyOver = true;
787 /**
788 * An event occurs when all element are pre-ready (When all elements have the loading attribute applied or the size is known)
789 * @ko 모든 엘리먼트들이 사전 준비된 경우 (모든 엘리먼트들이 loading 속성이 적용되었거나 사이즈를 알 수 있는 경우) 이벤트가 발생한다.
790 * @event eg.ImReady#preReady
791 * @param {eg.ImReady.OnPreReady} e - The object of data to be sent to an event <ko>이벤트에 전달되는 데이터 객체</ko>
792 * @param {number} [e.readyCount] - Number of elements ready <ko>준비된 엘리먼트들의 개수</ko>
793 * @param {number} [e.totalCount] - Total number of elements <ko>엘리먼트들의 총 개수</ko>
794 * @param {boolean} [e.isReady] - Whether all elements are ready <ko>모든 엘리먼트가 준비가 끝났는지 여부</ko>
795 * @param {boolean} [e.hasLoading] - Whether the loading attribute has been applied <ko>loading 속성이 적용되었는지 여부</ko>
796 * @example
797 * ```html
798 * <div>
799 * <img src="./1.jpg" data-width="1280" data-height="853" style="width:100%"/>
800 * <img src="./2.jpg" data-width="1280" data-height="853"/>
801 * <img src="ERR" data-width="1280" data-height="853"/>
802 * </div>
803 * ```
804 * ## Javascript
805 * ```js
806 * import ImReady from "@egjs/imready";
807 *
808 * const im = new ImReady(); // umd: eg.ImReady
809 * im.check(document.querySelectorAll("img")).on({
810 * preReady: e => {
811 * // 0, 3
812 * console.log(e.readyCount, e.totalCount),
813 * },
814 * });
815 * ```
816 */
817
818 this.trigger("preReady", {
819 readyCount: this.readyCount,
820 totalCount: this.totalCount,
821 isReady: this.isReady(),
822 hasLoading: this.hasLoading()
823 });
824 };
825
826 __proto.onReadyElement = function (index) {
827 var info = this.elementInfos[index];
828 /**
829 * An event occurs when the element is ready
830 * @ko 해당 엘리먼트가 준비가 되었을 때 이벤트가 발생한다.
831 * @event eg.ImReady#readyElement
832 * @param {eg.ImReady.OnReadyElement} e - The object of data to be sent to an event <ko>이벤트에 전달되는 데이터 객체</ko>
833 * @param {HTMLElement} [e.element] - The ready element.<ko>준비된 엘리먼트</ko>
834 * @param {number} [e.index] - The index of the ready element. <ko>준비된 엘리먼트의 인덱스</ko>
835 * @param {boolean} [e.hasError] - Whether there is an error in the element <ko>해당 엘리먼트에 에러가 있는지 여부</ko>
836 * @param {number} [e.errorCount] - The number of elements with errors <ko>에러가 있는 엘리먼트들의 개수</ko>
837 * @param {number} [e.totalErrorCount] - The total number of targets with errors <ko>에러가 있는 타겟들의 총 개수</ko>
838 * @param {number} [e.preReadyCount] - Number of elements pre-ready <ko>사전 준비된 엘리먼트들의 개수</ko>
839 * @param {number} [e.readyCount] - Number of elements ready <ko>준비된 엘리먼트들의 개수</ko>
840 * @param {number} [e.totalCount] - Total number of elements <ko>엘리먼트들의 총 개수</ko>
841 * @param {boolean} [e.isPreReady] - Whether all elements are pre-ready <ko>모든 엘리먼트가 사전 준비가 끝났는지 여부</ko>
842 * @param {boolean} [e.isReady] - Whether all elements are ready <ko>모든 엘리먼트가 준비가 끝났는지 여부</ko>
843 * @param {boolean} [e.hasLoading] - Whether the loading attribute has been applied <ko>loading 속성이 적용되었는지 여부</ko>
844 * @param {boolean} [e.isPreReadyOver] - Whether pre-ready is over <ko>사전 준비가 끝났는지 여부</ko>
845 * @param {boolean} [e.isSkip] - Whether the check is omitted due to skip attribute <ko>skip 속성으로 인하여 체크가 생략됐는지 여부</ko>
846 * @example
847 * ```html
848 * <div>
849 * <img src="./1.jpg" data-width="1280" data-height="853" style="width:100%"/>
850 * <img src="./2.jpg" data-width="1280" data-height="853"/>
851 * <img src="ERR" data-width="1280" data-height="853"/>
852 * </div>
853 * ```
854 * ## Javascript
855 * ```js
856 * import ImReady from "@egjs/imready";
857 *
858 * const im = new ImReady(); // umd: eg.ImReady
859 * im.check(document.querySelectorAll("img")).on({
860 * readyElement: e => {
861 * // 1, 0, false, 3
862 * // 2, 1, false, 3
863 * // 3, 2, true, 3
864 * console.log(e.readyCount, e.index, e.hasError, e.totalCount),
865 * },
866 * });
867 * ```
868 */
869
870 this.trigger("readyElement", {
871 index: index,
872 element: info.element,
873 hasError: info.hasError,
874 errorCount: this.getErrorCount(),
875 totalErrorCount: this.totalErrorCount,
876 preReadyCount: this.preReadyCount,
877 readyCount: this.readyCount,
878 totalCount: this.totalCount,
879 isPreReady: this.isPreReady(),
880 isReady: this.isReady(),
881 hasLoading: info.hasLoading,
882 isPreReadyOver: this.isPreReadyOver,
883 isSkip: info.isSkip
884 });
885 };
886
887 __proto.onReady = function () {
888 /**
889 * An event occurs when all element are ready
890 * @ko 모든 엘리먼트들이 준비된 경우 이벤트가 발생한다.
891 * @event eg.ImReady#ready
892 * @param {eg.ImReady.OnReady} e - The object of data to be sent to an event <ko>이벤트에 전달되는 데이터 객체</ko>
893 * @param {number} [e.errorCount] - The number of elements with errors <ko>에러가 있는 엘리먼트들의 개수</ko>
894 * @param {number} [e.totalErrorCount] - The total number of targets with errors <ko>에러가 있는 타겟들의 총 개수</ko>
895 * @param {number} [e.totalCount] - Total number of elements <ko>엘리먼트들의 총 개수</ko>
896 * @example
897 * ```html
898 * <div>
899 * <img src="./1.jpg" data-width="1280" data-height="853" style="width:100%"/>
900 * <img src="./2.jpg" data-width="1280" data-height="853"/>
901 * <img src="ERR" data-width="1280" data-height="853"/>
902 * </div>
903 * ```
904 * ## Javascript
905 * ```js
906 * import ImReady from "@egjs/imready";
907 *
908 * const im = new ImReady(); // umd: eg.ImReady
909 * im.check(document.querySelectorAll("img")).on({
910 * preReady: e => {
911 * // 0, 3
912 * console.log(e.readyCount, e.totalCount),
913 * },
914 * ready: e => {
915 * // 1, 3
916 * console.log(e.errorCount, e.totalCount),
917 * },
918 * });
919 * ```
920 */
921 this.trigger("ready", {
922 errorCount: this.getErrorCount(),
923 totalErrorCount: this.totalErrorCount,
924 totalCount: this.totalCount
925 });
926 };
927
928 __proto.getErrorCount = function () {
929 return this.elementInfos.filter(function (info) {
930 return info.hasError;
931 }).length;
932 };
933
934 __proto.hasLoading = function () {
935 return this.elementInfos.some(function (info) {
936 return info.hasLoading;
937 });
938 };
939
940 return ImReadyManager;
941}(Component);
942
943var ImageLoader =
944/*#__PURE__*/
945function (_super) {
946 __extends(ImageLoader, _super);
947
948 function ImageLoader() {
949 return _super !== null && _super.apply(this, arguments) || this;
950 }
951
952 var __proto = ImageLoader.prototype;
953
954 __proto.checkElement = function () {
955 var element = this.element;
956 var src = element.getAttribute("src");
957
958 if (element.complete) {
959 if (src) {
960 // complete
961 if (!element.naturalWidth) {
962 this.onAlreadyError(element);
963 }
964
965 return false;
966 } else {
967 // Using an external lazy loading module
968 this.onAlreadyPreReady();
969 }
970 }
971
972 this.addEvents();
973 IS_IE && element.setAttribute("src", src);
974 return true;
975 };
976
977 ImageLoader.EVENTS = ["load", "error"];
978 return ImageLoader;
979}(Loader);
980
981var VideoLoader =
982/*#__PURE__*/
983function (_super) {
984 __extends(VideoLoader, _super);
985
986 function VideoLoader() {
987 return _super !== null && _super.apply(this, arguments) || this;
988 }
989
990 var __proto = VideoLoader.prototype;
991
992 __proto.checkElement = function () {
993 var element = this.element; // HAVE_NOTHING: 0, no information whether or not the audio/video is ready
994 // HAVE_METADATA: 1, HAVE_METADATA - metadata for the audio/video is ready
995 // HAVE_CURRENT_DATA: 2, data for the current playback position is available, but not enough data to play next frame/millisecond
996 // HAVE_FUTURE_DATA: 3, data for the current and at least the next frame is available
997 // HAVE_ENOUGH_DATA: 4, enough data available to start playing
998
999 if (element.readyState >= 1) {
1000 return false;
1001 }
1002
1003 if (element.error) {
1004 this.onAlreadyError(element);
1005 return false;
1006 }
1007
1008 this.addEvents();
1009 return true;
1010 };
1011
1012 VideoLoader.EVENTS = ["loadedmetadata", "error"];
1013 return VideoLoader;
1014}(Loader);
1015
1016var ImReady =
1017/*#__PURE__*/
1018function (_super) {
1019 __extends(ImReady, _super);
1020
1021 function ImReady(options) {
1022 if (options === void 0) {
1023 options = {};
1024 }
1025
1026 return _super.call(this, __assign({
1027 loaders: {
1028 img: ImageLoader,
1029 video: VideoLoader
1030 }
1031 }, options)) || this;
1032 }
1033
1034 return ImReady;
1035}(ImReadyManager);
1036
1037/*
1038egjs-imready
1039Copyright (c) 2020-present NAVER Corp.
1040MIT license
1041*/
1042
1043var modules = {
1044 __proto__: null,
1045 'default': ImReady,
1046 Manager: ImReadyManager,
1047 VideoLoader: VideoLoader,
1048 ImageLoader: ImageLoader,
1049 Loader: Loader
1050};
1051
1052/*
1053egjs-imready
1054Copyright (c) 2020-present NAVER Corp.
1055MIT license
1056*/
1057
1058for (var name in modules) {
1059 ImReady[name] = modules[name];
1060}
1061
1062module.exports = ImReady;
1063//# sourceMappingURL=imready.cjs.js.map