SublimePotato / Amazon Germany Discount Filter

// ==UserScript==
// @name       Amazon Germany Discount Filter
// @version    0.51
// @description  Provides a Discount Filter for Amazon.de (may be working for other countries as well)
// @match https://www.amazon.de/*
// @copyright  2017+
// @icon http://www.amazon.com/favicon.ico
// @updateURL     https://openuserjs.org/meta/SublimePotato/Amazon_Germany_Discount_Filter.meta.js
// @downloadURL     https://openuserjs.org/install/SublimePotato/Amazon_Germany_Discount_Filter.user.js
// @grant none
// @license MIT
// ==/UserScript==

(function () {
    var constants = {
        // qsKey: 'pct-off', // after an update it seems only the decoded querystring parameter is compatible
        qsKey: "p_75",
        qsKeyDecoded: "p_75",
        anchorSelector: "#s-refinements",
        detailViewAnchorSelector: "#productTitle",
    };

    var template = {
        ui:
            '<div class="tmper_amazon_discount_container">' +
            "<h2>Discount</h2>" +
            '<ul class="a-unordered-list a-nostyle a-vertical a-spacing-medium">' +
            '<li class="a-spacing-micro">' +
            '<a href="javascript:void(0)" data-discountReset="1">Zurücksetzen</a>' +
            "</li>" +
            '<li class="a-spacing-micro">' +
            '<a href="javascript:void(0)" data-discountMin="0" data-discountMax="20"></a>' +
            "</li>" +
            '<li class="a-spacing-micro">' +
            '<a href="javascript:void(0)" data-discountMin="20" data-discountMax="40"></a>' +
            "</li>" +
            '<li class="a-spacing-micro">' +
            '<a href="javascript:void(0)" data-discountMin="40" data-discountMax="60"></a>' +
            "</li>" +
            '<li class="a-spacing-micro">' +
            '<a href="javascript:void(0)" data-discountMin="60" data-discountMax="80"></a>' +
            "</li>" +
            '<li class="a-spacing-micro">' +
            '<a href="javascript:void(0)" data-discountMin="80" data-discountMax="100"></a>' +
            "</li>" +
            '<li class="a-spacing-micro">' +
            '<input class="tmper_amazon_discount_min" placeholder="Min" type="number" min="0" max="100" style="width:55px;" />' +
            "<span> - </span>" +
            '<input class="tmper_amazon_discount_max" placeholder="Max" type="number" min="0" max="100" style="width:55px;" />' +
            "<span>   </span>" +
            '<button style="margin-left: 5px; height: 31px; width: 50px;">Filter</button>' +
            "</li>" +
            "</ul>" +
            "</div>",
    };

    var queryStringUtil = {
        get: function () {
            var min, max;
            if (location.search.indexOf(constants.qsKey + "=") !== -1) {
                var qsVals = location.search
                    .split(constants.qsKey + "=")[1]
                    .split("&")[0]
                    .split("-");
                min = qsVals[0];
                max = qsVals[1];
            } else if (
                location.search.indexOf(constants.qsKeyDecoded + "%3A") !== -1
            ) {
                var decodedQsVals = location.search
                    .split(constants.qsKeyDecoded + "%3A")[1]
                    .split("&")[0]
                    .split("-");
                min = decodedQsVals[0];
                max = decodedQsVals[1];
            }

            return {
                min: min || 0,
                max: max || 100,
            };
        },
        set: function (min, max) {
            var uri = location.search;
            var value = min + "-" + max;
            var re = new RegExp(`${constants.qsKeyDecoded}%3A.+?(&|$)`, "i");
            var separator = uri.indexOf("?") !== -1 ? "&" : "?";
            if (uri.match(re)) {
                uri = uri.replace(re, "");
            }
            location.search = uri + separator + constants.qsKey + "=" + value;
        },
        remove: function () {
            var uri = location.search;
            var re = new RegExp(`${constants.qsKeyDecoded}%3A.+?(&|$)`, "i");
            if (uri.match(re)) {
                location.search = uri.replace(re, "");
            }
        },
    };

    var navigateToDetailPage = function () {
        var idAndParams = location.href.split("dp")[1];
        var url =
            location.protocol +
            "//" +
            location.hostname +
            "/gp/offer-listing" +
            idAndParams;
        location.href = url;
    };


    var appendControls = function (container, currentValue) {
        container.innerHTML = template.ui;
        var minInput = container.querySelector(".tmper_amazon_discount_min");
        var maxInput = container.querySelector(".tmper_amazon_discount_max");
        var btn = container.querySelector("button");
        var discountLinks = container.querySelectorAll("a");

        var appendFilter = () => {
            minInput.value =
                parseInt(minInput.value) > parseInt(maxInput.value)
                    ? 0
                    : minInput.value;
            maxInput.value =
                maxInput.value === minInput.value
                    ? maxInput.value + 10
                    : maxInput.value;
            queryStringUtil.set(minInput.value, maxInput.value);
        };

        minInput.value = currentValue.min;
        maxInput.value = currentValue.max;

        minInput.addEventListener("blur", function () {
            minInput.value = parseInt(minInput.value) > 100 ? 100 : minInput.value;
            minInput.value = parseInt(minInput.value) < 0 ? 0 : minInput.value;
        });

        maxInput.addEventListener("blur", function () {
            maxInput.value = parseInt(maxInput.value) > 100 ? 100 : maxInput.value;
            maxInput.value = parseInt(maxInput.value) < 0 ? 0 : maxInput.value;
        });

        minInput.addEventListener("keypress", (e) => e.key === 'Enter' && appendFilter());
        maxInput.addEventListener("keypress", (e) => e.key === 'Enter' && appendFilter());


        btn.addEventListener("click", appendFilter);

        for (var i = 0; i < discountLinks.length; i++) {
            (function () {
                var link = discountLinks[i];
                var isReset = link.getAttribute("data-discountReset");
                if (isReset) {
                    link.addEventListener("click", function () {
                        queryStringUtil.remove();
                    });
                    return;
                }

                var min = link.getAttribute("data-discountMin");
                var max = link.getAttribute("data-discountMax");
                link.innerHTML = min + "% - " + max + "%";
                if (min === currentValue.min && max === currentValue.max) {
                    link.style.fontWeight = "bold";
                } else {
                    link.addEventListener("click", function () {
                        queryStringUtil.set(min, max);
                    });
                }
            })();
        }
    };

    var tryAddControls = function () {
        var anchor = document.querySelector(constants.anchorSelector);
        if (anchor) {
            var currentDiscountControls = document.querySelector(
                ".tmper_amazon_discount_container"
            );
            if (!currentDiscountControls) {
                var container = document.createElement("div");
                var currentData = queryStringUtil.get();
                appendControls(container, currentData);
                anchor.insertBefore(container, anchor.firstChild);
            }
        }

        var detailViewAnchor = document.querySelector(
            constants.detailViewAnchorSelector
        );
        if (detailViewAnchor) {
            var currentDetailViewControl = document.querySelector(
                ".tmper_amazon_detailview_container"
            );
            if (!currentDetailViewControl) {
                var detailViewContainer = getDetailViewControl();
                detailViewAnchor.parentNode.insertBefore(detailViewContainer, anchor);
            }
        }
    };

    var getDetailViewControl = function (container) {
        var elem = document.createElement("button");
        elem.innerHTML = "Detailansicht";
        elem.style.fontSize = "10px";
        elem.className += "tmper_amazon_detailview_container";
        elem.addEventListener("click", navigateToDetailPage);
        return elem;
    };

    var watchdog = function () {
        var watch;
        var main = document.getElementById("a-page");
        if (main) {
            main.addEventListener("DOMSubtreeModified", function () {
                if (watch) {
                    clearTimeout(watch);
                }
                watch = setTimeout(tryAddControls, 100);
            });
        }
    };

    var init = function () {
        watchdog();
        tryAddControls();
    };

    init();
})();