NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Best price helper for marketplace // @namespace http://tampermonkey.net/ // @version 0.4.3 // @description Считаем стоимость за штуку/за кг/за л // @author Apkawa // @license MIT // @icon https://www.google.com/s2/favicons?domain=ozon.ru // @match https://ozon.ru/* // @match https://www.ozon.ru/* // @match https://lenta.com/* // @match https://okeydostavka.ru/* // @match https://www.okeydostavka.ru/* // @match https://perekrestok.ru/* // @match https://www.perekrestok.ru/* // @homepage https://github.com/Apkawa/userscripts // @homepageUrl https://github.com/Apkawa/userscripts // @supportUrl https://github.com/Apkawa/userscripts/issues // @downloadUrl https://github.com/Apkawa/best_price_userscript/raw/release/release/best_price/best_price.user.js // @updateUrl https://github.com/Apkawa/best_price_userscript/raw/release/release/best_price/best_price.user.js // ==/UserScript== (function() { "use strict"; function getElementByXpath(xpath, root = document) { const e = document.evaluate(xpath, root, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; return e && e; } function waitElement(match, callback, root = document.body) { const observer = new MutationObserver((mutations => { let matchFlag = false; mutations.forEach((mutation => { if (!mutation.addedNodes) return; for (let i = 0; i < mutation.addedNodes.length; i++) { const node = mutation.addedNodes[i]; matchFlag = match(node); } })); if (matchFlag) { _stop(); callback(); _start(); } })); let isStarted = false; function _start() { if (isStarted) return; observer.observe(root || document.body, { childList: true, subtree: true, attributes: false, characterData: false }); isStarted = true; } function _stop() { observer.disconnect(); isStarted = false; } _start(); return () => { _stop(); }; } function waitCompletePage(callback, options = {}) { const {root: root = document.body, runOnce: runOnce = true, sync: sync = true, delay: delay = 150} = options; let t = null; let lock = false; const run = () => { const stop = waitElement((() => true), (() => { if (t) clearTimeout(t); t = setTimeout((() => { if (lock) return; lock = true; if (runOnce || sync) stop(); callback(); if (sync && !runOnce) setTimeout(run, delay); lock = false; }), delay); }), root); return stop; }; return run(); } function E(tag, attributes = {}, ...children) { const element = document.createElement(tag); for (const [k, v] of Object.entries(attributes)) element.setAttribute(k, v); const fragment = document.createDocumentFragment(); children.forEach((child => { if ("string" === typeof child) child = document.createTextNode(child); fragment.appendChild(child); })); element.appendChild(fragment); return element; } function ElementGetOrCreate(root, options = {}) { var _a; const {className: className = "GM-wrap", pos: pos = "appendChild"} = options; if (!root) return null; let wrapEl = null === (_a = root.parentElement) || void 0 === _a ? void 0 : _a.querySelector("." + className); if (!wrapEl) { wrapEl = E("div", { class: className }); root[pos](wrapEl); } return wrapEl; } function copyElementToNewRoot(el, toRoot, options = {}) { var _a, _b; const {className: className = "GM-cloned", pos: pos = "appendChild"} = options; if (!el) { console.warn(`el is ${typeof el}`); return; } let elList = []; if (el instanceof HTMLElement) elList = [ el ]; else elList = el; null === (_b = null === (_a = toRoot.parentElement) || void 0 === _a ? void 0 : _a.querySelectorAll("." + className)) || void 0 === _b ? void 0 : _b.forEach((e => e.remove())); for (const _el of elList) { const clonedEl = _el.cloneNode(true); clonedEl.classList.add(className); toRoot[pos](clonedEl); } } function isFunction(x) { return "function" === typeof x; } function matchLocation(...patterns) { const s = document.location.href; for (const p of patterns) { if (isFunction(p) && p(s)) return true; if (RegExp(p).test(s)) return true; } return false; } function GM_addStyle(css) { const style = document.getElementById("GM_addStyleBy8626") || function() { const style = document.createElement("style"); style.type = "text/css"; style.id = "GM_addStyleBy8626"; document.head.appendChild(style); return style; }(); const sheet = style.sheet; null === sheet || void 0 === sheet ? void 0 : sheet.insertRule(css, (sheet.rules || sheet.cssRules || []).length); } function isRegexp(value) { return "[object RegExp]" === toString.call(value); } function mRegExp(regExps) { return RegExp(regExps.map((function(r) { if (isRegexp(r)) return r.source; return r; })).join("")); } function round(n, parts = 2) { const i = Math.pow(10, parts); return Math.round(n * i) / i; } Object.keys; const entries = Object.entries; const values = Object.values; const WORD_BOUNDARY_END = /(?=\s|[.,);/]|$)/; const WEIGHT_REGEXP = mRegExp([ /(?<value>\d+[,.]\d+|\d+)/, /\s?/, "(?<unit>", "(?<weight_unit>(?<weight_SI>кг|килограмм(?:ов|а|))|г|грамм(?:ов|а|)|гр)", "|(?<volume_unit>(?<volume_SI>л|литр(?:ов|а|))|мл)", "|(?<length_unit>(?<length_SI>м|метр(?:ов|а|)))", ")", WORD_BOUNDARY_END ]); const QUANTITY_UNITS = [ "шт", "рулон", "пакет", "уп", "упаков(?:ок|ки|ка)", "салфет(?:ок|ки|ка)", "таб", "капсул" ]; const QUANTITY_REGEXP = RegExp(`(?<quantity>\\d+)\\s?(?<quantity_unit>${QUANTITY_UNITS.join("|")})\\.?`); const QUANTITY_2_REGEXP = RegExp(`(?<quantity_2>\\d+)\\s?(?<quantity_2_unit>${QUANTITY_UNITS.join("|")})\\.?`); const COMBINE_DELIMETER_REGEXP = /\s?(?:[xх*×/]|по)\s?/; const COMBINE_QUANTITY_LIST = [ mRegExp([ /(?<quantity_2>\d+)/, COMBINE_DELIMETER_REGEXP, QUANTITY_REGEXP ]), mRegExp([ QUANTITY_REGEXP, COMBINE_DELIMETER_REGEXP, /(?<quantity_2>\d+)/ ]), mRegExp([ QUANTITY_2_REGEXP, COMBINE_DELIMETER_REGEXP, QUANTITY_REGEXP ]) ]; const COMBINE_QANTITY_WEIGHT_REGEXP_LIST = [ mRegExp([ WEIGHT_REGEXP, COMBINE_DELIMETER_REGEXP, QUANTITY_REGEXP ]), mRegExp([ QUANTITY_REGEXP, COMBINE_DELIMETER_REGEXP, WEIGHT_REGEXP ]), mRegExp([ /(?<quantity>\d+)/, COMBINE_DELIMETER_REGEXP, WEIGHT_REGEXP ]), mRegExp([ WEIGHT_REGEXP, COMBINE_DELIMETER_REGEXP, /(?<quantity>\d+)/ ]) ]; function parseGroups(groups) { const result = { weight: null, item_weight: null, weight_unit: null, quantity: 1 }; if (groups.value) { const valueStr = null === groups || void 0 === groups ? void 0 : groups.value; const unit = null === groups || void 0 === groups ? void 0 : groups.unit; if (valueStr && unit) { let value = parseFloat(valueStr.replace(",", ".")); if (groups.weight_unit) { if (!groups.weight_SI) value /= 1e3; result.weight_unit = "кг"; } if (groups.volume_unit) { if (!groups.volume_SI) value /= 1e3; result.weight_unit = "л"; } if (groups.length_unit) { if (!groups.length_SI) value /= 1e3; result.weight_unit = "м"; } result.weight = value; result.item_weight = value; } } if (groups.quantity) { const valueStr = null === groups || void 0 === groups ? void 0 : groups.quantity; if (valueStr) result.quantity = parseInt(valueStr); } if (result.item_weight && result.quantity > 1) result.weight = result.quantity * result.item_weight; return result; } function parseTitle(title) { var _a; for (const r of COMBINE_QANTITY_WEIGHT_REGEXP_LIST) { const rMatch = r.exec(title); if (rMatch) return parseGroups(rMatch.groups); } let groups = {}; const weightMatch = WEIGHT_REGEXP.exec(title); if (null === weightMatch || void 0 === weightMatch ? void 0 : weightMatch.groups) groups = weightMatch.groups; let quantity = 0; for (const r of COMBINE_QUANTITY_LIST) { const rMatch = null === (_a = r.exec(title)) || void 0 === _a ? void 0 : _a.groups; if ((null === rMatch || void 0 === rMatch ? void 0 : rMatch.quantity) && (null === rMatch || void 0 === rMatch ? void 0 : rMatch.quantity_2)) { quantity = parseInt(rMatch.quantity) * parseInt(rMatch.quantity_2); break; } } if (quantity) groups.quantity = quantity.toString(); else { const quantityMatch = QUANTITY_REGEXP.exec(title); if (null === quantityMatch || void 0 === quantityMatch ? void 0 : quantityMatch.groups) groups = Object.assign(Object.assign({}, groups), quantityMatch.groups); } return parseGroups(groups); } function parseTitleWithPrice(title, price) { const res = Object.assign(Object.assign({}, parseTitle(title)), { weight_price: null, weight_price_display: null, quantity_price: null, quantity_price_display: null }); if ((!res.quantity || 1 == res.quantity) && !res.weight) return null; if (res.weight) { res.weight_price = round(price / res.weight); res.weight_price_display = `${res.weight_price} ₽/${res.weight_unit || "?"}`; } if (res.quantity > 1) { res.quantity_price = round(price / res.quantity); res.quantity_price_display = `${res.quantity_price} ₽/шт`; } return res; } const BEST_PRICE_CLASS_NAME = "GM-best-price"; const BEST_PRICE_WRAP_CLASS_NAME = "GM-best-price-wrap"; const ORDER_NAME_LOCAL_STORAGE = "GM-best-price-default-order"; const MAX_NUMBER = 99999999999; function renderBestPrice(titleInfo) { const wrapEl = document.createElement("div"); wrapEl.className = BEST_PRICE_CLASS_NAME; if (!titleInfo) return wrapEl; if (titleInfo.weight_price_display) { const weightEl = document.createElement("p"); weightEl.innerText = titleInfo.weight_price_display; wrapEl.appendChild(weightEl); } if (titleInfo.quantity_price_display) { const qtyEl = document.createElement("p"); qtyEl.innerText = titleInfo.quantity_price_display; wrapEl.appendChild(qtyEl); } if (wrapEl.childNodes.length) { wrapEl.style.border = "1px solid red"; wrapEl.style.padding = "5px"; wrapEl.style.margin = "5px"; wrapEl.style.width = "fit-content"; } return wrapEl; } function byPropertiesOf(sortBy) { function compareByProperty(arg) { let key; let sortOrder = 1; if ("string" === typeof arg && arg.startsWith("-")) { sortOrder = -1; key = arg.substr(1); } else key = arg; return function(a, b) { const result = a[key] < b[key] ? -1 : a[key] > b[key] ? 1 : 0; return result * sortOrder; }; } return function(obj1, obj2) { let i = 0; let result = 0; const numberOfProperties = null === sortBy || void 0 === sortBy ? void 0 : sortBy.length; while (0 === result && i < numberOfProperties) { result = compareByProperty(sortBy[i])(obj1, obj2); i++; } return result; }; } function sort(arr, ...sortBy) { arr.sort(byPropertiesOf(sortBy)); } const BEST_ORDER_BUTTON_CLASS_NAME = "GM-best-price-button-wrap"; GM_addStyle(`button.${BEST_ORDER_BUTTON_CLASS_NAME} {\nborder: 1px solid gray !important; padding: 5px !important; margin: 3px !important; }\n`); GM_addStyle(`button.${BEST_ORDER_BUTTON_CLASS_NAME}.active { border: 2px solid red !important; }`); function initReorderCatalog(catalogRoot, buttonRoot) { var _a; const buttonWrap = buttonRoot; if (!buttonWrap) return; const catalogRecords = []; let i = 0; for (const wrapEl of catalogRoot.querySelectorAll(":scope > *")) { const el = wrapEl.classList.contains(BEST_PRICE_WRAP_CLASS_NAME) ? wrapEl : wrapEl.querySelector("." + BEST_PRICE_WRAP_CLASS_NAME); if (!el) { console.warn("!", el); continue; } const ds = el.dataset; i += 1; let initial_order = parseInt(ds.initial_order || "0"); if (!initial_order) { initial_order = i; ds.initial_order = i.toString(); } catalogRecords.push({ el: wrapEl, initial_order: initial_order, weight_price: ds.weight_price ? parseFloat(ds.weight_price) : MAX_NUMBER, quantity_price: ds.quantity_price ? parseFloat(ds.quantity_price) : MAX_NUMBER }); } const buttons = { initial_order: E("button", { class: BEST_ORDER_BUTTON_CLASS_NAME }, "Reset"), weight_price: E("button", { class: BEST_ORDER_BUTTON_CLASS_NAME }, "by Weight"), quantity_price: E("button", { class: BEST_ORDER_BUTTON_CLASS_NAME }, "by Quantity") }; function buttonClickHandler(orderState) { console.log(orderState); localStorage.setItem(ORDER_NAME_LOCAL_STORAGE, orderState); sort(catalogRecords, orderState); refreshCatalog(); setActiveButton(buttons[orderState]); } for (const [k, b] of entries(buttons)) b.onclick = () => { buttonClickHandler(k); }; const defaultOrder = localStorage.getItem(ORDER_NAME_LOCAL_STORAGE); if (defaultOrder) if ("initial_order" === defaultOrder) setActiveButton(buttons[defaultOrder]); else buttonClickHandler(defaultOrder); function refreshCatalog() { const wrap = catalogRoot; if (!wrap) return; const elements = document.createDocumentFragment(); for (const c of catalogRecords) elements.appendChild(c.el); wrap.innerHTML = ""; wrap.appendChild(elements); } function setActiveButton(button) { for (const b of values(buttons)) b.classList.remove("active"); button.classList.add("active"); } null === (_a = buttonWrap.querySelector("." + BEST_ORDER_BUTTON_CLASS_NAME)) || void 0 === _a ? void 0 : _a.remove(); buttonWrap.appendChild(E("div", { class: BEST_ORDER_BUTTON_CLASS_NAME }, ...values(buttons))); } function getPriceFromElement(el) { var _a, _b; const priceText = null === (_b = null === (_a = null === el || void 0 === el ? void 0 : el.textContent) || void 0 === _a ? void 0 : _a.split("₽")[0]) || void 0 === _b ? void 0 : _b.trim(); if (priceText) return parseFloat(priceText.replace(" ", "").replace(" ", "").replace(" ", "").replace(/\s/g, "")); return null; } function getPrice(sel, root = document.body) { const priceEl = (root || document.body).querySelector(sel); return getPriceFromElement(priceEl); } function storeParsedTitleToElement(cardEl, parsedTitle) { cardEl.classList.add(BEST_PRICE_WRAP_CLASS_NAME); if (!parsedTitle) return; const ds = cardEl.dataset; for (const [k, v] of entries(parsedTitle)) ds[k] = (v || "").toString(); } function initProductPage() { const init = () => { var _a, _b; const title = null === (_a = document.querySelector("[data-widget='webProductHeading']")) || void 0 === _a ? void 0 : _a.textContent; if (!title) return; let price = getPrice("[data-widget='webOzonAccountPrice']"); if (!price) price = getPrice("[data-widget='webPrice']"); if (price) { const parsedTitle = parseTitleWithPrice(title, price); null === (_b = document.querySelector("[data-widget='webPrice']")) || void 0 === _b ? void 0 : _b.appendChild(renderBestPrice(parsedTitle)); } }; waitCompletePage((() => { init(); })); } function processProductCard(cardEl) { const wrapEl = getElementByXpath("a/following-sibling::div[1]", cardEl); if (!wrapEl || (null === wrapEl || void 0 === wrapEl ? void 0 : wrapEl.querySelector(".GM-best-price"))) { storeParsedTitleToElement(cardEl, null); return; } const price = getPriceFromElement(wrapEl.querySelector("div")); const titleEl = wrapEl.querySelector("a span.tsBodyL, " + "a span.tsBodyM:not([style]), " + 'a span.tsBodyM[style="color:;"]'); const title = null === titleEl || void 0 === titleEl ? void 0 : titleEl.textContent; if (!title || !price) { storeParsedTitleToElement(cardEl, null); return; } console.log(title, price); const parsedTitle = parseTitleWithPrice(title, price); null === titleEl || void 0 === titleEl ? void 0 : titleEl.before(renderBestPrice(parsedTitle)); storeParsedTitleToElement(cardEl, parsedTitle); } function initCatalog() { const init = () => { const catalogEl = document.querySelector(".widget-search-result-container > div"); if (null === catalogEl || void 0 === catalogEl ? void 0 : catalogEl.querySelector("." + BEST_PRICE_WRAP_CLASS_NAME)) return; const cardList = document.querySelectorAll(".widget-search-result-container > div > div" + ",[data-widget='skuLine'] > div:nth-child(2) > div" + ",[data-widget='skuLine'] > div:nth-child(1) > div" + ",[data-widget='skuLineLR'] > div:nth-child(2) > div" + ",[data-widget='skuGrid'][style] > div:nth-child(2) > div" + ",[data-widget='skuGrid']:not([style]) > div:nth-child(1) > div" + ",[data-widget='skuShelfGoods'] > div:nth-child(2) > div > div > div > div"); for (const cardEl of cardList) processProductCard(cardEl); const buttonWrapEl = document.querySelector('[data-widget="searchResultsSort"]'); if (catalogEl) { const el = catalogEl.querySelector(":scope > div"); const isDetailCatalog = el && "span 12" === getComputedStyle(el).gridColumnStart; if (isDetailCatalog) console.warn("is detail catalog, reorder disabled"); else buttonWrapEl && initReorderCatalog(catalogEl, buttonWrapEl); const paginator = document.querySelector('[data-widget="megaPaginator"] > div:nth-child(2)'); const paginatorWrap = document.querySelector(".widget-search-result-container"); if (null === paginator || void 0 === paginator ? void 0 : paginator.querySelector("a")) paginatorWrap && copyElementToNewRoot(paginator, paginatorWrap, { pos: "before" }); } }; waitCompletePage((() => { init(); }), { runOnce: false }); } (function() { "use strict"; if (!matchLocation("^https://(www\\.|)ozon\\.ru/.*")) return; console.log("OZON.ru"); if (matchLocation("^https://(www\\.|)ozon\\.ru/product/.*")) initProductPage(); if (matchLocation("^https://(www\\.|)ozon\\.ru/")) initCatalog(); if (matchLocation("^https://(www\\.|)ozon\\.ru/(category|highlight|search|my|product|brand)/.*")) initCatalog(); })(); function lenta_com_initProductPage() { const init = () => { var _a, _b, _c; const title = null === (_b = null === (_a = document.querySelector(".sku-page__title")) || void 0 === _a ? void 0 : _a.textContent) || void 0 === _b ? void 0 : _b.trim(); let price = getPrice(".sku-price--primary"); if (!price || !title) return; price /= 100; console.log(title, price); const parsedTitle = parseTitleWithPrice(title, price); null === (_c = document.querySelector(".sku-prices-block")) || void 0 === _c ? void 0 : _c.after(renderBestPrice(parsedTitle)); }; waitCompletePage((() => { init(); })); } function lenta_com_processProductCard(cardEl) { var _a, _b, _c; if (cardEl.classList.contains(BEST_PRICE_WRAP_CLASS_NAME)) return; let price = getPriceFromElement(cardEl.querySelector(".price-label--primary")); const title = null === (_b = null === (_a = cardEl.querySelector(".sku-card-small-header__title")) || void 0 === _a ? void 0 : _a.textContent) || void 0 === _b ? void 0 : _b.trim(); if (!title || !price) { storeParsedTitleToElement(cardEl, null); return; } price /= 100; console.log(title, price); const parsedTitle = parseTitleWithPrice(title, price); null === (_c = cardEl.querySelector(".sku-card-small-prices ")) || void 0 === _c ? void 0 : _c.after(renderBestPrice(parsedTitle)); storeParsedTitleToElement(cardEl, parsedTitle); } function lenta_com_initCatalog() { const init = () => { const cardList = document.querySelectorAll(".sku-card-small"); for (const cardEl of cardList) lenta_com_processProductCard(cardEl); const catalogWrapEl = document.querySelector(".catalog-grid__grid"); const buttonWrapEl = ElementGetOrCreate(document.querySelector(".catalog-sorting"), { pos: "before" }); if (catalogWrapEl && buttonWrapEl) initReorderCatalog(catalogWrapEl, buttonWrapEl); const catalogEl = document.querySelector(".catalog-view__main"); const paginationRootWrap = ElementGetOrCreate(catalogEl, { pos: "before", className: "GM-pagination-clone" }); paginationRootWrap && copyElementToNewRoot(null === catalogEl || void 0 === catalogEl ? void 0 : catalogEl.querySelectorAll(".pagination"), paginationRootWrap); waitCompletePage((() => { init(); }), { root: document.querySelector(".catalog-view__grid-container") }); }; waitCompletePage((() => { init(); })); } (function() { "use strict"; if (!matchLocation("^https://lenta\\.com/.*")) return; if (matchLocation("^https://lenta\\.com/product/.*")) lenta_com_initProductPage(); if (matchLocation("^https://lenta\\.com/(catalog|search|brand)/.*")) lenta_com_initCatalog(); })(); function okeydostavka_ru_initProductPage() { const init = () => { var _a, _b, _c, _d; const productWrapEl = document.querySelector(".product_main_info"); if (!productWrapEl) return; const title = null === (_b = null === (_a = null === productWrapEl || void 0 === productWrapEl ? void 0 : productWrapEl.querySelector("h1.main_header")) || void 0 === _a ? void 0 : _a.textContent) || void 0 === _b ? void 0 : _b.trim(); const price = parseFloat((null === (_c = null === productWrapEl || void 0 === productWrapEl ? void 0 : productWrapEl.querySelector('.product-price > meta[itemprop="price"]')) || void 0 === _c ? void 0 : _c.content) || ""); if (!price || !title) return; console.log(title, price); const parsedTitle = parseTitleWithPrice(title, price); null === (_d = null === productWrapEl || void 0 === productWrapEl ? void 0 : productWrapEl.querySelector(".product-price")) || void 0 === _d ? void 0 : _d.after(renderBestPrice(parsedTitle)); }; waitCompletePage((() => { init(); })); } function okeydostavka_ru_processProductCard(cardEl) { var _a, _b; if (cardEl.classList.contains(BEST_PRICE_WRAP_CLASS_NAME)) return; const priceEl = null === cardEl || void 0 === cardEl ? void 0 : cardEl.querySelector(".price_and_cart .product-price"); const price = getPriceFromElement(null === priceEl || void 0 === priceEl ? void 0 : priceEl.querySelector(":scope > span.price")); const title = null === (_b = null === (_a = cardEl.querySelector(".product-name a")) || void 0 === _a ? void 0 : _a.getAttribute("title")) || void 0 === _b ? void 0 : _b.trim(); if (!title || !price) { storeParsedTitleToElement(cardEl, null); return; } console.log(title, price); const parsedTitle = parseTitleWithPrice(title, price); null === priceEl || void 0 === priceEl ? void 0 : priceEl.after(renderBestPrice(parsedTitle)); storeParsedTitleToElement(cardEl, parsedTitle); } function okeydostavka_ru_initCatalog() { const init = () => { const cardList = document.querySelectorAll(".product_listing_container li" + ", .also-products li > div.product" + ", .similar-products li > div.product" + ", .catalogEntryRecommendationWidget li > div.product"); for (const cardEl of cardList) okeydostavka_ru_processProductCard(cardEl); const catalogWrapEl = document.querySelector(".product_listing_container > ul"); const buttonWrapEl = ElementGetOrCreate(catalogWrapEl, { pos: "before" }); if (catalogWrapEl && buttonWrapEl) initReorderCatalog(catalogWrapEl, buttonWrapEl); waitCompletePage((() => { init(); })); }; waitCompletePage((() => { init(); })); } (function() { "use strict"; if (!matchLocation("^https://(www\\.|)okeydostavka.ru/.*")) return; if (document.querySelector(".product_main_info")) okeydostavka_ru_initProductPage(); okeydostavka_ru_initCatalog(); })(); function auchan_ru_initProductPage() { const init = () => { var _a, _b, _c; if (document.querySelector("main .GM-best-price")) return; const title = null === (_b = null === (_a = document.querySelector("main h1#productName")) || void 0 === _a ? void 0 : _a.textContent) || void 0 === _b ? void 0 : _b.trim(); const price = getPrice("main .fullPricePDP"); if (!price || !title) return; console.log(title, price); const parsedTitle = parseTitleWithPrice(title, price); null === (_c = document.querySelector("main .fullPricePDP")) || void 0 === _c ? void 0 : _c.after(renderBestPrice(parsedTitle)); }; init(); } function auchan_ru_processProductCard(cardEl, priceSel, titleSel, renderPriceSel) { var _a, _b, _c; if (cardEl.classList.contains(BEST_PRICE_WRAP_CLASS_NAME)) return; const price = getPriceFromElement(cardEl.querySelector(priceSel)); const title = null === (_b = null === (_a = cardEl.querySelector(titleSel)) || void 0 === _a ? void 0 : _a.textContent) || void 0 === _b ? void 0 : _b.trim(); if (!title || !price) { storeParsedTitleToElement(cardEl, null); return; } console.log(title, price); const parsedTitle = parseTitleWithPrice(title, price); null === (_c = cardEl.querySelector(renderPriceSel)) || void 0 === _c ? void 0 : _c.after(renderBestPrice(parsedTitle)); storeParsedTitleToElement(cardEl, parsedTitle); } function auchan_ru_initCatalog() { const init = () => { const cardList = document.querySelectorAll("article.productCard"); for (const cardEl of cardList) auchan_ru_processProductCard(cardEl, ".productCardPriceData > div", ".linkToPDP", ".productCardPriceData "); const catalogWrapEl = getElementByXpath('//article[contains(@class,"productCard")]/ancestor::main//article/../..'); if (!document.querySelector(".GM-wrap")) { const buttonWrapEl = ElementGetOrCreate(document.querySelector("#categoriesThirdLvlList"), { pos: "after" }); if (catalogWrapEl && buttonWrapEl) initReorderCatalog(catalogWrapEl, buttonWrapEl); } const catalogEl = document.querySelector(".catalog-view__main"); const paginationRootWrap = ElementGetOrCreate(catalogEl, { pos: "before", className: "GM-pagination-clone" }); paginationRootWrap && copyElementToNewRoot(null === catalogEl || void 0 === catalogEl ? void 0 : catalogEl.querySelectorAll(".pagination"), paginationRootWrap); }; init(); } function initSearchResults() { const cardList = document.querySelectorAll(".digi-product"); for (const cardEl of cardList) auchan_ru_processProductCard(cardEl, ".digi-product-price-variant_actual", ".digi-product__label", ".price-and-cart"); const catalogWrapEl = document.querySelector(".digi-products-grid"); if (!document.querySelector(".digi-search .GM-wrap")) { const buttonWrapEl = ElementGetOrCreate(document.querySelector(".digi-main-results-actions"), { pos: "after" }); if (catalogWrapEl && buttonWrapEl) initReorderCatalog(catalogWrapEl, buttonWrapEl); } } (function() { "use strict"; if (!matchLocation("^https://(www\\.|)auchan\\.ru/.*")) return; waitCompletePage((() => { if (document.querySelector("#productName")) auchan_ru_initProductPage(); else if (document.querySelector(".digi-products")) initSearchResults(); else auchan_ru_initCatalog(); }), { runOnce: false }); })(); function common_parser_processProductCard(cardEl, options) { var _a, _b, _c; const {price_sel: price_sel, title_sel: title_sel, to_render: to_render} = options; if (cardEl.classList.contains(BEST_PRICE_WRAP_CLASS_NAME)) return; const price = getPrice(price_sel, cardEl); const title = null === (_b = null === (_a = cardEl.querySelector(title_sel)) || void 0 === _a ? void 0 : _a.textContent) || void 0 === _b ? void 0 : _b.trim(); if (!title || !price) { console.warn("Not found price or title", title, price, cardEl); storeParsedTitleToElement(cardEl, null); return; } console.debug(title, price); const parsedTitle = parseTitleWithPrice(title, price); const renderedPrice = renderBestPrice(parsedTitle); let to_render_sel = ""; let to_render_pos = "after"; if ("string" === typeof to_render) to_render_sel = to_render; else { to_render_sel = to_render.sel; to_render_pos = to_render.pos || to_render_pos; } const to_render_el = cardEl.querySelector(to_render_sel); null === (_c = null === to_render_el || void 0 === to_render_el ? void 0 : to_render_el.parentElement) || void 0 === _c ? void 0 : _c.querySelectorAll("." + BEST_PRICE_CLASS_NAME).forEach((e => e.remove())); null === to_render_el || void 0 === to_render_el ? void 0 : to_render_el[to_render_pos](renderedPrice); storeParsedTitleToElement(cardEl, parsedTitle); } function perekrestok_ru_initProductPage() { var _a; const productRoot = document.querySelector("main"); if (!productRoot) return; const productId = null === (_a = productRoot.querySelector('[itemprop="sku"]')) || void 0 === _a ? void 0 : _a.getAttribute("content"); if (productId && productRoot.dataset.productId !== productId) { productRoot.classList.remove(BEST_PRICE_WRAP_CLASS_NAME); productRoot.dataset.productId = productId; } common_parser_processProductCard(productRoot, { price_sel: "div.price-new", title_sel: "h1.product__title", to_render: { sel: "div.price-new", pos: "after" } }); } function perekrestok_ru_initCatalog() { const cardList = document.querySelectorAll(".product-card-wrapper" + ", .swiper-slide"); for (const cardEl of cardList) common_parser_processProductCard(cardEl, { price_sel: "div.price-new", title_sel: "span.product-card__link-text", to_render: "div.product-card__control" }); for (const group of document.querySelectorAll(".catalog-content-group__list > div > div")) { const buttonWrapEl = ElementGetOrCreate(group.parentElement, { pos: "before" }); if (buttonWrapEl) initReorderCatalog(group, buttonWrapEl); } } (function() { "use strict"; const prefix = "https://(www\\.|)perekrestok\\.ru"; if (!matchLocation(prefix)) return; waitCompletePage((() => { if (matchLocation(prefix + "/cat/\\d+/p/")) perekrestok_ru_initProductPage(); perekrestok_ru_initCatalog(); }), { runOnce: false, delay: 200 }); })(); })();