PageSourceSearch

https://kamnemir.ru/templates/stek/js/header-minicart.js?_ver=1788693840

js kamnemir.ru collected 2026-10-02 20:31:42 UTC 8,878 bytes, 290 lines download raw bytes

1(function () {
2	'use strict';
3
4	var PLACEHOLDER = '/templates/stek/images/cart-item-img.png';
5	var STORAGE_KEY = 'km_minicart_meta_v1';
6	var metaByKey = {};
7
8	function toArray(obj) {
9		if (!obj) return [];
10		return Array.isArray(obj) ? obj : Object.keys(obj).map(function (k) {
11			return obj[k];
12		});
13	}
14
15	function loadMeta() {
16		try {
17			var raw = localStorage.getItem(STORAGE_KEY);
18			if (!raw) return;
19			var parsed = JSON.parse(raw);
20			if (parsed && typeof parsed === 'object') metaByKey = parsed;
21		} catch (e) {}
22	}
23
24	function saveMeta() {
25		try {
26			localStorage.setItem(STORAGE_KEY, JSON.stringify(metaByKey));
27		} catch (e) {}
28	}
29
30	function esc(s) {
31		return String(s)
32			.replace(/&/g, '&')
33			.replace(/</g, '&lt;')
34			.replace(/>/g, '&gt;')
35			.replace(/"/g, '&quot;');
36	}
37
38	function cartCountNodes() {
39		return document.querySelectorAll('a.basket-action-icon[href*="/emarket/cart"] .basket-action-icon-count');
40	}
41
42	function setCount(n) {
43		n = Math.max(0, parseInt(n, 10) || 0);
44		cartCountNodes().forEach(function (el) {
45			el.textContent = String(n);
46		});
47	}
48
49	function optionKeys(item) {
50		var keys = [];
51		var opts = item && item.options && item.options.option ? toArray(item.options.option) : [];
52		opts.forEach(function (o) {
53			if (!o) return;
54			if (o.id != null && String(o.id) !== '') keys.push(String(o.id));
55			if (o.name != null && String(o.name) !== '') keys.push(String(o.name));
56			if (o.float != null && String(o.float) !== '') keys.push(String(o.float));
57			if (o.value != null && String(o.value) !== '') keys.push(String(o.value));
58		});
59		return keys;
60	}
61
62	function itemKeys(item) {
63		// Сначала gid/option — иначе один parent id подменяет фото разных остатков
64		var keys = optionKeys(item);
65		if (item && item.id != null) keys.push(String(item.id));
66		if (item && item.page && item.page.id != null) keys.push(String(item.page.id));
67		return keys;
68	}
69
70	function metaFor(item) {
71		var keys = itemKeys(item);
72		for (var i = 0; i < keys.length; i++) {
73			if (metaByKey[keys[i]] && (metaByKey[keys[i]].thumb || metaByKey[keys[i]].title)) {
74				return metaByKey[keys[i]];
75			}
76		}
77		return null;
78	}
79
80	function remember(meta) {
81		if (!meta) return;
82		var title = String(meta.title || '').trim();
83		var thumb = String(meta.thumb || meta.img || '').trim();
84		if (!title && !thumb) return;
85		var keys = [];
86		if (meta.key != null && String(meta.key) !== '') keys.push(String(meta.key));
87		if (meta.gid != null && String(meta.gid) !== '') {
88			keys.push(String(meta.gid));
89		} else if (meta.id != null && String(meta.id) !== '') {
90			// parent id только без gid — иначе разные остатки одного камня делят одно фото
91			keys.push(String(meta.id));
92		}
93		if (!keys.length) return;
94		keys.forEach(function (key) {
95			var prev = metaByKey[key] || {};
96			metaByKey[key] = {
97				title: title || prev.title || '',
98				thumb: thumb || prev.thumb || ''
99			};
100		});
101		saveMeta();
102	}
103
104	function itemTitle(item) {
105		var meta = metaFor(item);
106		if (meta && meta.title) return meta.title;
107		if (item.page && item.page.name) return item.page.name;
108		if (item.name) return item.name;
109		return 'Товар';
110	}
111
112	function itemLink(item) {
113		if (item.page && item.page.link) return item.page.link;
114		return '/emarket/cart/';
115	}
116
117	function itemThumb(item) {
118		var meta = metaFor(item);
119		if (meta && meta.thumb) return meta.thumb;
120		if (item.page && item.page.thumbnail) return item.page.thumbnail;
121		if (item.thumbnail) return item.thumbnail;
122		if (item.page && item.page.image) return item.page.image;
123		return PLACEHOLDER;
124	}
125
126	function itemPrice(item) {
127		var price = item.price || item['total-price'];
128		if (!price) return '';
129		var val = price.actual || price.original;
130		if (!val) return '';
131		var suffix = price.suffix || ' ₽';
132		return String(val) + suffix;
133	}
134
135	function indexLeftoverCards() {
136		document.querySelectorAll('.leftovers-stone-card[data-gid], .leftovers-stone-card[data-product]').forEach(function (card) {
137			remember({
138				id: card.getAttribute('data-product') || '',
139				gid: card.getAttribute('data-gid') || '',
140				title: card.getAttribute('data-title') || '',
141				thumb: card.getAttribute('data-img') || ''
142			});
143		});
144	}
145
146	function renderMinicart(data) {
147		var items = data && data.items && data.items.item ? toArray(data.items.item) : [];
148		var hasItems = items.length > 0;
149
150		document.querySelectorAll('.km-minicart__body').forEach(function (body) {
151			var empty = body.querySelector('.km-minicart__empty');
152			var list = body.querySelector('.km-minicart__list');
153			if (!empty || !list) return;
154
155			if (!hasItems) {
156				empty.hidden = false;
157				list.hidden = true;
158				list.innerHTML = '';
159				return;
160			}
161
162			empty.hidden = true;
163			list.hidden = false;
164			list.innerHTML = items.map(function (item) {
165				var title = esc(itemTitle(item));
166				var link = esc(itemLink(item));
167				var thumb = esc(itemThumb(item));
168				var itemId = item && item.id != null ? String(item.id) : '';
169				var price = itemPrice(item);
170				var qty = parseInt(item.amount, 10);
171				if (isNaN(qty) || qty < 1) qty = 1;
172				var priceHtml = price ? '<span class="km-minicart__price">' + price + '</span>' : '';
173				var qtyHtml = '<span class="km-minicart__qty">' + qty + ' шт.</span>';
174				var removeHtml = itemId
175					? '<button type="button" class="km-minicart__remove" data-remove-item="' +
176						esc(itemId) +
177						'" aria-label="Удалить из корзины" title="Удалить">×</button>'
178					: '';
179				return (
180					'<li class="km-minicart__item">' +
181					'<a class="km-minicart__thumb" href="' + link + '">' +
182					'<img src="' + thumb + '" alt="" width="48" height="48" loading="lazy">' +
183					'</a>' +
184					'<div class="km-minicart__meta">' +
185					'<a class="km-minicart__title" href="' + link + '">' + title + '</a>' +
186					'<div class="km-minicart__line">' + priceHtml + qtyHtml + '</div>' +
187					'</div>' +
188					removeHtml +
189					'</li>'
190				);
191			}).join('');
192		});
193	}
194
195	function syncLeftoverButtons(data) {
196		var inCart = {};
197		var items = data && data.items && data.items.item ? toArray(data.items.item) : [];
198		items.forEach(function (item) {
199			itemKeys(item).forEach(function (key) {
200				inCart[key] = true;
201			});
202		});
203
204		document.querySelectorAll('[data-add-cart], [data-popup-add-cart], [data-add-cart-main]').forEach(function (btn) {
205			var card = btn.closest('.leftovers-stone-card, .leftovers-popup, .leftovers-stone');
206			var gid = (card && card.getAttribute('data-gid')) || '';
207			var productId =
208				(card && (card.getAttribute('data-product') || card.getAttribute('data-product-id'))) ||
209				btn.getAttribute('data-product') ||
210				'';
211			var isIn =
212				(gid && inCart[gid]) ||
213				(productId && inCart[productId] && btn.hasAttribute('data-add-cart-main'));
214
215			if (isIn) {
216				if (!btn.getAttribute('data-label')) {
217					btn.setAttribute('data-label', (btn.textContent || '').trim() || 'Добавить в корзину');
218				}
219				btn.setAttribute('data-in-cart', '1');
220				btn.textContent = 'В корзине';
221			} else if (btn.getAttribute('data-in-cart') === '1') {
222				btn.removeAttribute('data-in-cart');
223				btn.textContent = btn.getAttribute('data-label') || 'Добавить в корзину';
224			}
225		});
226	}
227
228	function removeItem(itemId, btn) {
229		itemId = String(itemId || '').trim();
230		if (!itemId) return Promise.resolve();
231		if (btn) btn.disabled = true;
232		return fetch('/udata/emarket/basket/remove/item/' + encodeURIComponent(itemId) + '/.json', {
233			method: 'POST',
234			credentials: 'same-origin',
235			headers: { 'X-Requested-With': 'XMLHttpRequest' }
236		})
237			.then(function () {
238				return refresh();
239			})
240			.catch(function (err) {
241				console.error('kmCart remove error:', err);
242				if (btn) btn.disabled = false;
243			});
244	}
245
246	function refresh() {
247		indexLeftoverCards();
248		return fetch('/udata/emarket/cart/.json', {
249			method: 'GET',
250			credentials: 'same-origin',
251			headers: { 'X-Requested-With': 'XMLHttpRequest' }
252		})
253			.then(function (res) {
254				return res.json();
255			})
256			.then(function (data) {
257				var amount = data && data.summary ? parseInt(data.summary.amount, 10) || 0 : 0;
258				setCount(amount);
259				renderMinicart(data);
260				syncLeftoverButtons(data);
261				return data;
262			})
263			.catch(function (err) {
264				console.error('kmCart refresh error:', err);
265			});
266	}
267
268	loadMeta();
269
270	document.addEventListener('click', function (e) {
271		var btn = e.target.closest('.km-minicart__remove[data-remove-item]');
272		if (!btn) return;
273		e.preventDefault();
274		e.stopPropagation();
275		removeItem(btn.getAttribute('data-remove-item'), btn);
276	});
277
278	window.kmCart = {
279		refresh: refresh,
280		setCount: setCount,
281		remember: remember,
282		removeItem: removeItem
283	};
284
285	if (document.readyState === 'loading') {
286		document.addEventListener('DOMContentLoaded', refresh);
287	} else {
288		refresh();
289	}
290})();

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.