Greasy Fork

Greasy Fork is available in English.

Ozon, Wildberries and Simaland customizer: bad reviews first + interface improvements

Ozon, Wildberries and Simaland: sorting reviews by product by ascending rating

目前为 2024-10-02 提交的版本,查看 最新版本

// ==UserScript==
// @name         Ozon, Wildberries and Simaland customizer: bad reviews first + interface improvements
// @name:ru      Ozon, Wildberries и Simaland настройка: сначала плохие отзывы + улучшения интерфейса
// @namespace    http://tampermonkey.net/
// @version      2024-10-02_16-13
// @description  Ozon, Wildberries and Simaland: sorting reviews by product by ascending rating
// @description:ru  Ozon, Wildberries и Simaland: сортировка отзывов по товару по возрастанию рейтинга
// @author       Igor Lebedev
// @license        GPL-3.0-or-later
// @icon         https://raw.githubusercontent.com/LebedevIV/Ozon-Wildberries-Simaland-customizer/main/icons/logo_color.svg
// @match          http://*.ozon.ru/*
// @match          https://*.ozon.ru/*
// @match          http://*.ozon.com/*
// @match          https://*.ozon.com/*
// @match          http://*.wildberries.ru/*
// @match          https://*.wildberries.ru/*
// @match          http://*.sima-land.ru/*
// @match          https://*.sima-land.ru/*
// ==/UserScript==


