Last active
May 21, 2025 20:07
-
-
Save KarpenkoY/745833cb35b6e3e1bbd2f0b3327fd1f8 to your computer and use it in GitHub Desktop.
Sort products by price on cactuskiev.com.ua
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Sort Products by Price - CactusKiev | |
// @namespace http://tampermonkey.net/ | |
// @version 0.2 | |
// @description Sort products by price on cactuskiev.com.ua (context is only current page) | |
// @author Yaroslav Karpenko | |
// @match https://www.cactuskiev.com.ua/* | |
// @grant none | |
// @updateURL https://gist.githubusercontent.com/KarpenkoY/745833cb35b6e3e1bbd2f0b3327fd1f8/raw/sort-products-by-price.user.js | |
// @downloadURL https://gist.githubusercontent.com/KarpenkoY/745833cb35b6e3e1bbd2f0b3327fd1f8/raw/sort-products-by-price.user.js | |
// ==/UserScript== | |
(function () { | |
"use strict"; | |
function parsePrice(text) { | |
const match = text.match(/[\d,.]+/); | |
return match | |
? parseFloat(match[0].replace(",", "")) | |
: Number.POSITIVE_INFINITY; | |
} | |
function extractPrice(product) { | |
const ins = product.querySelector("ins bdi"); | |
if (ins) { | |
return parsePrice(ins.textContent.trim()); | |
} | |
const firstBdi = product.querySelector("bdi"); | |
return firstBdi | |
? parsePrice(firstBdi.textContent.trim()) | |
: Number.POSITIVE_INFINITY; | |
} | |
function removeOldPrices(product) { | |
// Remove old prices in <del> | |
const oldPrice = product.querySelector("del"); | |
if (oldPrice) { | |
oldPrice.remove(); | |
} | |
// Also remove screen-reader texts like "Оригінальна ціна", etc. | |
const screenReaderTexts = product.querySelectorAll(".screen-reader-text"); | |
screenReaderTexts.forEach((el) => el.remove()); | |
} | |
function sortAndCleanProducts(order = "asc") { | |
const container = document.querySelector(".products.list"); | |
if (!container) return; | |
const productDivs = Array.from(container.querySelectorAll(".product")); | |
const productsWithPrices = productDivs.map((product) => { | |
removeOldPrices(product); // remove <del> and redundant price info | |
return { | |
element: product, | |
price: extractPrice(product), | |
}; | |
}); | |
productsWithPrices.sort((a, b) => | |
order === "asc" ? a.price - b.price : b.price - a.price, | |
); | |
// Clear and re-append in sorted order | |
productDivs.forEach((el) => el.remove()); | |
productsWithPrices.forEach(({ element }) => container.appendChild(element)); | |
} | |
function handleSortingIfApplicable() { | |
const orderby = document.querySelector("select.orderby"); | |
if (!orderby) return; | |
const value = orderby.value; | |
if (value === "price") { | |
sortAndCleanProducts("asc"); | |
} else if (value === "price-desc") { | |
sortAndCleanProducts("desc"); | |
} | |
} | |
function setupDropdownListener() { | |
const orderby = document.querySelector("select.orderby"); | |
if (!orderby) return; | |
handleSortingIfApplicable(); | |
orderby.addEventListener("change", () => { | |
setTimeout(() => { | |
handleSortingIfApplicable(); | |
}, 100); | |
}); | |
} | |
const waitForDropdown = new MutationObserver((mutations, obs) => { | |
if (document.querySelector("select.orderby")) { | |
setupDropdownListener(); | |
obs.disconnect(); | |
} | |
}); | |
waitForDropdown.observe(document.body, { childList: true, subtree: true }); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment