Skip to content

Instantly share code, notes, and snippets.

@KarpenkoY
Last active May 21, 2025 20:07
Show Gist options
  • Save KarpenkoY/745833cb35b6e3e1bbd2f0b3327fd1f8 to your computer and use it in GitHub Desktop.
Save KarpenkoY/745833cb35b6e3e1bbd2f0b3327fd1f8 to your computer and use it in GitHub Desktop.
Sort products by price on cactuskiev.com.ua
// ==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