(() => {
    'use strict'

    // получаем текущий адрес страницы
    const currentURL = window.location.href
    const config = {
        // advanced: false,
        SettingsOnOff: true,
        isRunningAsExtension: false,
    };
    let api

    // определение среды выполнения скрипта: как пользовательский или в составе расширения
    function isRunningAsExtension() {
        const isChromeExtension = typeof chrome !== 'undefined' && chrome.runtime && typeof chrome.runtime.id !== 'undefined';
        const isBrowserExtension = typeof browser !== 'undefined' && browser.runtime && typeof browser.runtime.id !== 'undefined';

        const currentScript = document.currentScript;
        const isInlineScript = currentScript && currentScript.src && currentScript.src.startsWith('chrome-extension://');

        return isChromeExtension || isBrowserExtension || isInlineScript;
    }

    if (isRunningAsExtension()) {
        // console.log('Script is running as a browser extension.');
        config.isRunningAsExtension = true
    } else {
        // console.log('Script is running independently.');
        config.isRunningAsExtension = false
    }

    // опредлеение типа браузера
    function getBrowser() {
        if (typeof chrome !== "undefined" && typeof chrome.runtime !== "undefined") {
            return chrome
        } else if (
            typeof browser !== "undefined" &&
            typeof browser.runtime !== "undefined"
        ) {
            return browser
        }
        else {
            console.log("browser is not supported");
            return false
        }
    }

    if (config.isRunningAsExtension === true) api = getBrowser()


    // Ozon: Функция для добавления к ссылкам на страницах каталогов параметра сортировки рейтинга по возрастанию - на случай если пользователь будет вручную открывать ссылки с карточкой товара в новой вкладке
    // Так же добавление ссылок на отзывы для блоков рейтингов (звёздочек)
    function addOzonSortParamToLinks() {
        if (config.SettingsOnOff) {
            const links = document.querySelectorAll('a[href^="/product/"]:not([href*="&sort=score_asc"])');
            links.forEach(link => {
                const linkOrig = link.href
                link.href += '&sort=score_asc';
                // Проверяем, является ли родительский элемент (parentNode) div с классом 'iy6'
                const link_parentNode = link.parentNode
                // Привязка к блоку рейтингов (звёздочек) ссылки на рейтинги
                // if(link_parentNode.tagName.toLowerCase() === 'div' && link_parentNode.classList.contains('iy6')) {
                if(link_parentNode.tagName.toLowerCase() === 'div') {

                    // Определение наличия вложенного элемента, содержащего рейтинги
                    const divStars = link_parentNode.querySelector('div.tsBodyMBold') || link_parentNode.querySelector('div.tsCaptionBold')
                    // + проверка что ссылка уже не была назначена ранее - почему-то происходит двойное срабатывание скрипта
                    if (divStars && divStars.parentNode.nodeName !== 'A') {
                        let url1Base = linkOrig.match(/(^[^\?]+)/g)[0];

                        // Создание нового узла <a>
                        let aNode = document.createElement('a');

                        // Установка параметров узла
                        aNode.href = `${url1Base}reviews?sort=score_asc`;
                        aNode.style.cssText = 'display: flex; width: 100%; height: 100%; cursor: pointer; text-decoration: none;';

                        // Получаем родительский элемент div
                        let parentNode = divStars.parentNode;

                        // Вставляем новый узел перед div1
                        parentNode.insertBefore(aNode, divStars);

                        // Перемещаем узел div внутрь aNode
                        aNode.appendChild(divStars);
                        divStars.style.cursor = 'pointer';

                    }
                }
            });
        }
    }

    // Wildberries: Ожидание загрузки страницы товара до появления элемента сортировки рейтинга и искусственное двойное нажатие этого элемента чтобы добиться сортировки рейтинга по возрастанию
    function sortWildberriesReviews() {
        const interval = setInterval(() => {
            // ожидание загрузки страницы до необходимого значения
            const preloader = document.querySelector('#app > div[data-link="visible{:router.showPreview}"]')
            if (preloader?.style.display === 'none') {
                const sortButton = document.querySelector("#app > div:nth-child(5) > div > section > div.product-feedbacks__main > div.user-activity__tab-content > div.product-feedbacks__sorting > ul > li:nth-child(2) > a");
                if (sortButton) {
                    clearInterval(interval);

                    // Инициируем событие на элементе
                    // Проверяет, содержит ли элемент класс 'sorting__selected'
                    if (sortButton.classList.contains('sorting__selected')) {
                        // Находим элемент <span> внутри найденного <a>
                        let span = sortButton.querySelector('span');
                        // Проверяем, содержит ли <span> класс 'sorting__decor--up'
                        // Если содержит, значит, сортировка по возрастанию уже произведена и никаких действий производить не нужно (всё равно приходится произвести два клика, так как, по-видимому, по мере загрузки происходит последующий сброс настроек) - надо отловить объект, который появляется уже после сброса, и зацепиться за него
                        if (span && span.classList.contains('sorting__decor--up')) {
                            // Первое нажатие производит сортировку по убыванию рейтинга
                            // sortButton.click();
                            // Второе нажатие производит сортировку по возрастанию рейтинга
                            // sortButton.click();
                        } else {
                            // Нажатие производит сортировку по возрастанию рейтинга
                            sortButton.click();
                        }
                    } else {
                        // Первое нажатие производит сортировку по убыванию рейтинга
                        sortButton.click();
                        // Второе нажатие производит сортировку по возрастанию рейтинга
                        sortButton.click();
                    }
                }
            }
        }, 50);
    }

    // Wildberries: добавление ссылок для блоков рейтингов (звёздочек)
    function addWildberriesSortParamToLinks() {
        if (config.SettingsOnOff) {

            // Функция для выполнения действий с новыми элементами
            function handleNewElement(element) {

                const interval_main_page__content = setInterval(() => {
                    // проверка загрузки блока с визитками товаров
                    const main_page__content = document.querySelector('div.main-page__content');
                    if (main_page__content) {
                        clearInterval(interval_main_page__content)
                        const rating_wraps = document.querySelectorAll('p.product-card__rating-wrap');
                        rating_wraps.forEach(rating_wrap => {
                            // ссылка на карточку товара
                            const outerLink = rating_wrap.parentNode.parentNode.querySelector('a')
                            // получение ссылки на отзывы
                            const linkReviews = outerLink.href.replace('/detail.aspx', '/feedbacks')


                            const rating_wrap_parentNode = rating_wrap.parentNode
                            // Привязка к блоку рейтингов (звёздочек) ссылки на рейтинги
                            if(rating_wrap_parentNode.tagName.toLowerCase() === 'div') {


                                // Создание нового узла <a>
                                let aNode = document.createElement('a');

                                // Установка параметров узла
                                aNode.href = linkReviews
                                aNode.style.cssText = 'display: flex; width: 100%; height: 100%; cursor: pointer; text-decoration: none; z-index: 4;'; // z-index: 4 - должен быть больше чем z-index у внешней ссылки для всей визитки (z-index: 3)

                                // Вставляем новый узел aNode перед rating_wrap
                                rating_wrap_parentNode.insertBefore(aNode, rating_wrap);

                                // Перемещаем узел rating_wrap внутрь aNode
                                aNode.appendChild(rating_wrap);

                                rating_wrap.style.cursor = 'pointer';

                            }
                        });
                    }
                });
            }

            // Настройка MutationObserver
            const observer = new MutationObserver((mutationsList) => {
                outerLoop: for (let mutation of mutationsList) {
                    // изменения всего блока визиток товаров
                    if (mutation.type === 'childList' && mutation.target.className === 'main-page__content-wrapper') {
                        // муткация где происходит вставка сразу всех нод - можно сразу выходит из цикла
                        for (let node of mutation.addedNodes) {
                            // if (node.nodeType === Node.ELEMENT_NODE && node.matches('p.product-card__rating-wrap')) {
                            if (node.nodeType === Node.ELEMENT_NODE) {
                                handleNewElement(node);
                                break outerLoop;
                            }
                        }
                    }
                }
            });

            // Указываем, за какими изменениями наблюдать
            observer.observe(document.body, {
                childList: true,       // Наблюдаем за добавлением/удалением детей
                subtree: true         // Также отслеживаем все поддеревья
            });

        }
    }



    // Simaland: Ожидание фрейма с отзывами и его обработка
    function clickLinkReviews() {
        const interval2 = setInterval(() => {
            // отключаем динамический выезд (пока не получается)
            // const frameWithReviews = document.querySelector("#product__root > div > div.Fa76rh > div.iOZqnu > div:nth-child(2) > div > div.dfZ2S8")
            // if (frameWithReviews) {
            // frameWithReviews.style.transition = 'transform 0s';
            // }
            // ожидание дозагрузки страницы до появления ссылки открытия списка сортировки
            // const divGpksVe = document.querySelector("#product__root > div > div.Fa76rh > div.iOZqnu > div:nth-child(2) > div.GpksVe")
            // if (divGpksVe)
            // divGpksVe.style.setProperty("--transition-duration", "0ms");
            const sortButton =
                  document.querySelector('a[role="button"][data-testid="sort"]') ||
                  document.querySelector("button.vuz3sk");
            if (sortButton) {
                clearInterval(interval2);

                if (config.SettingsOnOff) {
                    // проверка что список уже не раскрыт (Сайт Сималенд этот список может раскрывать заранее)
                    const sortButtonSortingPoint =
                          document.querySelector('div[data-overlayscrollbars-viewport="scrollbarHidden overflowXHidden overflowYHidden"] > div:nth-child(4)')
                    document.querySelector('div[data-overlayscrollbars-viewport="scrollbarHidden overflowXHidden overflowYHidden"] > div > div > button:nth-child(4)');
                    if (sortButtonSortingPoint) {
                        sortButtonSortingPoint.click();
                    } else {
                        const programmaticClickEvent = new CustomEvent('customClick', { detail: { isProgrammatic: true } });
                        sortButton?.addEventListener('customClick', (event) => {
                            if (event.detail && event.detail.isProgrammatic) {
                                sortButton.click();
                                const interval3 = setInterval(() => {
                                    // ожидание дозагрузки страницы до раскрытия списка сортировки ипоявления пункта сортировки по возрастанию рейтинга
                                    const sortButtonSortingPoint =
                                          document.querySelector('div[data-overlayscrollbars-viewport="scrollbarHidden overflowXHidden overflowYHidden"] > div:nth-child(4)') ||
                                          document.querySelector('div[data-overlayscrollbars-viewport="scrollbarHidden overflowXHidden overflowYHidden"] > div > div > button:nth-child(4)');
                                    if (sortButtonSortingPoint) {
                                        clearInterval(interval3);
                                        if (config.SettingsOnOff) {
                                            sortButtonSortingPoint.click();
                                        }
                                    }
                                }, 50);
                            } else {
                                // console.log('Button was clicked manually.');
                            }

                        });
                        sortButton.dispatchEvent(programmaticClickEvent);
                    }
                }
            }
        }, 50);
    }

    // Simaland: Ожидание загрузки страницы товара до появления элемента сортировки рейтинга и искусственное нажатие этого элемента чтобы добиться сортировки рейтинга по возрастанию
    function sortSimaLandReviews() {
        const interval = setInterval(() => {
            // ожидание загрузки страницы до появления ссылки на отзывы: соответствено для десктопной или мобильной версии
            const aReviews =
                  document.querySelector("#product__root > div > div.Fa76rh > div:nth-child(1) > div > div > div.hb20Nd > div.bcg7Pf > div > div > div.RB0Z2S.vZiVTa > a") ||
                  document.querySelector("button[data-testid='reviews-button']");

            if (aReviews) {
                clearInterval(interval);
                // если ссылка активна (когда отзывы есть в случае десктопной версии) или счётчик отзывов > 0 (в случае мобильной версии)
                if ((aReviews.tagName === 'A' && aReviews.getAttribute('tabindex') === "0" && !aReviews.classList.contains('HuzmFE'))
                    || (aReviews.tagName === 'BUTTON' && Number(aReviews.querySelector('.WKsLn3 >span.HrbHuT')?.innerText) > 0)
                   ) {
                    aReviews?.addEventListener('click', (event) => {
                        clickLinkReviews()
                    });
                }
            }
        }, 50);
        // Ссылка на отзывы внизу страницы Все отзывы - появляется только при прокрутке вниз и более не исчезает
        const intervalAllReviewsBottom = setInterval(() => {
            // ожидание загрузки страницы до появления ссылки на отзывы: второй элемент из-за влияния подгружаемого блока (в дальнейшем найти более надёжную привязку)
            const AllReviewsBottom =
                  document.querySelector("#product__root > div > div.Fa76rh > div:nth-child(2) > div > div:nth-child(5) > div > div.D5cu9p > div.M0Dw8o > a") ||
                  document.querySelector("#product__root > div > div.Fa76rh > div:nth-child(2) > div > div:nth-child(6) > div > div.D5cu9p > div.M0Dw8o > a")
            if (AllReviewsBottom) {
                clearInterval(intervalAllReviewsBottom);
                // если ссылка активна (когда отзывы есть в случае десктопной версии) или счётчик отзывов > 0 (в случае мобильной версии)
                if (AllReviewsBottom.tagName === 'A' && AllReviewsBottom.getAttribute('tabindex') === "0" && AllReviewsBottom.role === 'button') {
                    AllReviewsBottom.addEventListener('click', (event) => {
                        clickLinkReviews()
                    });
                }
            }
        }, 50);

        SimaLandAllReviewsPanelTop()

    }

    // Ссылка на отзывы на панели вверху страницы - появляется только при прокрутке вниз и исчезает при прокрутке вверх
    function SimaLandAllReviewsPanelTop() {
        // Выбираем элемент, внутри которого будем отслеживать изменения
        const targetNode = document.body;

        // Опции для обсерватора (какие именно изменения нужно отслеживать)
        const configObserver = {
            childList: true,
            subtree: true
        };
        // Функция-коллбэк, которая будет вызвана при изменениях
        const callback = function(mutationsList, observer) {
            for (let mutation of mutationsList) {
                // Если произошло добавление узла
                if (mutation.type === 'childList') {
                    mutation.addedNodes.forEach(node => {
                        if (node.nodeType === Node.ELEMENT_NODE && node.matches('div.M4Ud_g')) {
                            // console.log('Элемент <a role="button"> появился на странице:', node);
                            const AllReviewsPanelTop = document.querySelector("#product__root > div > div.M4Ud_g > div > div > div > div.xx8J2G > div > div.pQ3PLI > a:nth-child(2)")
                            if (AllReviewsPanelTop) {
                                // если ссылка активна (когда отзывы есть в случае десктопной версии) или счётчик отзывов > 0 (в случае мобильной версии)
                                if (AllReviewsPanelTop.tagName === 'A' && AllReviewsPanelTop.getAttribute('tabindex') === "0" && AllReviewsPanelTop.role === 'button') {
                                    AllReviewsPanelTop.addEventListener('click', (event) => {
                                        clickLinkReviews()
                                    });
                                }
                            }
                        }
                    });
                }
            }
        };

        // Создаем экземпляр обсерватора с указанием коллбэк-функции
        const observer = new MutationObserver(callback);

        // Начинаем наблюдение за целевым узлом с переданными опциями
        observer.observe(targetNode, configObserver);
    }

    // Simaland: страница карточки товара, вызванная из каталога при нажатии ссылки рейтинга
    // Simaland: Ожидание загрузки страницы товара до появления элемента рейтинга и искусственное нажатие этого элемента
    function SimaLandCatalogReviewsOpen() {
        function clickLinkReviews_appWrappers(){
            const interval_appWrappers = setInterval(() => {
                let appWrappers = document.querySelectorAll('[data-testid="app-wrapper"]');
                if (appWrappers) {
                    clearInterval(interval_appWrappers);
                    clickLinkReviews()
                }
            }, 50);
        }
        const interval = setInterval(() => {
            // отключение динамического выезда
            const frameWithReviews = document.querySelector("#product__root > div > div.Fa76rh > div.iOZqnu > div:nth-child(2) > div > div.dfZ2S8")
            if (frameWithReviews) {
                frameWithReviews.style.transition = 'transform 0s';
            }
            // ожидание загрузки страницы до появления ссылки на отзывы
            const aReviews =
                  document.querySelector("#product__root > div > div.Fa76rh > div:nth-child(1) > div > div > div.hb20Nd > div.bcg7Pf > div > div > div.RB0Z2S.vZiVTa > a") ||
                  document.querySelector("#product__root > div > div.k41rqL > div:nth-child(10) > button")
            if (aReviews) {
                clearInterval(interval);
                // если ссылка активна (когда отзывы есть в случае десктопной версии) или счётчик отзывов > 0 (в случае мобильной версии)
                if ((aReviews.tagName === 'A' && aReviews.getAttribute('tabindex') === "0" && !aReviews.classList.contains('HuzmFE'))
                    || (aReviews.tagName === 'BUTTON' && Number(aReviews.querySelector('.WKsLn3 >span.HrbHuT')?.innerText) > 0)
                   ) {
                    aReviews.addEventListener('click', (event) => {
                        clickLinkReviews_appWrappers()
                    });
                    if (config.SettingsOnOff) {
                        aReviews.click();
                    }
                }
            }
        }, 50);
        // Ссылка на отзывы внизу страницы Все отзывы - появляется только при прокрутке вниз и более не исчезает
        const intervalAllReviewsBottom = setInterval(() => {
            // ожидание загрузки страницы до появления ссылки на отзывы
            const AllReviewsBottom = document.querySelector("#product__root > div > div.Fa76rh > div:nth-child(2) > div > div:nth-child(5) > div > div.D5cu9p > div.M0Dw8o > a")
            if (AllReviewsBottom) {
                clearInterval(intervalAllReviewsBottom);
                // если ссылка активна (когда отзывы есть в случае десктопной версии) или счётчик отзывов > 0 (в случае мобильной версии)
                if (AllReviewsBottom.tagName === 'A' && AllReviewsBottom.getAttribute('tabindex') === "0" && AllReviewsBottom.role === 'button') {
                    AllReviewsBottom.addEventListener('click', (event) => {
                        clickLinkReviews_appWrappers()
                    });
                }
            }
        }, 50);
        SimaLandAllReviewsPanelTop()
        SimaLandOptimization()
    }

    // Sima-lend: Ожидание загружки страницы каталога привязка к рейтингам ссылок на страницы товара
    function SimaLandCatalogReviews() {
        // выбор всех Рейтинги на странице каталога: div с классом 'YREwlL'
        const interval = setInterval(() => {
            // ожидание загрузки страницы до появления ссылки на отзывы: десктопная и мобильная версии
            const aReviews =
                  // document.querySelector("#category-page__root > div > div.SvXTv3.pPpF_h.Go7gld.MoKdBA.ckfJXr.elXZ47 > div.WBjroC > div.YF_0Ly > div.R4UxqH > div") ||
                  document.querySelector("div.catalog") ||
                  // document.querySelector("div.Jweg1q")
                  document.querySelector('div[data-testid="items-list"]')

            if (aReviews) {
                clearInterval(interval);
                // var divs = document.querySelectorAll('.YREwlL');
                // десктопная версия
                // var divs = document.querySelectorAll('.ulVbvy')
                // var divs = document.querySelectorAll('div[data-testid="feedback-side-bar:count-comments"]')
                var divs = document.querySelectorAll('div[data-testid="rating-counter"]') // для десктопной и мобильной версий одновременно
                // или мобильная
                if (divs.length === 0) { // устарело, на всякий случай
                    divs = document.querySelectorAll('div.Ca1QyR')
                }
                // цикл по каждому div
                divs.forEach((div) => {
                    // если ссылка ранее не была добавлена: повторное добавление после загрузки всей страницы. По каким-то причинам в конце загрузки страницы ссылки удаляются, но их добавление во время загузки необходимо чтобы пльзователь имел возможность нажимать
                    if (!div.querySelector('a')) {
                        // div.parentNode.parentNode.parentNode.querySelector('div[data-testid="item-name"] a')
                        // десктопная и мобильная версии
                        const div_itemName = div.closest('div:has(div[data-testid="item-name"] a)') || div.closest('div[data-testid="catalog-item:row"] a')
                        if (!div_itemName) return
                        let link = div_itemName.querySelector('a')

                        if(link?.tagName === "A") {
                            var href = link.getAttribute('href');

                            // Создание нового узла <a>
                            let aNode = document.createElement('a');

                            // Установка параметров узла
                            aNode.href = `${href}###`;
                            aNode.style.cssText = 'display: flex; width: 100%; height: 100%; cursor: pointer; text-decoration: none;';

                            // Перемещаем все дочерние узлы из div1 в новый узел <a>
                            while (div.firstChild) {
                                aNode.appendChild(div.firstChild);
                            }
                            // Перемещаем узел div внутрь aNode
                            div.appendChild(aNode);
                        }
                    }
                });
            }
        }, 50);
    }

    // Simaland: Оптимизация вида
    function SimaLandOptimization() {
        // Сималенд: Карточка товара: Характеристики
        const interval_Characteristics_mini = setInterval(() => {
            const Characteristics_mini = document.querySelector("#product__root > div > div.Fa76rh > div:nth-child(1) > div > div > div.hb20Nd > div.gnpN7o > div.yV_RnX > div:nth-child(1)")

            if (Characteristics_mini) {
                clearInterval(interval_Characteristics_mini);
                // Блок с: Все товары данной фирмы
                const interval_Prices = setInterval(() => {
                    const Prices = document.querySelector("#product__root > div > div.Fa76rh > div:nth-child(1) > div > div > div.hb20Nd > div.gnpN7o > div.nl50DW")
                    if (Prices) {
                        clearInterval(interval_Prices);
                        // Переместим узел SimilarProducts внутрь узла details в самый конец
                        Prices.append(Characteristics_mini);
                    }

                })
                }
        })

        // Блок с: Похожие товары; Также рекомендуем
        let details
        const interval_SimilarProducts_AlsoRecommend = setInterval(() => {
            const SimilarProducts = document.querySelector('#product__root > div > div.Fa76rh > div:nth-child(2) > div > div[data-testid="similar-recommendations-ref"]')
            const AlsoRecommend = document.querySelector('#product__root > div > div.Fa76rh > div:nth-child(2) > div > div[data-testid="related-recommendations-ref"]')
            const SimilarProducts_AlsoRecommend = SimilarProducts || AlsoRecommend

            if (SimilarProducts_AlsoRecommend && SimilarProducts_AlsoRecommend.children.length > 0) {

                // Если определён только один из двух блоков - details не был создан ранее
                if (!details) {
                    // Создать элемент <details> и установить его в свернутом состоянии по умолчанию
                    details = document.createElement('details');
                    details.style.marginTop = "2em";
                    // Создать элемент <summary> с текстом
                    const summary = document.createElement('summary');
                    summary.classList.add('N6SYKn');
                    summary.textContent = 'Похожие товары + Также рекомендуем';
                    summary.style.cursor = 'pointer';

                    // Добавить элемент <summary> в <details>
                    details.appendChild(summary);

                    // Добавить созданный элемент <details> перед любым из двух блоков, который вывелся первым
                    SimilarProducts_AlsoRecommend.insertAdjacentElement('beforebegin', details);
                    // Переместить SimilarProducts_AlsoRecommend внутрь <details>
                    details.appendChild(SimilarProducts_AlsoRecommend);
                    // определён и второй блок
                } else {
                    clearInterval(interval_SimilarProducts_AlsoRecommend);
                    // Переместим узел SimilarProducts внутрь узла details в самое начало
                    if (SimilarProducts_AlsoRecommend === SimilarProducts) {
                        details.prepend(SimilarProducts);
                    } else if (SimilarProducts_AlsoRecommend === AlsoRecommend) {
                        // Переместим узел SimilarProducts внутрь узла details в самый конец
                        details.append(AlsoRecommend);
                    }
                }
            }
        }, 50);
    }



    // Проверка, является ли страница карточкой товара, содержащей отзывы, и если да - сортировка отзывов по возрастанию рейтинга. В случае Simaland важна последовательность
    // Ozon: начинается ли адрес страницы со 'https://www.ozon.ru/product/' и не содержит ли он уже '&sort=score_asc' и прочие варианты сортировки
    if (currentURL.includes('ozon.ru/product/') && !currentURL.includes('&sort=score_asc') && !currentURL.includes('?sort=score_asc') && !currentURL.includes('&sort=score_desc') && !currentURL.includes('?sort=score_desc')) {
        // Если условия выполняются - добавляем к адресу параметр и перезагружаем страницу с новым адресом, производящим сортировку рейтингов по возрастанию
        if (config.SettingsOnOff) {
            let NewURL
            if (!currentURL.includes('/reviews?sort=score_asc') && !currentURL.includes('/reviews?sort=score_desc')) {
                if (currentURL.includes('/reviews')) {
                    NewURL = currentURL.replace('/reviews', '/reviews?sort=score_asc');
                } else {
                    NewURL = `${currentURL}&sort=score_asc`;
                }
                if (config.isRunningAsExtension) {
                    api.runtime.sendMessage({action: "redirect", url: NewURL}); // перезагрузка страницы приводит к оходу данного условия и переходу к следующим условиям
                } else {
                    window.location.href = NewURL; // перезагрузка страницы приводит к оходу данного условия и переходу к следующим условиям
                }
            }
        }
        // Ozon: Страница карточки товара
    } else if (currentURL.includes('ozon.ru/product/')) {
        // Если условия выполняются - добавляем к адресу параметр и перезагружаем страницу с новым адресом, производящим сортировку рейтингов по возрастанию
        if (config.SettingsOnOff) {
            // сокрытие и перестановка мешающих блоков
            // первый блок фото из отзывов - скрываем, так как он дублирует этот же блок в отзывах
            const intervalReviewsFoto = setInterval(() => {
                const ReviewsFoto = document.querySelector("#layoutPage > div.b2 > div:nth-child(7) > div > div.container.b6 > div:nth-child(1)") // фотки из отзывов - скрыть
                if (ReviewsFoto) {
                    clearInterval(intervalReviewsFoto);
                    ReviewsFoto.style.display = 'none'
                }
            }, 50);
            // Блок с: Информация о продавце; Другие предложения от продавцов на Ozon.ru
            const intervalSellers = setInterval(() => {
                const Sellers = document.querySelector("#layoutPage > div.b2 > div:nth-child(7) > div > div.container.b6 > div.d8") // инфа по продавцам
                if (Sellers) {
                    // Другие предложения от продавцов на Ozon.ru - скрываем так как он дублирует аналогичный блок внизу страницы
                    const SellersOtherOffers = Sellers.querySelector("div > div.j6y")
                    if (SellersOtherOffers) {
                        // SellersOtherOffers.style.display = 'none'
                        clearInterval(intervalSellers);
                    }
                }
            }, 50);
            // Блок с: Похожие товары; Покупают вместе
            const interval_AlsoRecommend_BuyTogether = setInterval(() => {
                // const AlsoRecommend_BuyTogether = document.querySelector("#layoutPage > div.b2 > div:nth-child(7) > div > div.container.b6 > div.ml6.l2n.m9l.nl0 > div:nth-child(1)") || document.querySelector("#layoutPage > div.b2.b4 > div:nth-child(10) > div > div > div.pj6")
                // десктопная версия
                const AlsoRecommend_BuyTogether = document.querySelector('div[data-widget="skuShelfGoods"]') // всего два таких лемента, на достаточно выбрать первый
                let AlsoRecommend_BuyTogether_Full
                if (AlsoRecommend_BuyTogether) AlsoRecommend_BuyTogether_Full = AlsoRecommend_BuyTogether.parentNode.parentNode

                // мобильная версия
                const AlsoRecommend_BuyTogether_mobile_Divs = document.querySelectorAll('div[data-widget="skuScroll"]')

                if (AlsoRecommend_BuyTogether || AlsoRecommend_BuyTogether_mobile_Divs.length > 0) {
                    // пока отключаю, потом буду сворачивать
                    clearInterval(interval_AlsoRecommend_BuyTogether);

                    let UseDetails = true
                    const observer = new MutationObserver((mutationsList, observer) => {
                        for (const mutation of mutationsList) {
                            if (mutation.type === 'childList' || mutation.type === 'attributes') {
                                console.log('Изменение содержимого div или атрибутов div обнаружено.');

                                // Дополнительная логика проверки:
                                if (UseDetails) {
                                    // if ((AlsoRecommend_BuyTogether && AlsoRecommend_BuyTogether.children.length === 1 && AlsoRecommend_BuyTogether.children[0].children.length === 1) ||
                                    //     (!AlsoRecommend_BuyTogether && AlsoRecommend_BuyTogether_mobile_Divs.length === 0)) {
                                    if (AlsoRecommend_BuyTogether || AlsoRecommend_BuyTogether_mobile_Divs.length > 0) {
                                        UseDetails = false
                                        // Если нужно остановить наблюдение в будущем:
                                        // Но срабатывает не мгновенно - приходится использовать флаг UseDetails
                                        observer.disconnect();
                                        // Создать элемент <details> и установить его в свернутом состоянии по умолчанию
                                        const details = document.createElement('details');

                                        // Создать элемент <summary> с текстом
                                        const summary = document.createElement('summary');
                                        summary.classList.add('tsHeadline500Medium');
                                        summary.textContent = 'Похожие товары + Покупают вместе';
                                        summary.style.cursor = 'pointer';


                                        // Добавить элемент <summary> в <details>
                                        details.appendChild(summary);
                                        // десктопная версия
                                        if (AlsoRecommend_BuyTogether) {
                                            // Добавить созданный элемент <details> перед элементом AlsoRecommend_BuyTogether
                                            AlsoRecommend_BuyTogether_Full.insertAdjacentElement('beforebegin', details);

                                            // Переместить существующий элемент AlsoRecommend_BuyTogether внутрь <details>

                                            details.appendChild(AlsoRecommend_BuyTogether_Full);
                                            // details перемещаем до блока комментариев
                                            const div_Description = document.querySelector("#comments")
                                            if (div_Description) div_Description.insertAdjacentElement('beforebegin', details);
                                        }
                                        // мобильная версия
                                        if (AlsoRecommend_BuyTogether_mobile_Divs.length > 0) {
                                            // Добавить созданный элемент <details> перед элементом AlsoRecommend_BuyTogether
                                            AlsoRecommend_BuyTogether_mobile_Divs[0].insertAdjacentElement('beforebegin', details);

                                            // Переместить элементы AlsoRecommend_BuyTogether_mobile_Divs внутрь <details>
                                            AlsoRecommend_BuyTogether_mobile_Divs.forEach(div => {
                                                details.appendChild(div);
                                            });

                                            const div_Description = document.querySelector('div[data-widget="webMobTabs"]')
                                            if (div_Description) div_Description.insertAdjacentElement('afterend', details);
                                        }

                                    }
                                }
                            }
                        }
                    });

                    // Указываем, за какими изменениями хотим наблюдать:
                    const config = { attributes: true, childList: true, subtree: true };

                    // Начинаем наблюдение:
                    if (AlsoRecommend_BuyTogether) {
                        observer.observe(AlsoRecommend_BuyTogether_Full, config);
                    } else if (AlsoRecommend_BuyTogether_mobile_Divs.length > 0) {
                        observer.observe(AlsoRecommend_BuyTogether_mobile_Divs[0], config)
                    }

                    // Если нужно остановить наблюдение в будущем:
                    // observer.disconnect();

                }

            }, 50);

            // Блок с рекламой
            function OzonpPoductRemoveElements() {
                // десктопная версия
                document.querySelectorAll('div[data-widget="skuGrid"]').forEach(function(element) {
                    element.remove();
                });
                // мобильная версия
                document.querySelectorAll('div.q3j_23[data-widget="skuScroll"]').forEach(function(element) {
                    element.remove();
                });
            }
            // Удаление при загрузке содержимого
            OzonpPoductRemoveElements();

            window.addEventListener('load', ()=>{
                // Удаление при прокрутке страницы
                window.addEventListener('scroll', OzonpPoductRemoveElements);

                // Наблюдатель за изменениями в DOM
                const observer = new MutationObserver(OzonpPoductRemoveElements);

                // Настройки наблюдателя
                const config = { childList: true, subtree: true };

                // Наблюдение за изменениями в body
                observer.observe(document.body, config);
            });
        }
        // Ozon: Страница каталога товаров
    } else if (currentURL.includes('ozon.ru/category/') ) {
        if (config.SettingsOnOff) {
            addOzonSortParamToLinks()
        }
        // Ozon: Страница главная
    } else if (currentURL==='https://www.ozon.ru/' ) {
        if (config.SettingsOnOff) {
            // Добавление кнопки "Реклама"
            const EspeciallyForYou = CreateEspeciallyForYou()
            // let EspeciallyForYou_factView = false // факт вывода раскрывающегося блока рекламы
            // вырезание верхнего баннера
            const targetNode = document.querySelector('div[data-widget="advBanner"]')
            // targetNode?.remove()
            function Add_targetNode_into_EspeciallyForYou(targetNode) {
                if (targetNode && targetNode.parentNode !== EspeciallyForYou) {
                    if (!targetNode.parentNode.contains(EspeciallyForYou)) {
                        targetNode.parentNode.insertBefore(EspeciallyForYou, targetNode)
                    }
                    targetNode.style.marginTop = '0.3rem'
                    EspeciallyForYou?.appendChild(targetNode)
                }
            }
            Add_targetNode_into_EspeciallyForYou(targetNode)
            // Настраиваем наблюдение за изменениями в документе
            const observer = new MutationObserver((mutationsList, observer) => {
                for (let mutation of mutationsList) {
                    if (mutation.type === 'childList') {
                        mutation.addedNodes.forEach(node => {
                            if (node.nodeType === Node.ELEMENT_NODE && node.nodeName === 'DIV') {
                                if (node.dataset.widget === "advBanner") {
                                    Add_targetNode_into_EspeciallyForYou(node)
                                }
                            }
                        });

                    }
                }
            });
            const observer_config = { attributes: true, childList: true, subtree: true };
            observer.observe(document.querySelector('div#__ozon'), observer_config);
        }

        // Wildberries: карточка товара
    } else if (currentURL.includes('wildberries.ru/catalog/') && currentURL.includes('/feedbacks')) {

        sortWildberriesReviews();
        // Wildberries: каталоги
    } else if (currentURL.includes('wildberries.ru/')) {
        if (config.SettingsOnOff) {

            window.addEventListener('load', addWildberriesSortParamToLinks)
        }
        // Simaland: страница карточки товара
    } else if (currentURL.match(/^https:\/\/www\.sima-land\.ru\/\d+\/.+\/$/)) {
        // } else if (/^https:\/\/www\.sima-land\.ru\/\d{7}\/.*\/$/.test(currentURL)) {
        sortSimaLandReviews();
        SimaLandOptimization()
        // Simaland: страница карточки товара, вызванная из каталога при нажатии ссылки рейтинга
    } else if (currentURL.match(/^https:\/\/www\.sima-land\.ru\/\d+\/.+\/###$/)) {
        // } else if (/^https:\/\/www\.sima-land\.ru\/\d{7}\/.*\/###$/.test(currentURL)) {
        // SimaLandCatalogReviews();
        // приходится ждать загруки страницы так, иначе не подвязываются необходиме функции обработки клика по ссылке рейтинга
        window.addEventListener('load', SimaLandCatalogReviewsOpen)
        // SimaLandCatalogReviewsOpen()
        // Страница каталога товаров
    } else if (currentURL.match(/^https:\/\/www\.sima-land\.ru\/.+\/(.*)$/)) {
        // } else if (/^https:\/\/www\.sima-land\.ru\/.+\/$/.test(currentURL)) {
        SimaLandCatalogReviews()
        window.addEventListener('load', SimaLandCatalogReviews) // в дальнейшем можно разремить при условии проверки на добавленые в div ссылки
    }


    // Wildberries: определение совершения перехода на карточку товара с разделом отзывов
    // перехват событияй истории (кнопок назад-вперёд)
    window.onpopstate = () => {
        // получаем текущий адрес страницы
        if (new URL(window.location.href).pathname.startsWith('/catalog/') && window.location.href.includes('/feedbacks')) {
            sortWildberriesReviews();
        }
    };

    const originalPushState = history.pushState;
    history.pushState = function (state, ...args) {
        originalPushState.apply(this, [state, ...args]);
        // Вызываем функцию сортировки после пуша состояния
        sortWildberriesReviews();
    };

    history.replaceState = new Proxy(history.replaceState, {
        apply: function(target, thisArg, argArray) {
            target.apply(thisArg, argArray);
            sortWildberriesReviews();
        }
    });

    if (config.isRunningAsExtension) {
        // событие изменения адреса данной вкладки
        api.runtime.onMessage.addListener((request, sender, sendResponse) => {
            // получаем текущий адрес страницы
            if (new URL(request.url).pathname.startsWith('/catalog/') && request.url.includes('/feedbacks')) {
                sortWildberriesReviews();
            }
        });
    }

    // Ozon: Замена ссылок на странице на случай если пользователь захочет открыть ссылку карточки товара в новой вкладке. Отработает позднее, после загрузки. Не обязательное действие.
    // Вызываем функцию сразу после загрузки страницы
    if (currentURL.startsWith('https://www.ozon.ru/')) {
        window.addEventListener('load', addOzonSortParamToLinks)
    }



    // For extentions
    function initConfig() {
        initializeSettingsOnOff();
    }

    // получение значения при загрузке popup
    function initializeSettingsOnOff() {
        api.storage.local.get(["SettingsOnOff"], (res) => {
            if ("SettingsOnOff" in res){
                handleSettingsOnOffChangeEvent(res.SettingsOnOff)
            }else{
                handleSettingsOnOffChangeEvent(true);
                api.storage.local.set({ SettingsOnOff: true })
            }
        });
    }

    //если в хранилище произошли изменения соответствующего параметра...
    function storageChangeHandler(changes, area) {
        if (area === 'local') {
            if (changes.SettingsOnOff !== undefined) {
                // if (changes.SettingsOnOff?.newValue) {
                handleSettingsOnOffChangeEvent(
                    changes.SettingsOnOff.newValue
                )
            }

        }
    }
    //... происходит установка значения конфига и контрола
    function handleSettingsOnOffChangeEvent(value) {
        config.SettingsOnOff = value;
    }

    if (config.isRunningAsExtension) {
        //добавление прослушивания события изменения хранилища
        api.storage.onChanged.addListener(storageChangeHandler)
    }

    // Добавлекние раскрывающегося блока "Реклама"
    function CreateEspeciallyForYou() {
        // Создание стилей с помощью JavaScript
        const style = document.createElement("style")
        style.textContent = `
                details {
                    // display: none;
                    font-family: Arial, sans-serif;
                    font-size: 18px;
                    color: #333;
                    position: relative;
                    padding: 10px;
                    border: 1px solid #ccc;
                    border-radius: 5px;
                    background-color: #fff;
                    max-height: 50vh;
                    overflow-y: auto;
                }
                summary {
                    cursor: pointer;
                    outline: none;
                    position: relative;
                    z-index: 1;
                    color: #df0f70; /* Изменение цвета текста на красный */
                }
                .shimmer {
                    position: absolute;
                    top: 0;
                    left: 0;
                    width: 100%;
                    height: 100%;
                    background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.5) 50%, rgba(255, 255, 255, 0) 100%);
                    animation: shimmer 60s linear infinite;
                    pointer-events: none;
                }
                @keyframes shimmer {
                    0% {
                        transform: translateX(-100%);
                    }
                    100% {
                        transform: translateX(100%);
                    }
                }
            `;
        document.head.appendChild(style);

        // Создание элемента details
        const details = document.createElement("details");
        // Добавляем класс my-details-class к элементу <details>
        details.classList.add('details_EspeciallyForYou');

        // Определение языка браузера
        const browserLanguage = navigator.language || navigator.userLanguage;
        let messageSpecialOffer = 'Реклама'

        switch (browserLanguage) {
            case "uken":
                messageSpecialOffer = 'Реклама'
                break;
            default:
                messageSpecialOffer = 'Реклама'
        }
        const summary = document.createElement("summary");
        summary.textContent = messageSpecialOffer;

        const shimmer = document.createElement("div");
        shimmer.className = "shimmer";

        // const content = document.createElement("p");
        // content.textContent = "Содержимое деталей...";

        details.appendChild(summary);
        details.appendChild(shimmer);
        // details.appendChild(content);

        // document.body.appendChild(details);
        return details
    }

})();