PageSourceSearch

https://www.earthmotorcars.com/v9/media/js/unveil-intersection/1.0.0/lib.js

js earthmotorcars.com collected 2026-09-24 12:20:18 UTC 6,994 bytes, 207 lines download raw bytes

1/**
2 * Unveil Intersection
3 * 
4 * This is a lightweight module which would 
5 * lazy load images. And, dynamically resize our images.
6 * If, it contains the `dynamic-resize-(background)` class.
7 * 
8 * After doing any changes in this file remember to minify it by running
9 * `npm run build` in this directory.
10 */
11
12(() => {
13	'use strict';
14
15	const domainRegex = /(.*\/\/.*)?(pictures|images|static)(\.)([^.]+\.)?dealer\.com(.*)/;
16	const IMG = "image_tag";
17	const BG_IMG = "background_image";
18
19	class ImageElement {
20		constructor(img) {
21			this.img = img;
22			this.wrappedImage = img.getElementsByTagName('img')[0];
23			this.source = img.getAttribute("data-src");
24			this.type = img.getAttribute("data-src") ? IMG : BG_IMG;
25			if(this.type !== IMG) {
26				// In case the image is a background or a linked image
27				if (img.classList.contains('cta-background') || img.nodeName === 'A') {
28					this.wrapperDiv = img;
29				} else {
30					// In case of sections, make sure that the given wrapped div 
31					// has a data-responsive-image-bg attribute
32					const sectionWrapper = !img.hasAttribute('data-responsive-image-bg') && img.closest("[data-responsive-image-group]");
33					this.wrapperDiv = sectionWrapper ? sectionWrapper.querySelector('[data-responsive-image-bg]') : img;
34				}
35			}
36			if(!this.source) {
37				this.source = img.getAttribute("data-background-image");
38			}
39			// Support ws-content-cta widget
40			if(!this.source) {
41				// If the image has srcset
42				if(this.wrappedImage?.hasAttribute("data-sizes")) {
43					this.wrappedImage.setAttribute("sizes", this.wrappedImage.getAttribute("data-sizes"));
44				}
45				if(this.wrappedImage?.hasAttribute("data-srcset")) {
46					this.wrappedImage.setAttribute("srcset", this.wrappedImage.getAttribute("data-srcset"));
47					this.source = this.wrappedImage?.currentSrc;
48				}
49
50				// If the image has no srcset
51				if(this.wrappedImage?.hasAttribute("data-src")) {
52					this.source = this.wrappedImage.getAttribute("data-src");
53				}
54				
55			}
56			if(!this.source) {
57				if(img.hasAttribute("data-style")) {
58					img.setAttribute("style", img.getAttribute("data-style"))
59				}
60				this.source = '';
61			}
62		}
63
64		setSource(newSource) {
65			this.source = newSource;
66		}
67
68		getSource() {
69			return this.source;
70		}
71
72		setLazyImage() {
73			const imgUrl = this.getSource();
74			if(imgUrl) {
75				if(this.type === IMG) {
76					this.img.setAttribute("src", imgUrl);
77				} else {
78					// if lazyloading is already completed, skip setting it again
79					const isAlreadyLoaded = this.wrapperDiv?.hasAttribute('data-lazy-initialized');
80					if(!isAlreadyLoaded) {
81						if (this.wrapperDiv?.getAttribute("style")) {
82							// Incase the backgroundImage style already has gradient set.
83							const existingUrl = this.wrapperDiv.style['backgroundImage'] 
84								? this.wrapperDiv.style['backgroundImage'].match(/url\(\s*(?<url>.*?)\s*\)/)?.[0] ?? ""
85								: "";
86							this.wrapperDiv.style['backgroundImage'] = existingUrl
87								? this.wrapperDiv.style['backgroundImage'].replace(existingUrl, `url("${imgUrl}")`)
88								: `url("${imgUrl}")`;
89						} else {
90							this.wrapperDiv?.setAttribute('style', `background-image: url("${imgUrl}")`);
91						}
92						// set a flag indicating that lazyloading has finished
93						this.wrapperDiv?.setAttribute('data-lazy-initialized', true)
94					}
95				}
96			}
97			return this;
98		}
99
100		cleanLazyLoadAttrs() {
101			this.wrappedImage?.classList?.remove('lazy-image');
102			this.wrapperDiv?.classList?.remove('lazy-background-image');
103			this.wrapperDiv?.removeAttribute('data-background-image');
104			this.img.classList.remove('lazy-image');
105			this.img.classList.remove('lazy-background-image');
106			this.img.classList.remove('lazy-element');
107			this.img.removeAttribute('data-background-image');
108			this.img.removeAttribute('data-sizes');
109			this.img.removeAttribute('data-src');
110			this.img.removeAttribute('data-srcset');
111			this.img.removeAttribute('data-style');
112			if(this.img.getAttribute('width') === '1') {
113				this.img.removeAttribute('width');
114			}
115			if(this.img.getAttribute('height') === '1') {
116				this.img.removeAttribute('height');
117			}
118		}
119
120		isDealerImage() {
121			return this.getSource().indexOf('/static/') === 0 || domainRegex.test(this.getSource());
122		}
123
124		addParam(name, value) {
125			const imgUrl = this.getSource();
126			// Check if params don't already exists
127			if (imgUrl.indexOf(`?${name}=`) === -1 && imgUrl.indexOf(`&${name}=`) === -1) {
128				const param = `${name}=${value}`;
129				imgUrl.indexOf("?") === -1 
130					? this.setSource(`${imgUrl}?${param}`) 
131					: this.setSource(`${imgUrl}&${param}`);
132			}
133			return this;
134		}
135
136		addResizerParamsToSource(width) {
137			this.addParam('impolicy', 'downsize_bkpt').addParam('w', Math.round(width).toString());
138		}
139
140		dynamicallyResizeImage() {
141			const target = this.img;
142			const widthMultiplier = parseFloat(target.getAttribute('data-width-multiplier') || this.wrappedImage?.getAttribute('data-width-multiplier') || 1);
143
144			if (!this.isDealerImage()) {
145				return this;
146			}
147	
148			// Fix static.dealer.com paths to be /static/ while we're already modifying things.
149			if (this.getSource().indexOf('static.dealer.com') > -1) {
150				this.setSource(this.getSource().replace(/^(http(s?)\:)?\/\/static\.dealer\.com\//i, '/static/'));
151			}
152
153			if(target.classList.contains('dynamic-resize') || (this.wrappedImage?.classList?.contains('dynamic-resize') || false)) {
154				const minImageWidth = target.getAttribute('min-width');
155				let parentsWidth = target?.closest('li')?.getBoundingClientRect()?.width 
156					|| target?.closest('dd')?.getBoundingClientRect()?.width 
157					|| target?.closest('div')?.getBoundingClientRect()?.width;
158
159				parentsWidth = minImageWidth && parentsWidth < minImageWidth ? minImageWidth : parentsWidth;
160
161				if (parentsWidth > 0) {
162					this.addResizerParamsToSource(parentsWidth * widthMultiplier);
163				}
164			} else if(target.classList.contains('dynamic-resize-background')) {
165				const width = target?.getBoundingClientRect()?.width ?? 0;
166				if (width > 0) {
167					this.addResizerParamsToSource(width * widthMultiplier);
168				}
169			}
170			return this;
171		}
172
173		lazyLoad() {
174			this.dynamicallyResizeImage().setLazyImage().cleanLazyLoadAttrs();
175		}
176	}
177
178	const unveil = (selector, context = document, threshold) => {
179		const elements = context.querySelectorAll(selector);
180		const options = {
181			rootMargin: `${threshold}px 0px`
182		}
183
184		const handleUnveil = entries => {
185			entries.forEach(entry => {
186				if (entry.isIntersecting) {
187					const img = entry.target;
188					const imageElement = new ImageElement(img);
189					imageElement.lazyLoad();
190					
191					observer.unobserve(img);
192				}
193			});
194		}
195
196		const observer = new IntersectionObserver(handleUnveil, options);
197		elements.forEach(el => el.classList.contains("d-none") 
198			// To support ws-content-cta widget and section backgrounds which hides the img tag.
199			? observer.observe(el.closest('div'))
200			: observer.observe(el)
201		);
202		
203	}
204
205	const DDC = (window.DDC = (window.DDC || {}));
206	DDC.unveil = unveil;
207})();

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.