UNPKG

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