PageSourceSearch

https://www.volvo.com/etc.clientlibs/core/wcm/components/image/v2/…e.lc-d31d55e65397b599da9a48a99dd8f4af-lc.js

js volvo.com collected 2026-10-02 03:13:02 UTC 30,667 bytes, 787 lines download raw bytes

1/*******************************************************************************
2 * Copyright 2017 Adobe
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 ******************************************************************************/
16if (window.Element && !Element.prototype.closest) {
17    // eslint valid-jsdoc: "off"
18    Element.prototype.closest =
19        function(s) {
20            "use strict";
21            var matches = (this.document || this.ownerDocument).querySelectorAll(s);
22            var el      = this;
23            var i;
24            do {
25                i = matches.length;
26                while (--i >= 0 && matches.item(i) !== el) {
27                    // continue
28                }
29            } while ((i < 0) && (el = el.parentElement));
30            return el;
31        };
32}
33
34if (window.Element && !Element.prototype.matches) {
35    Element.prototype.matches =
36        Element.prototype.matchesSelector ||
37        Element.prototype.mozMatchesSelector ||
38        Element.prototype.msMatchesSelector ||
39        Element.prototype.oMatchesSelector ||
40        Element.prototype.webkitMatchesSelector ||
41        function(s) {
42            "use strict";
43            var matches = (this.document || this.ownerDocument).querySelectorAll(s);
44            var i       = matches.length;
45            while (--i >= 0 && matches.item(i) !== this) {
46                // continue
47            }
48            return i > -1;
49        };
50}
51
52if (!Object.assign) {
53    Object.assign = function(target, varArgs) { // .length of function is 2
54        "use strict";
55        if (target === null) {
56            throw new TypeError("Cannot convert undefined or null to object");
57        }
58
59        var to = Object(target);
60
61        for (var index = 1; index < arguments.length; index++) {
62            var nextSource = arguments[index];
63
64            if (nextSource !== null) {
65                for (var nextKey in nextSource) {
66                    if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
67                        to[nextKey] = nextSource[nextKey];
68                    }
69                }
70            }
71        }
72        return to;
73    };
74}
75
76(function(arr) {
77    "use strict";
78    arr.forEach(function(item) {
79        if (Object.prototype.hasOwnProperty.call(item, "remove")) {
80            return;
81        }
82        Object.defineProperty(item, "remove", {
83            configurable: true,
84            enumerable: true,
85            writable: true,
86            value: function remove() {
87                this.parentNode.removeChild(this);
88            }
89        });
90    });
91})([Element.prototype, CharacterData.prototype, DocumentType.prototype]);
92
93/*******************************************************************************
94 * Copyright 2022 Adobe
95 *
96 * Licensed under the Apache License, Version 2.0 (the "License");
97 * you may not use this file except in compliance with the License.
98 * You may obtain a copy of the License at
99 *
100 *     http://www.apache.org/licenses/LICENSE-2.0
101 *
102 * Unless required by applicable law or agreed to in writing, software
103 * distributed under the License is distributed on an "AS IS" BASIS,
104 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
105 * See the License for the specific language governing permissions and
106 * limitations under the License.
107 ******************************************************************************/
108(function(document) {
109    "use strict";
110
111    window.CMP = window.CMP || {};
112    window.CMP.utils = (function() {
113        var NS = "cmp";
114
115        /**
116         * Reads options data from the Component wrapper element, defined via {@code data-cmp-*} data attributes
117         *
118         * @param {HTMLElement} element The component element to read options data from
119         * @param {String} is The component identifier
120         * @returns {String[]} The options read from the component data attributes
121         */
122        var readData = function(element, is) {
123            var data = element.dataset;
124            var options = [];
125            var capitalized = is;
126            capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
127            var reserved = ["is", "hook" + capitalized];
128
129            for (var key in data) {
130                if (Object.prototype.hasOwnProperty.call(data, key)) {
131                    var value = data[key];
132
133                    if (key.indexOf(NS) === 0) {
134                        key = key.slice(NS.length);
135                        key = key.charAt(0).toLowerCase() + key.substring(1);
136
137                        if (reserved.indexOf(key) === -1) {
138                            options[key] = value;
139                        }
140                    }
141                }
142            }
143            return options;
144        };
145
146        /**
147         * Set up the final properties of a component by evaluating the transform function or fall back to the default value on demand
148         * @param {String[]} options the options to transform
149         * @param {Object} properties object of properties of property functions
150         * @returns {Object} transformed properties
151         */
152        var setupProperties = function(options, properties) {
153            var transformedProperties = {};
154
155            for (var key in properties) {
156                if (Object.prototype.hasOwnProperty.call(properties, key)) {
157                    var property = properties[key];
158                    if (options && options[key] != null) {
159                        if (property && typeof property.transform === "function") {
160                            transformedProperties[key] = property.transform(options[key]);
161                        } else {
162                            transformedProperties[key] = options[key];
163                        }
164                    } else {
165                        transformedProperties[key] = properties[key]["default"];
166                    }
167                }
168            }
169            return transformedProperties;
170        };
171
172
173        return {
174            readData: readData,
175            setupProperties: setupProperties
176        };
177    }());
178}(window.document));
179
180/*******************************************************************************
181 * Copyright 2022 Adobe
182 *
183 * Licensed under the Apache License, Version 2.0 (the "License");
184 * you may not use this file except in compliance with the License.
185 * You may obtain a copy of the License at
186 *
187 *     http://www.apache.org/licenses/LICENSE-2.0
188 *
189 * Unless required by applicable law or agreed to in writing, software
190 * distributed under the License is distributed on an "AS IS" BASIS,
191 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
192 * See the License for the specific language governing permissions and
193 * limitations under the License.
194 ******************************************************************************/
195(function(document) {
196    "use strict";
197
198    window.CMP = window.CMP || {};
199    window.CMP.image = window.CMP.image || {};
200    window.CMP.image.dynamicMedia = (function() {
201        var autoSmartCrops = {};
202        var SRC_URI_TEMPLATE_WIDTH_VAR = "{.width}";
203        var SRC_URI_TEMPLATE_DPR_VAR = "{dpr}";
204        var SRC_URI_DPR_OFF = "dpr=off";
205        var SRC_URI_DPR_ON = "dpr=on,{dpr}";
206        var dpr = window.devicePixelRatio || 1;
207        var config = {
208            minWidth: 20
209        };
210
211        /**
212         * get auto smart crops from dm
213         * @param {String} src the src uri
214         * @returns {{}} the smart crop json object
215         */
216        var getAutoSmartCrops = function(src) {
217            var request = new XMLHttpRequest();
218            var url = src.split(SRC_URI_TEMPLATE_WIDTH_VAR)[0] + "?req=set,json";
219            request.open("GET", url, false);
220            request.onload = function() {
221                if (request.status >= 200 && request.status < 400) {
222                    // success status
223                    var responseText = request.responseText;
224                    var rePayload = new RegExp(/^(?:\/\*jsonp\*\/)?\s*([^()]+)\(([\s\S]+),\s*"[0-9]*"\);?$/gmi);
225                    var rePayloadJSON = new RegExp(/^{[\s\S]*}$/gmi);
226                    var resPayload = rePayload.exec(responseText);
227                    var payload;
228                    if (resPayload) {
229                        var payloadStr = resPayload[2];
230                        if (rePayloadJSON.test(payloadStr)) {
231                            payload = JSON.parse(payloadStr);
232                        }
233
234                    }
235                    // check "relation" - only in case of smartcrop preset
236                    if (payload && payload.set.relation && payload.set.relation.length > 0) {
237                        for (var i = 0; i < payload.set.relation.length; i++) {
238                            autoSmartCrops[parseInt(payload.set.relation[i].userdata.SmartCropWidth)] =
239                                ":" + payload.set.relation[i].userdata.SmartCropDef;
240                        }
241                    }
242                } else {
243                    // error status
244                }
245            };
246            request.send();
247            return autoSmartCrops;
248        };
249
250        /**
251         * Build and return the srcset value based on the available auto smart crops
252         * @param {String} src the src uri
253         * @param {Object} smartCrops the smart crops object
254         * @returns {String} the srcset
255         */
256        var getSrcSet = function(src, smartCrops) {
257            var srcset;
258            var keys = Object.keys(smartCrops);
259            if (keys.length > 0) {
260                srcset = [];
261                for (var key in autoSmartCrops) {
262                    srcset.push(src.replace(SRC_URI_TEMPLATE_WIDTH_VAR, smartCrops[key]) + " " + key + "w");
263                }
264            }
265            return  srcset.join(",");
266        };
267
268        /**
269         * Get the optimal width based on the available sizes
270         * @param {[Number]} sizes the available sizes
271         * @param {Number} width the element width
272         * @returns {String} the optimal width
273         */
274        function getOptimalWidth(sizes, width) {
275            var len = sizes.length;
276            var key = 0;
277
278            while ((key < len - 1) && (sizes[key] < width)) {
279                key++;
280            }
281
282            return sizes[key] !== undefined ? sizes[key].toString() : width;
283        }
284
285        /**
286         * Get the width of an element or parent element if the width is smaller than the minimum width
287         * @param {HTMLElement} component the image component
288         * @param {HTMLElement | Node} parent the parent element
289         * @returns {Number} the width of the element
290         */
291        var getWidth = function(component, parent) {
292            var width = component.offsetWidth;
293            while (width < config.minWidth && parent && !component._autoWidth) {
294                width =  parent.offsetWidth;
295                parent = parent.parentNode;
296            }
297            return width;
298        };
299
300        /**
301         * Set the src and srcset attribute for a Dynamic Media Image which auto smart crops enabled.
302         * @param {HTMLElement} component the image component
303         * @param {{}} properties the component properties
304         */
305        var setDMAttributes = function(component, properties) {
306            // for v3 we first have to turn the dpr on
307            var src = properties.src.replace(SRC_URI_DPR_OFF, SRC_URI_DPR_ON);
308            src = src.replace(SRC_URI_TEMPLATE_DPR_VAR, dpr);
309            var smartCrops = {};
310            var width;
311            if (properties["smartcroprendition"] === "SmartCrop:Auto") {
312                smartCrops = getAutoSmartCrops(src);
313            }
314            var hasWidths = (properties.widths && properties.widths.length > 0) || Object.keys(smartCrops).length > 0;
315            if (hasWidths) {
316                var image = component.querySelector("img");
317                var elemWidth = getWidth(component, component.parentNode);
318                if (properties["smartcroprendition"] === "SmartCrop:Auto") {
319                    image.setAttribute("srcset", CMP.image.dynamicMedia.getSrcSet(src, smartCrops));
320                    width = getOptimalWidth(Object.keys(smartCrops, elemWidth));
321                    image.setAttribute("src", CMP.image.dynamicMedia.getSrc(src, smartCrops[width]));
322                } else {
323                    width = getOptimalWidth(properties.widths, elemWidth);
324                    image.setAttribute("src", CMP.image.dynamicMedia.getSrc(src, width));
325                }
326            }
327        };
328
329        /**
330         * Get the src attribute based on the optimal width
331         * @param {String} src the src uri
332         * @param {String} width the element width
333         * @returns {String} the final src attribute
334         */
335        var getSrc = function(src, width) {
336            if (src.indexOf(SRC_URI_TEMPLATE_WIDTH_VAR) > -1) {
337                src = src.replace(SRC_URI_TEMPLATE_WIDTH_VAR, width);
338            }
339            return src;
340        };
341
342
343        return {
344            getAutoSmartCrops: getAutoSmartCrops,
345            getSrcSet: getSrcSet,
346            getSrc: getSrc,
347            setDMAttributes: setDMAttributes,
348            getWidth: getWidth
349        };
350    }());
351    document.dispatchEvent(new CustomEvent("core.wcm.components.commons.site.image.dynamic-media.loaded"));
352}(window.document));
353
354/*******************************************************************************
355 * Copyright 2016 Adobe
356 *
357 * Licensed under the Apache License, Version 2.0 (the "License");
358 * you may not use this file except in compliance with the License.
359 * You may obtain a copy of the License at
360 *
361 *     http://www.apache.org/licenses/LICENSE-2.0
362 *
363 * Unless required by applicable law or agreed to in writing, software
364 * distributed under the License is distributed on an "AS IS" BASIS,
365 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
366 * See the License for the specific language governing permissions and
367 * limitations under the License.
368 ******************************************************************************/
369(function() {
370    "use strict";
371
372    var NS = "cmp";
373    var IS = "image";
374
375    var EMPTY_PIXEL = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
376    var LAZY_THRESHOLD_DEFAULT = 0;
377    var SRC_URI_TEMPLATE_WIDTH_VAR = "{.width}";
378    var SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY = "width={width}";
379    var SRC_URI_TEMPLATE_DPR_VAR = "{dpr}";
380
381    var selectors = {
382        self: "[data-" + NS + '-is="' + IS + '"]',
383        image: '[data-cmp-hook-image="image"]',
384        map: '[data-cmp-hook-image="map"]',
385        area: '[data-cmp-hook-image="area"]'
386    };
387
388    var lazyLoader = {
389        "cssClass": "cmp-image__image--is-loading",
390        "style": {
391            "height": 0,
392            "padding-bottom": "" // will be replaced with % ratio
393        }
394    };
395
396    var properties = {
397        /**
398         * An array of alternative image widths (in pixels).
399         * Used to replace a {.width} variable in the src property with an optimal width if a URI template is provided.
400         *
401         * @memberof Image
402         * @type {Number[]}
403         * @default []
404         */
405        "widths": {
406            "default": [],
407            "transform": function(value) {
408                var widths = [];
409                value.split(",").forEach(function(item) {
410                    item = parseFloat(item);
411                    if (!isNaN(item)) {
412                        widths.push(item);
413                    }
414                });
415                return widths;
416            }
417        },
418        /**
419         * Indicates whether the image should be rendered lazily.
420         *
421         * @memberof Image
422         * @type {Boolean}
423         * @default false
424         */
425        "lazy": {
426            "default": false,
427            "transform": function(value) {
428                return !(value === null || typeof value === "undefined");
429            }
430        },
431        /**
432         * Indicates image is DynamicMedia image.
433         *
434         * @memberof Image
435         * @type {Boolean}
436         * @default false
437         */
438        "dmimage": {
439            "default": false,
440            "transform": function(value) {
441                return !(value === null || typeof value === "undefined");
442            }
443        },
444        /**
445         * The lazy threshold.
446         * This is the number of pixels, in advance of becoming visible, when an lazy-loading image should begin
447         * to load.
448         *
449         * @memberof Image
450         * @type {Number}
451         * @default 0
452         */
453        "lazythreshold": {
454            "default": 0,
455            "transform": function(value) {
456                var val =  parseInt(value);
457                if (isNaN(val)) {
458                    return LAZY_THRESHOLD_DEFAULT;
459                }
460                return val;
461            }
462        },
463        /**
464         * The image source.
465         *
466         * Can be a simple image source, or a URI template representation that
467         * can be variable expanded - useful for building an image configuration with an alternative width.
468         * e.g. '/path/image.coreimg{.width}.jpeg/1506620954214.jpeg'
469         *
470         * @memberof Image
471         * @type {String}
472         */
473        "src": {
474            "transform": function(value) {
475                return decodeURIComponent(value);
476            }
477        }
478    };
479
480    var devicePixelRatio = window.devicePixelRatio || 1;
481
482    function Image(config) {
483        var that = this;
484
485        var smartCrops = {};
486
487        var useAssetDelivery = false;
488        var srcUriTemplateWidthVar = SRC_URI_TEMPLATE_WIDTH_VAR;
489
490        function init(config) {
491            // prevents multiple initialization
492            config.element.removeAttribute("data-" + NS + "-is");
493
494            // check if asset delivery is used
495            if (config.options.src && config.options.src.indexOf(SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY) >= 0) {
496                useAssetDelivery = true;
497                srcUriTemplateWidthVar = SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY;
498            }
499
500            that._properties = CMP.utils.setupProperties(config.options, properties);
501            cacheElements(config.element);
502            // check image is DM asset; if true try to make req=set
503            if (config.options.src && Object.prototype.hasOwnProperty.call(config.options, "dmimage") && (config.options["smartcroprendition"] === "SmartCrop:Auto")) {
504                smartCrops = CMP.image.dynamicMedia.getAutoSmartCrops(config.options.src);
505            }
506
507            if (!that._elements.noscript) {
508                return;
509            }
510
511            that._elements.container = that._elements.link ? that._elements.link : that._elements.self;
512
513            unwrapNoScript();
514
515            if (that._properties.lazy) {
516                addLazyLoader();
517            }
518
519            if (that._elements.map) {
520                that._elements.image.addEventListener("load", onLoad);
521            }
522
523            window.addEventListener("resize", onWindowResize);
524            ["focus", "click", "load", "transitionend", "animationend", "scroll"].forEach(function(name) {
525                document.addEventListener(name, that.update);
526            });
527
528            that._elements.image.addEventListener("cmp-image-redraw", that.update);
529
530            that._interSectionObserver = new IntersectionObserver(function(entries, interSectionObserver) {
531                entries.forEach(function(entry) {
532                    if (entry.intersectionRatio > 0) {
533                        that.update();
534                    }
535                });
536            });
537            that._interSectionObserver.observe(that._elements.self);
538
539            that.update();
540        }
541
542        function loadImage() {
543            var hasWidths = (that._properties.widths && that._properties.widths.length > 0) || Object.keys(smartCrops).length > 0;
544            var replacement;
545            if (Object.keys(smartCrops).length > 0) {
546                var optimalWidth = getOptimalWidth(Object.keys(smartCrops), false);
547                replacement = smartCrops[optimalWidth];
548            } else {
549                replacement = hasWidths ? (that._properties.dmimage ? "" : ".") + getOptimalWidth(that._properties.widths, true) : "";
550            }
551            if (useAssetDelivery) {
552                replacement = replacement !== "" ? ("width=" + replacement.substring(1)) : "";
553            }
554            var url = that._properties.src.replace(srcUriTemplateWidthVar, replacement);
555            url = url.replace(SRC_URI_TEMPLATE_DPR_VAR, devicePixelRatio);
556
557            var imgSrcAttribute = that._elements.image.getAttribute("src");
558
559            if (url !== imgSrcAttribute) {
560                if (imgSrcAttribute === null || imgSrcAttribute === EMPTY_PIXEL) {
561                    that._elements.image.setAttribute("src", url);
562                } else {
563                    var urlTemplateParts = that._properties.src.split(srcUriTemplateWidthVar);
564                    // check if image src was dynamically swapped meanwhile (e.g. by Target)
565                    var isImageRefSame = imgSrcAttribute.startsWith(urlTemplateParts[0]);
566                    if (isImageRefSame && urlTemplateParts.length > 1) {
567                        isImageRefSame = imgSrcAttribute.endsWith(urlTemplateParts[urlTemplateParts.length - 1]);
568                    }
569                    if (isImageRefSame) {
570                        that._elements.image.setAttribute("src", url);
571                        if (!hasWidths) {
572                            window.removeEventListener("scroll", that.update);
573                        }
574                    }
575                }
576            }
577            if (that._lazyLoaderShowing) {
578                that._elements.image.addEventListener("load", removeLazyLoader);
579            }
580            that._interSectionObserver.unobserve(that._elements.self);
581        }
582
583        function getOptimalWidth(widths, useDevicePixelRatio) {
584            var container = that._elements.self;
585            var containerWidth = container.clientWidth;
586            while (containerWidth === 0 && container.parentNode) {
587                container = container.parentNode;
588                containerWidth = container.clientWidth;
589            }
590
591            var dpr = useDevicePixelRatio ? devicePixelRatio : 1;
592            var optimalWidth = containerWidth * dpr;
593            var len = widths.length;
594            var key = 0;
595
596            while ((key < len - 1) && (widths[key] < optimalWidth)) {
597                key++;
598            }
599
600            return widths[key].toString();
601        }
602
603        function addLazyLoader() {
604            var width = that._elements.image.getAttribute("width");
605            var height = that._elements.image.getAttribute("height");
606
607            if (width && height) {
608                var ratio = (height / width) * 100;
609                var styles = lazyLoader.style;
610
611                styles["padding-bottom"] = ratio + "%";
612
613                for (var s in styles) {
614                    if (Object.prototype.hasOwnProperty.call(styles, s)) {
615                        that._elements.image.style[s] = styles[s];
616                    }
617                }
618            }
619            that._elements.image.setAttribute("src", EMPTY_PIXEL);
620            that._elements.image.classList.add(lazyLoader.cssClass);
621            that._lazyLoaderShowing = true;
622        }
623
624        function unwrapNoScript() {
625            var markup = decodeNoscript(that._elements.noscript.textContent.trim());
626            var parser = new DOMParser();
627
628            // temporary document avoids requesting the image before removing its src
629            var temporaryDocument = parser.parseFromString(markup, "text/html");
630            var imageElement = temporaryDocument.querySelector(selectors.image);
631            imageElement.removeAttribute("src");
632            that._elements.container.insertBefore(imageElement, that._elements.noscript);
633
634            var mapElement = temporaryDocument.querySelector(selectors.map);
635            if (mapElement) {
636                that._elements.container.insertBefore(mapElement, that._elements.noscript);
637            }
638
639            that._elements.noscript.parentNode.removeChild(that._elements.noscript);
640            if (that._elements.container.matches(selectors.image)) {
641                that._elements.image = that._elements.container;
642            } else {
643                that._elements.image = that._elements.container.querySelector(selectors.image);
644            }
645
646            that._elements.map = that._elements.container.querySelector(selectors.map);
647            that._elements.areas = that._elements.container.querySelectorAll(selectors.area);
648        }
649
650        function removeLazyLoader() {
651            that._elements.image.classList.remove(lazyLoader.cssClass);
652            for (var property in lazyLoader.style) {
653                if (Object.prototype.hasOwnProperty.call(lazyLoader.style, property)) {
654                    that._elements.image.style[property] = "";
655                }
656            }
657            that._elements.image.removeEventListener("load", removeLazyLoader);
658            that._lazyLoaderShowing = false;
659        }
660
661        function isLazyVisible() {
662            if (that._elements.container.offsetParent === null) {
663                return false;
664            }
665
666            var wt = window.pageYOffset;
667            var wb = wt + document.documentElement.clientHeight;
668            var et = that._elements.container.getBoundingClientRect().top + wt;
669            var eb = et + that._elements.container.clientHeight;
670
671            return eb >= wt - that._properties.lazythreshold && et <= wb + that._properties.lazythreshold;
672        }
673
674        function resizeAreas() {
675            if (that._elements.areas && that._elements.areas.length > 0) {
676                for (var i = 0; i < that._elements.areas.length; i++) {
677                    var width = that._elements.image.width;
678                    var height = that._elements.image.height;
679
680                    if (width && height) {
681                        var relcoords = that._elements.areas[i].dataset.cmpRelcoords;
682                        if (relcoords) {
683                            var relativeCoordinates = relcoords.split(",");
684                            var coordinates = new Array(relativeCoordinates.length);
685
686                            for (var j = 0; j < coordinates.length; j++) {
687                                if (j % 2 === 0) {
688                                    coordinates[j] = parseInt(relativeCoordinates[j] * width);
689                                } else {
690                                    coordinates[j] = parseInt(relativeCoordinates[j] * height);
691                                }
692                            }
693
694                            that._elements.areas[i].coords = coordinates;
695                        }
696                    }
697                }
698            }
699        }
700
701        function cacheElements(wrapper) {
702            that._elements = {};
703            that._elements.self = wrapper;
704            var hooks = that._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]");
705
706            for (var i = 0; i < hooks.length; i++) {
707                var hook = hooks[i];
708                var capitalized = IS;
709                capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1);
710                var key = hook.dataset[NS + "Hook" + capitalized];
711                that._elements[key] = hook;
712            }
713        }
714
715        function onWindowResize() {
716            that.update();
717            resizeAreas();
718        }
719
720        function onLoad() {
721            resizeAreas();
722        }
723
724        that.update = function() {
725            if (that._properties.lazy) {
726                if (isLazyVisible()) {
727                    loadImage();
728                }
729            } else {
730                loadImage();
731            }
732        };
733
734        if (config && config.element) {
735            init(config);
736        }
737    }
738
739    function onDocumentReady() {
740        var elements = document.querySelectorAll(selectors.self);
741        for (var i = 0; i < elements.length; i++) {
742            new Image({ element: elements[i], options: CMP.utils.readData(elements[i], IS) });
743        }
744
745        var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
746        var body             = document.querySelector("body");
747        var observer         = new MutationObserver(function(mutations) {
748            mutations.forEach(function(mutation) {
749                // needed for IE
750                var nodesArray = [].slice.call(mutation.addedNodes);
751                if (nodesArray.length > 0) {
752                    nodesArray.forEach(function(addedNode) {
753                        if (addedNode.querySelectorAll) {
754                            var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self));
755                            elementsArray.forEach(function(element) {
756                                new Image({ element: element, options: CMP.utils.readData(element, IS) });
757                            });
758                        }
759                    });
760                }
761            });
762        });
763
764        observer.observe(body, {
765            subtree: true,
766            childList: true,
767            characterData: true
768        });
769    }
770
771    var documentReady = document.readyState !== "loading" ? Promise.resolve() : new Promise(function(resolve) {
772        document.addEventListener("DOMContentLoaded", resolve);
773    });
774
775    Promise.all([documentReady]).then(onDocumentReady);
776    /*
777        on drag & drop of the component into a parsys, noscript's content will be escaped multiple times by the editor which creates
778        the DOM for editing; the HTML parser cannot be used here due to the multiple escaping
779     */
780    function decodeNoscript(text) {
781        text = text.replace(/&(amp;)*lt;/g, "<");
782        text = text.replace(/&(amp;)*gt;/g, ">");
783        return text;
784    }
785
786})();
787

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.