PageSourceSearch

https://www.skisport.dk/skishop/static/js/product.js?v=20260929093704

js skisport.dk collected 2026-09-29 08:03:13 UTC 6,477 bytes, 269 lines download raw bytes

1jQuery(document).ready(function()
2{
3	jQuery("[href='#readmore']").on("click", function(e)
4	{
5		jQuery("[href='#first']").click();
6
7		jQuery("body,html").animate({
8			scrollTop: jQuery(".product-description").offset().top - 80
9		}, 0);
10
11		e.preventDefault();
12	});
13
14	if(jQuery(".cz-countdown").html() !== undefined)
15	{
16		let object = jQuery(".cz-countdown .product-countdown");
17
18		let date = object.attr("attr-date");
19
20		let langhour = object.attr("attr-lang-hour");
21		let langminute = object.attr("attr-lang-minute");
22		let langsecond = object.attr("attr-lang-second");
23
24		let text = object.attr("attr-lang-text");
25
26		let strings = [
27			langhour,
28			langminute,
29			langsecond
30		]
31
32		let render = function()
33		{
34			let countdownhtml = countdown(date, strings, text);
35			jQuery(".time", object).html(countdownhtml);
36		};
37
38		// Render at once so the text does not pop in a second after load
39		render();
40
41		setInterval(render, 1000);
42	}
43
44	if(jQuery("#product_added_toast").html() !== undefined)
45	{
46		jQuery("#product_added_toast").toast("show");
47	}
48
49	if(jQuery("#product_not_added_amount_not_enough").html() !== undefined)
50	{
51		jQuery("#product_not_added_amount_not_enough").toast("show");
52	}
53
54	jQuery("[name='size_id'], [name='kit_size_id[]']").on("change", function()
55	{
56		// Hide amount info message
57		jQuery("#amountinfo").hide();
58
59		// Hide preorder message
60		jQuery("#preorderinfo").hide();
61
62		// Set amount
63		const amount = jQuery("option:selected", this).attr("attr-amount");
64
65		// Set preorder
66		const preorder = jQuery("option:selected", this).attr("attr-preorder");
67		const preorderdate = jQuery("option:selected", this).attr("attr-preorder-date");
68
69		// Check for preorder
70		if(preorder == '1')
71		{
72			// Set preorder date
73			jQuery("#preorderinfo span").html(preorderdate);
74
75			// Show preorder message
76			jQuery("#preorderinfo").show();
77		} else if(parseInt(amount) > 0) {
78			// Set amount info amount
79			jQuery("#amountinfo span").html(amount);
80
81			// Show amount info message
82			jQuery("#amountinfo").show();
83		}
84	});
85
86	// Count length of size
87	const lengthOfSizeIdSelect = jQuery("[name='size_id'] option").length;
88
89	// Check if 2
90	if(lengthOfSizeIdSelect == 2)
91	{
92		// Set amount
93		const amount = jQuery("option:selected", this).attr("attr-amount");
94
95		// Check for positive amount
96		if(parseInt(amount) > 0)
97		{
98			// Set amount info amount
99			jQuery("#amountinfo span").html(amount);
100
101			// Show amount info message
102			jQuery("#amountinfo").show();
103		}
104	}
105
106	// Listen on size chart show
107	jQuery("#size-chart").on("show.bs.modal", function (e) {
108		// Hide
109		jQuery(".modal-body span", e.target).hide();
110
111		// Set id
112		const id = jQuery(e.relatedTarget).attr("attr-sizechart-id");
113
114		// Show
115		jQuery(".modal-body span[attr-sizechart-id='" + id + "']", e.target).show();
116	})
117});
118
119// Pad a number to two digits so a ticking countdown does not change width
120function countdownPad(number)
121{
122	return ('0' + number).slice(-2);
123}
124
125function countdown(tid, strings, text)
126{
127	var now = Math.floor(jQuery.now() / 1000);
128	var diff = tid - now;
129	if(diff > 0)
130	{
131		var sek = diff % 60;
132		var min = Math.floor(diff / 60) % 60;
133		var timer = Math.floor(diff / 3600);
134
135		// Pad with a leading zero so the countdown keeps the same width every second
136		sek = countdownPad(sek);
137		min = countdownPad(min);
138		timer = countdownPad(timer);
139
140		return '<span>' + timer + '</span> ' + strings[0] + ' <span>' + min + '</span> ' + strings[1] + ' <span>' + sek + '</span> ' + strings[2];
141	}
142}
143
144// Activates a pop-up with price guarantee information
145jQuery(document).ready(function() {
146	jQuery(".product-title").on('copy', function(e) {
147		e.preventDefault();
148		jQuery("#priceguarantee").modal();
149	});
150});
151
152
153// Product gallery: thumbnail click + mobile swipe between images
154jQuery(document).ready(function() {
155	const gallery = document.querySelector('.cz-product-gallery');
156	if (!gallery) {
157		return;
158	}
159
160	const preview = gallery.querySelector('.cz-preview');
161	const SWIPE_THRESHOLD = 40;
162	const MOBILE_MQ = window.matchMedia('(max-width: 768px)');
163
164	function activateImage(href) {
165		if (!href || href.indexOf('#image-') !== 0) {
166			return;
167		}
168
169		const previews = gallery.querySelectorAll('.cz-preview-item');
170		const thumbs = gallery.querySelectorAll('.cz-thumblist-item:not(.video-item)');
171
172		for (let i = 0; i < previews.length; i++) {
173			previews[i].classList.remove('active');
174		}
175		for (let i = 0; i < thumbs.length; i++) {
176			thumbs[i].classList.remove('active');
177		}
178
179		const target = gallery.querySelector(href);
180		if (target) {
181			target.classList.add('active');
182		}
183
184		const matchingThumbs = gallery.querySelectorAll('.cz-thumblist-item[href="' + href + '"]');
185		for (let i = 0; i < matchingThumbs.length; i++) {
186			matchingThumbs[i].classList.add('active');
187		}
188	}
189
190	function swipeTo(deltaX) {
191		if (Math.abs(deltaX) < SWIPE_THRESHOLD) {
192			return;
193		}
194
195		const previews = gallery.querySelectorAll('.cz-preview-item');
196		if (previews.length < 2) {
197			return;
198		}
199
200		let index = -1;
201		for (let i = 0; i < previews.length; i++) {
202			if (previews[i].classList.contains('active')) {
203				index = i;
204				break;
205			}
206		}
207		if (index < 0) {
208			index = 0;
209		}
210
211		const nextIndex = deltaX < 0 ? index + 1 : index - 1;
212		if (nextIndex < 0 || nextIndex >= previews.length) {
213			return;
214		}
215
216		activateImage('#' + previews[nextIndex].id);
217	}
218
219	jQuery(gallery).on('click', '.cz-thumblist-item:not(.video-item)', function(e) {
220		e.preventDefault();
221		activateImage(jQuery(this).attr('href'));
222	});
223
224	if (!preview) {
225		return;
226	}
227
228	// Pointer events work for real touch devices and Chrome device-toolbar (mouse-as-touch).
229	// Only active at mobile widths so desktop image zoom is unaffected.
230	let startX = 0;
231	let startY = 0;
232	let tracking = false;
233	let pointerId = null;
234
235	preview.addEventListener('pointerdown', function(e) {
236		if (!MOBILE_MQ.matches || e.button !== 0) {
237			return;
238		}
239		tracking = true;
240		pointerId = e.pointerId;
241		startX = e.clientX;
242		startY = e.clientY;
243		try {
244			preview.setPointerCapture(e.pointerId);
245		} catch (err) {}
246	});
247
248	preview.addEventListener('pointerup', function(e) {
249		if (!tracking || e.pointerId !== pointerId) {
250			return;
251		}
252		tracking = false;
253		pointerId = null;
254
255		const dx = e.clientX - startX;
256		const dy = e.clientY - startY;
257		if (Math.abs(dx) <= Math.abs(dy)) {
258			return;
259		}
260		swipeTo(dx);
261	});
262
263	preview.addEventListener('pointercancel', function(e) {
264		if (e.pointerId === pointerId) {
265			tracking = false;
266			pointerId = null;
267		}
268	});
269});

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.