Greasy Fork is available in English.

Ozon, Wildberries, Simaland и Яндекс.Маркет настройка: сначала плохие отзывы + улучшения интерфейса

Ozon, Wildberries, Simaland и Яндекс.Маркет: сортировка отзывов по товару по возрастанию рейтинга

// ==UserScript==
// @name         Ozon, Wildberries, Simaland и Яндекс.Маркет настройка: сначала плохие отзывы + улучшения интерфейса
// @name:en      Ozon, Wildberries and Simaland customizer: bad reviews first + interface improvements
// @name:ru      Ozon, Wildberries, Simaland и Яндекс.Маркет настройка: сначала плохие отзывы + улучшения интерфейса
// @namespace    http://tampermonkey.net/
// @version      2025-02-04_03-27
// @description  Ozon, Wildberries, Simaland и Яндекс.Маркет: сортировка отзывов по товару по возрастанию рейтинга
// @description:en  Ozon, Wildberries, Simaland and Яндекс.Маркет: 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          https://*.ozon.by/*
// @match          http://*.wildberries.ru/*
// @match          https://*.wildberries.ru/*
// @match          https://*.global.wildberries.ru/*
// @match          http://*.sima-land.ru/*
// @match          https://*.sima-land.ru/*
// @match          http://*.market.yandex.ru/*
// @match          https://*.market.yandex.ru/*
// ==/UserScript==

/* global GM_config */

(() => {
    '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 => {
                link.search = ''
                const linkOrig = link.href
                link.href += '&sort=score_asc';
                // Проверяем, является ли родительский элемент (parentNode) div с классом 'iy6'
                const link_parentNode = link.parentNode
                // Привязка к блоку рейтингов (звёздочек) ссылки на рейтинги
                const nextNode = link.nextElementSibling;

                if (nextNode && nextNode.tagName === 'DIV' && (nextNode.classList.contains('tsBodyMBold') || nextNode.classList.contains('tsCaptionBold'))) {

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

                        divStars.addEventListener('click', () => {
                            // Формируем URL
                            const url = `${url1Base}reviews/?sort=score_asc`;
                            // Переходим по ссылке
                            // window.location.href = url;
                            // Открыть в новой вкладке
                            window.open(url, '_blank');
                        });


                        //                         // Создание нового узла <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('a[data-link*="sorterModel.sortingEntries[\'valuationup\']"]')
                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 Wildberries__Показать_блок__Характеристики_и_описание__и_разместить_под_фото_товара() {
        // Для Wildberries и WildberriesGlobal
        let popup__content = document.querySelector('div.popup-product-details > div.popup__content') // Всплывающий блок с описанием уже присутствует на загружаемой странице - это маловероятно
        let product_params__table = document.querySelector('div.popup__content > div.product-details > div.product-params > table.product-params__table')
        let factClick_button_product_page__btn_detail = false // факт программного нажатия button_product_page__btn_detail
        let button_product_page__btn_detail // кнопка вызова блока Характеристикаи и описание

        if (product_params__table) { // Всплывающий блок присутствует на загружаемой странице - это маловероятно
            popup_product_details_Replace()
        }
        else { // Всплывающий блок отсутствует
            // Создаем новый экземпляр MutationObserver
            const observer = new MutationObserver((mutationsList, observer) => {
                // Проходимся по списку изменений
                for (let mutation of mutationsList) {
                    // Проверяем, добавлены ли новые узлы
                    if (mutation.type === 'childList') {
                        // Проходимся по списку добавленных узлов
                        for (let node of mutation.addedNodes) {
                            if (node.nodeType === 1) {
                                // Проверяем, является ли узел элементом <div> с классом popup-product-details
                                if (!button_product_page__btn_detail &&
                                    node.matches('button.product-page__btn-detail')) {
                                    button_product_page__btn_detail = node // произошёл вывод кнокпи вызова всплывающего блока Характеристики и описания
                                    button_product_page__btn_detail_click()
                                }
                                // Программное нажатие button_product_page__btn_detail: Последующий вызов всплывающего блока с заполненными Характеристики и описания
                                else if (factClick_button_product_page__btn_detail &&
                                         node.matches('div.popup-product-details')) {
                                    // Выведен полноценный заполненный блок
                                    if (node.querySelector('div.popup__content > div.product-details > div.product-params > table.product-params__table')) {
                                        // Прерываем наблюдение
                                        observer.disconnect()
                                        popup__content = node.querySelector('div.popup__content')
                                        popup_product_details_Replace()
                                        break
                                    }
                                    // Блок ещё не заполнен: такое происходит при навигации по сайту и открытию карточек товара
                                    else {
                                        node.remove()
                                        factClick_button_product_page__btn_detail = false
                                        setTimeout(function() {
                                            button_product_page__btn_detail_click()
                                        }, 1000);

                                    }

                                }
                            }
                        }
                    }
                }
            });

            // Начинаем наблюдение за изменениями внутри элемента <body>
            observer.observe(document.body, { childList: true })
            button_product_page__btn_detail_click()

        }

        // Программное нажатие кнопки вызов всплывающего блока Характеристик и описания
        function button_product_page__btn_detail_click() {
            if (!button_product_page__btn_detail) // Если не успело определиться в обсервере
                button_product_page__btn_detail = document.querySelector('#app button.product-page__btn-detail') // Кнокпа вызова всплывающего блока Характеристики и описания
            if (button_product_page__btn_detail && !factClick_button_product_page__btn_detail) { // Если в обсервере не произошёл факт нажатия
                factClick_button_product_page__btn_detail = true
                button_product_page__btn_detail.click() // вызов всплывающего блока Характеристик и описания
            }
        }
        // Перенос Характеристик и описания из вызываемого всплывающего блока под блок товара
        function popup_product_details_Replace() {
            if (factClick_button_product_page__btn_detail) // при програмном нажатии
                popup__content.parentNode.remove() // удаление вызванного всплывающего блока
            // Wildberries и WildberriesGlobal
            const product_page__grid = document.querySelector('div.product-page__grid')
            if (product_page__grid) {
                product_page__grid.parentNode.querySelectorAll('div.popup__content').forEach(function(element) { // удаление всех ранее внедрённых блоков popup__content, которые сохраняются на страинце при навигации
                    element.remove();
                });
            }
            if (popup__content && product_page__grid) {
                popup__content?.querySelector('div.popup__footer')?.remove() // Удаление лишней информации и элементов из подваала вспывающего блока
                product_page__grid.insertAdjacentElement('afterend', popup__content)
            }
            document.body.classList.remove('body--overflow') // при выводе всплывающего блока добавляется вредный класс body--overflow, скрывающий полосы прокрутки, и при программном закрытии всплывающего блока класс body--overflow не удаляется.
        }
    }
    // TODO:    // Wildberries Global: Показать блок "Характеристики и описание" и разместить под фото товара()
    function WildberriesGlobal__Показать_блок__Характеристики_и_описание__и_разместить_под_фото_товара() {
        // Для Wildberries и WildberriesGlobal
        let popup__content = document.querySelector('div.drawer-wrapper') // Всплывающий блок с описанием уже присутствует на загружаемой странице - это маловероятно
        let product_params__table = document.querySelector('div.full-details__list div.full-details-info')
        let factClick_button_product_page__btn_detail = false // факт программного нажатия button_product_page__btn_detail
        let button_product_page__btn_detail // кнопка вызова блока Характеристикаи и описание

        if (product_params__table) { // Всплывающий блок присутствует на загружаемой странице - это маловероятно
            popup_product_details_Replace()
        }
        else { // Всплывающий блок отсутствует
            // Создаем новый экземпляр MutationObserver
            const observer = new MutationObserver((mutationsList, observer) => {
                // Проходимся по списку изменений
                for (let mutation of mutationsList) {
                    // Проверяем, добавлены ли новые узлы
                    if (mutation.type === 'childList') {
                        // Проходимся по списку добавленных узлов
                        for (let node of mutation.addedNodes) {
                            if (node.nodeType === 1) {
                                // Проверяем, является ли узел элементом <div> с классом popup-product-details
                                if (!button_product_page__btn_detail &&
                                    node.matches('button.product-page__btn-detail')) {
                                    button_product_page__btn_detail = node // произошёл вывод кнокпи вызова всплывающего блока Характеристики и описания
                                    button_product_page__btn_detail_click()
                                }
                                // Программное нажатие button_product_page__btn_detail: Последующий вызов всплывающего блока с заполненными Характеристики и описания
                                else if (factClick_button_product_page__btn_detail &&
                                         node.matches('div.popup-product-details')) {
                                    // Выведен полноценный заполненный блок
                                    if (node.querySelector('div.popup__content > div.product-details > div.product-params > table.product-params__table')) {
                                        // Прерываем наблюдение
                                        observer.disconnect()
                                        popup__content = node.querySelector('div.popup__content')
                                        popup_product_details_Replace()
                                        break
                                    }
                                    // Блок ещё не заполнен: такое происходит при навигации по сайту и открытию карточек товара
                                    else {
                                        node.remove()
                                        factClick_button_product_page__btn_detail = false
                                        setTimeout(function() {
                                            button_product_page__btn_detail_click()
                                        }, 1000);

                                    }

                                }
                            }
                        }
                    }
                }
            });

            // Начинаем наблюдение за изменениями внутри элемента <body>
            observer.observe(document.body, { childList: true })
            button_product_page__btn_detail_click()

        }

        // Программное нажатие кнопки вызов всплывающего блока Характеристик и описания
        function button_product_page__btn_detail_click() {
            if (!button_product_page__btn_detail) // Если не успело определиться в обсервере
                button_product_page__btn_detail = document.querySelector('#app button.product-page__btn-detail') // Кнокпа вызова всплывающего блока Характеристики и описания
            if (button_product_page__btn_detail && !factClick_button_product_page__btn_detail) { // Если в обсервере не произошёл факт нажатия
                factClick_button_product_page__btn_detail = true
                button_product_page__btn_detail.click() // вызов всплывающего блока Характеристик и описания
            }
        }
        // Перенос Характеристик и описания из вызываемого всплывающего блока под блок товара
        function popup_product_details_Replace() {
            if (factClick_button_product_page__btn_detail) // при програмном нажатии
                popup__content.parentNode.remove() // удаление вызванного всплывающего блока
            // Wildberries и WildberriesGlobal
            const product_page__grid = document.querySelector('div.product-main')
            if (product_page__grid) {
                product_page__grid.parentNode.querySelectorAll('div.drawer-wrapper').forEach(function(element) { // удаление всех ранее внедрённых блоков popup__content, которые сохраняются на страинце при навигации
                    element.remove();
                });
            }
            if (popup__content && product_page__grid) {
                popup__content?.querySelector('div.drawer__button')?.remove() // Удаление лишней информации и элементов из подваала вспывающего блока
                product_page__grid.insertAdjacentElement('afterend', popup__content)
            }
            document.body.classList.remove('body--overflow') // при выводе всплывающего блока добавляется вредный класс body--overflow, скрывающий полосы прокрутки, и при программном закрытии всплывающего блока класс body--overflow не удаляется.
        }
    }

    // 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         // Также отслеживаем все поддеревья
            });

        }
    }
    function WildberriesGlobal__Сортировка_отзывов_по_возрастанию() {
        if (!window.location.pathname.includes('&sort=valueup')) {
            const кнопкаРейтинг = document.querySelector('button.switcher__item.has-alternate')
            if (кнопкаРейтинг) {
                кнопкаРейтинг.click()
            }
            else {
                const callback = function (mutationsList, observer) {
                    for (const mutation of mutationsList) {
                        // Проверяем, были ли добавлены новые узлы
                        if (mutation.type === 'childList') {
                            mutation.addedNodes.forEach(node => {
                                if (node.nodeType === Node.ELEMENT_NODE) {
                                    if (node.matches('button.switcher__item.has-alternate') && !node.matches('button.is-active')) {
                                        node.click()
                                        observer.disconnect()
                                    } else {
                                        // Проверяем вложенные элементы
                                        const switcherItem = node.querySelector('button.switcher__item.has-alternate');
                                        if (switcherItem) {
                                            if (!switcherItem.matches('button.is-active')) {
                                                switcherItem.click()
                                                // После нахождения элемента можно остановить наблюдение
                                                observer.disconnect()
                                            }
                                        }
                                    }
                                }
                            });
                        }
                    }
                };

                // Создаем экземпляр MutationObserver
                const observer = new MutationObserver(callback);

                // Начинаем наблюдение за изменениями в DOM
                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() {

        // Ожидание появления интересующего элемента
        function waitForElement(parentSelector, targetSelector, targetAttributeName, targetAttributeValue, callback) {
            let parent = document.querySelector(parentSelector);

            if (!parent) {
                parent = document.body
            }

            const observer = new MutationObserver((mutations) => {
                for (const mutation of mutations) {
                    if (mutation.type === 'childList') {
                        const addedNodes = mutation.addedNodes;
                        addedNodes.forEach((node) => {
                            // if (node.nodeType === Node.ELEMENT_NODE && node.getAttribute('data-testid') === 'app-wrapper') {
                            if (node.nodeType === Node.ELEMENT_NODE && node.getAttribute(targetAttributeName) === targetAttributeValue) {
                                callback(node);
                                return;
                            }
                        });


                    }
                }
            });

            // Начинаем наблюдение за изменениями в DOM
            observer.observe(parent, {
                childList: true, // Наблюдаем за добавлением/удалением дочерних элементов
                subtree: true    // Наблюдаем за всеми элементами в поддереве
            });
        }

        // Проверяем, может быть элемент уже есть на странице
        const appWrapper = document.querySelector('#product__root div[data-testid="app-wrapper"]');
        if (appWrapper) {
            clickLinkReviews()
        }
        waitForElement('#product__root', '[data-testid="app-wrapper"]', 'data-testid', 'app-wrapper', (element) => {
            clickLinkReviews()
        });

    }

    // 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);
        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);
    }




    // Яндекс.Маркет: Показать блок "Характеристики и описание" и разместить под фото товара()
    function Яндекс_Маркет__Показать_блок__Характеристики_и_описание__и_разместить_под_фото_товара() {
        let popup__content = document.querySelector('div.popup-product-details > div.popup__content') // Всплывающий блок с описанием уже присутствует на загружаемой странице - это маловероятно
        let product_params__table = document.querySelector('div.popup__content > div.product-details > div.product-params > table.product-params__table')
        let factClick_button_product_page__btn_detail = false // факт программного нажатия button_product_page__btn_detail
        let button_product_page__btn_detail // кнопка вызова блока Характеристикаи и описание

        if (product_params__table) { // Всплывающий блок присутствует на загружаемой странице - это маловероятно
            popup_product_details_Replace()
        }
        else { // Всплывающий блок отсутствует
            // Создаем новый экземпляр MutationObserver
            const observer = new MutationObserver((mutationsList, observer) => {
                // Проходимся по списку изменений
                for (let mutation of mutationsList) {
                    // Проверяем, добавлены ли новые узлы
                    if (mutation.type === 'childList') {
                        // Проходимся по списку добавленных узлов
                        for (let node of mutation.addedNodes) {
                            if (node.nodeType === 1) {
                                // Проверяем, является ли узел элементом <div> с классом popup-product-details
                                if (!button_product_page__btn_detail &&
                                    node.matches('button.product-page__btn-detail')) {
                                    button_product_page__btn_detail = node // произошёл вывод кнокпи вызова всплывающего блока Характеристики и описания
                                    button_product_page__btn_detail_click()
                                }
                                // Программное нажатие button_product_page__btn_detail: Последующий вызов всплывающего блока с заполненными Характеристики и описания
                                else if (factClick_button_product_page__btn_detail &&
                                         node.matches('div.popup-product-details')) {
                                    // Выведен полноценный заполненный блок
                                    if (node.querySelector('div.popup__content > div.product-details > div.product-params > table.product-params__table')) {
                                        // Прерываем наблюдение
                                        observer.disconnect()
                                        popup__content = node.querySelector('div.popup__content')
                                        popup_product_details_Replace()
                                        break
                                    }
                                    // Блок ещё не заполнен: такое происходит при навигации по сайту и открытию карточек товара
                                    else {
                                        node.remove()
                                        factClick_button_product_page__btn_detail = false
                                        setTimeout(function() {
                                            button_product_page__btn_detail_click()
                                        }, 1000);

                                    }

                                }
                            }
                        }
                    }
                }
            });

            // Начинаем наблюдение за изменениями внутри элемента <body>
            observer.observe(document.body, { childList: true })
            button_product_page__btn_detail_click()

        }

        // Программное нажатие кнопки вызов всплывающего блока Характеристик и описания
        function button_product_page__btn_detail_click() {
            if (!button_product_page__btn_detail) // Если не успело определиться в обсервере
                button_product_page__btn_detail = document.querySelector('#app button.product-page__btn-detail') // Кнокпа вызова всплывающего блока Характеристики и описания
            if (button_product_page__btn_detail && !factClick_button_product_page__btn_detail) { // Если в обсервере не произошёл факт нажатия
                factClick_button_product_page__btn_detail = true
                button_product_page__btn_detail.click() // вызов всплывающего блока Характеристик и описания
            }
        }
        // Перенос Характеристик и описания из вызываемого всплывающего блока под блок товара
        function popup_product_details_Replace() {
            if (factClick_button_product_page__btn_detail) // при програмном нажатии
                popup__content.parentNode.remove() // удаление вызванного всплывающего блока

            const product_page__grid = document.querySelector('div.product-page__grid')
            if (product_page__grid) {
                product_page__grid.parentNode.querySelectorAll('div.popup__content').forEach(function(element) { // удаление всех ранее внедрённых блоков popup__content, которые сохраняются на страинце при навигации
                    element.remove();
                });
            }
            if (popup__content && product_page__grid) {
                popup__content?.querySelector('div.popup__footer')?.remove() // Удаление лишней информации и элементов из подваала вспывающего блока
                product_page__grid.insertAdjacentElement('afterend', popup__content)
            }
            document.body.classList.remove('body--overflow') // при выводе всплывающего блока добавляется вредный класс body--overflow, скрывающий полосы прокрутки, и при программном закрытии всплывающего блока класс body--overflow не удаляется.
        }
    }







    if (config.SettingsOnOff) {

        // Проверка, является ли страница карточкой товара, содержащей отзывы, и если да - сортировка отзывов по возрастанию рейтинга.
        // Ozon: начинается ли адрес страницы со 'https://www.ozon.ru/product/' и не содержит ли он уже '&sort=score_asc' и прочие варианты сортировки
        if ((window.location.host.endsWith('ozon.ru') || window.location.host.endsWith('ozon.com') || window.location.host.endsWith('ozon.by')) && window.location.pathname.startsWith('/product/') &&
            !currentURL.includes('&sort=score_asc') && !currentURL.includes('?sort=score_asc') && !currentURL.includes('&sort=score_desc') && !currentURL.includes('?sort=score_desc')) {
            // Если условия выполняются - добавляем к адресу параметр и перезагружаем страницу с новым адресом, производящим сортировку рейтингов по возрастанию
            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 ((window.location.host.endsWith('ozon.ru') || window.location.host.endsWith('ozon.com') || window.location.host.endsWith('ozon.by')) && window.location.pathname.startsWith('/product/')) {
            // Если условия выполняются - добавляем к адресу параметр и перезагружаем страницу с новым адресом, производящим сортировку рейтингов по возрастанию
            // Мобильная версия
            // Удаление предложения перейти на мобильное приложение
            const webToAppBanner = document.querySelector('div[data-widget="webToAppBanner"]')
            if (webToAppBanner)
                webToAppBanner.style.display = 'none'
            const interval_webToAppBanner = setInterval(() => {
                webToAppBanner = document.querySelector('div[data-widget="webToAppBanner"]')
                if (webToAppBanner)
                    webToAppBanner.style.display = 'none'
            }, 200)
            // Настраиваем наблюдение за изменениями в документе
            const observer = new MutationObserver((mutationsList, observer) => {
                clearInterval(interval_webToAppBanner)
                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 === "webToAppBanner") {
                                    node.style.display = 'none'
                                }
                            }
                        });

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

            // сокрытие и перестановка мешающих блоков
            // первый блок фото из отзывов - скрываем, так как он дублирует этот же блок в отзывах
            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[data-widget="bannerCarousel"]').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 ((window.location.host.endsWith('ozon.ru') || window.location.host.endsWith('ozon.com') || window.location.host.endsWith('ozon.by')) &&
                   (window.location.pathname.startsWith('/category/') || window.location.pathname.startsWith('/highlight/'))) {
            addOzonSortParamToLinks() // TODO: вызвыает глюки
            // Ozon: Страница главная
            //         } else if (currentURL==='https://www.ozon.ru/' ) {
            //             // Любая другая страница Ozon
        } else if (window.location.host.endsWith('ozon.ru') || window.location.host.endsWith('ozon.com') || window.location.host.endsWith('ozon.by')) {
            // Добавление кнопки "Реклама"
            const EspeciallyForYou = CreateEspeciallyForYou('#df0f70')
            // 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(document.querySelector('div[data-widget="seasonWidget"]'))
            Add_targetNode_into_EspeciallyForYou(document.querySelector('div[data-widget="advBanner"]'))
            // Мобильная версия
            // Удаление предложения перейти на мобильное приложение
            document.querySelector('div[data-widget="webToAppBanner"]')?.parentNode.remove()
            const interval_webToAppBanner = setInterval(() => {
                document.querySelector('div[data-widget="webToAppBanner"]')?.parentNode.remove()
            }, 200)

            // Настраиваем наблюдение за изменениями в документе
            const observer = new MutationObserver((mutationsList, observer) => {
                clearInterval(interval_webToAppBanner)
                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 === "seasonWidget" || node.dataset.widget === "advBanner" ) {
                                    Add_targetNode_into_EspeciallyForYou(node)
                                }
                                // Мобильная версия
                                // Удаление предложения перейти на мобильное приложение
                                else if (node.dataset.widget === "webToAppBanner") {
                                    node.parentNode.remove()
                                }
                                // else if (node.classList.contains('tsBodyMBold')){
                                //     div.tsBodyMBold
                                // }
                            }
                        });

                    }
                }
            });
            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.endsWith('/detail.aspx')) {
            Wildberries__Показать_блок__Характеристики_и_описание__и_разместить_под_фото_товара()
            // Wildberries: отзывы товара
        } else if ((window.location.host === 'wildberries.ru' || window.location.host === 'www.wildberries.ru') && window.location.pathname.startsWith('/catalog/') && window.location.pathname.includes('/feedbacks')) {
            sortWildberriesReviews()
            // Wildberries Global: страница товара, но не отзывы
        } else if (window.location.host === 'global.wildberries.ru' && window.location.pathname.startsWith('/product/') && !window.location.pathname.includes('/feedbacks')) {
            // TODO:            // WildberriesGlobal__Показать_блок__Характеристики_и_описание__и_разместить_под_фото_товара()
            //             // ++ Создание ссылки с параметром-сортировкой отзывов: не сработало
            //             const СсылкаНаОтзывы = document.querySelector('a.reviews__view-all-btn')
            //             if (СсылкаНаОтзывы) {
            //                 if (!СсылкаНаОтзывы.href.includes('&sort=valueup'))
            //                     СсылкаНаОтзывы.href += '&sort=valueup'
            //             }
            //             else {
            //                 // Функция, которая будет вызываться при изменениях в DOM
            //                 const callback = function (mutationsList, observer) {
            //                     for (const mutation of mutationsList) {
            //                         // Проверяем, были ли добавлены новые узлы
            //                         if (mutation.type === 'childList') {
            //                             mutation.addedNodes.forEach(node => {
            //                                 // Проверяем, является ли добавленный узел элементом <a> с классом reviews__view-all-btn
            //                                 // if (node.nodeType === Node.ELEMENT_NODE && node.matches('a.reviews__view-all-btn')) {
            //                                 if (node.nodeType === Node.ELEMENT_NODE) {
            //                                     const кнопкаВсеОтзывы = node.querySelector('a.reviews__view-all-btn');
            //                                     if (кнопкаВсеОтзывы) {
            //                                         observer.disconnect();
            //                                         observeReviewsInnerClassChange(кнопкаВсеОтзывы);
            //                                         if (!кнопкаВсеОтзывы.href.includes('&sort=valueup')) {
            //                                             кнопкаВсеОтзывы.href += '&sort=valueup'
            //                                         }
            //                                     }
            //                                 }
            //                             });
            //                         }
            //                     }
            //                 };

            //                 // Создаем экземпляр MutationObserver
            //                 const observer = new MutationObserver(callback);

            //                 // Начинаем наблюдение за изменениями в DOM
            //                 observer.observe(document.body, {
            //                     childList: true, // Отслеживать добавление/удаление дочерних элементов
            //                     subtree: true,   // Отслеживать изменения во всем поддереве
            //                 });

            //                 // Функция для наблюдения за изменениями в атрибутах элемента
            //                 function observeReviewsInnerClassChange(кнопкаВсеОтзывы) {
            //                     const кнопкаВсеОтзывы_Родитель = кнопкаВсеОтзывы.parentNode

            //                     const observer = new MutationObserver((mutations) => {
            //                         mutations.forEach((mutation) => {
            //                             if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
            //                                 const reviewsInner = mutation.target;
            //                                 if (!reviewsInner.classList.contains('hide')) {
            //                                     // После нахождения элемента можно остановить наблюдение
            //                                     observer.disconnect();
            //                                     if (!кнопкаВсеОтзывы.href.includes('&sort=valueup')) {
            //                                         кнопкаВсеОтзывы.href += '&sort=valueup'
            //                                     }
            //                                 }
            //                             }
            //                         });
            //                     });

            //                     const config = { attributes: true };
            //                     observer.observe(кнопкаВсеОтзывы_Родитель, config);
            //                 }
            //             }
            //             // -- Создание ссылки с параметром-сортировкой: не сработало
        } else if (window.location.host === 'global.wildberries.ru' && window.location.pathname.startsWith('/product/') && window.location.pathname.includes('/feedbacks')) {
            WildberriesGlobal__Сортировка_отзывов_по_возрастанию()

        } else if (currentURL.includes('wildberries.ru/')) {
            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 ссылки
        }
        // Яндекс.Маркет: Страница карточки товара
        // else if (currentURL.pathname.startsWith('/product--') && currentURL.includes('&uniqueId=') && currentURL.includes('&do-waremd5=')) {
        // else if (currentURL.includes('market.yandex.ru/product--') && currentURL.includes('&uniqueId=') && currentURL.includes('&do-waremd5=')) {
        else if (window.location.host === 'market.yandex.ru' || window.location.host === 'market.yandex.com') {
            let факт_УдалениеБаннеров = false
            // Если условия выполняются - добавляем к адресу параметр и перезагружаем страницу с новым адресом, производящим сортировку рейтингов по возрастанию
            // Мобильная версия
            // Удаление предложения перейти на мобильное приложение
            function УдалениеБаннеров() {
                let webToAppBanner = document.getElementById('/content/header/headerAppDistributionBanner') || document.getElementById('HeaderAppDistributionBanner')
                if (webToAppBanner)
                    // webToAppBanner.style.display = 'none'
                    webToAppBanner.remove()
                // Баннер верхний
                document.getElementById('/content/header/headerPromo')?.remove()
                document.querySelector('div[data-apiary-widget-id="/content/header/headerPromo"]')?.remove()
                // Десктопная версия: баннер справа
                document.getElementById('/content/page/fancyPage/defaultPage/heroBannerCarousel')?.remove()
                // Баннер-карусель на главной странице
                if (window.location.pathname === '/') {
                    // document.querySelector('div[data-apiary-widget-name="@marketfront/HeroBannerCarousel"]')?.remove()
                    // Добавление кнопки "Реклама"
                    const EspeciallyForYou = CreateEspeciallyForYou('#e35539')
                    // let EspeciallyForYou_factView = false // факт вывода раскрывающегося блока рекламы
                    // Перенос верхнего баннера в блок Реклама
                    const targetNode = document.querySelector('div[data-apiary-widget-name="@marketfront/HeroBannerCarousel"]')
                    // 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) => {
                if (!факт_УдалениеБаннеров) {
                    факт_УдалениеБаннеров = true
                    УдалениеБаннеров()
                }
                for (let mutation of mutationsList) {
                    if (mutation.type === 'childList') {
                        mutation.addedNodes.forEach(node => {
                            if (node.nodeType === Node.ELEMENT_NODE && node.nodeName === 'DIV') {
                                // Удаление предложения перейти на мобильное приложение: на всякий случай любой из блоков
                                if (node.id === '/content/header/headerAppDistributionBanner' || node.id === 'headerAppDistributionBanner') {
                                    // node.style.display = 'none'
                                    node.remove()
                                }
                                // Баннер верхний
                                else if (node.id === '/content/header/headerPromo') {
                                    node.remove()
                                }
                                // Десктопная версия: баннер справа
                                else if (node.id === '/content/page/fancyPage/defaultPage/heroBannerCarousel') {
                                    node.remove()
                                }
                                // // Баннер-карусель на главной странице
                                // else if (window.location.pathname === '/' &&
                                //          node.dataset.apiaryWidgetName === '@marketfront/HeroBannerCarousel') {
                                //     node.remove()
                                // }
                            }
                        });

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

            // Страница карточки товара
            if (currentURL.includes('&uniqueId=') && currentURL.includes('&do-waremd5=')) {
                // сокрытие и перестановка мешающих блоков
                // Блок с: Ещё может подойти; Вам может понравиться
                const interval_ЕщёМожетПодойти_ВамМожетПонравиться = setInterval(() => {
                    // Ещё может подойти
                    // десктопная версия или мобильная версия
                    const ЕщёМожетПодойти = document.getElementById('/content/page/fancyPage/defaultPage/kkmCarousel') || document.getElementById('/content/page/fancyPage/defaultPage/kkmCommon/kkmRecommendations/kkmCarousel/content')
                    // Вам может понравиться
                    const ВамМожетПонравиться = document.getElementById('/content/page/fancyPage/defaultPage/madvIncutWrapper')

                    if (ЕщёМожетПодойти || ВамМожетПонравиться) {
                        // пока отключаю, потом буду сворачивать
                        clearInterval(interval_ЕщёМожетПодойти_ВамМожетПонравиться);

                        let UseDetails = true

                        // Дополнительная логика проверки:
                        if (UseDetails) {
                            UseDetails = false
                            // Если нужно остановить наблюдение в будущем:
                            // Но срабатывает не мгновенно - приходится использовать флаг UseDetails
                            // Создать элемент <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);

                            const div_Отзывы = document.getElementById('/content/page/fancyPage/defaultPage/reviewBlock') || document.querySelector('div[data-auto="product-card-ugc-section"]')
                            // Добавить созданный элемент <details> перед элементом div_Отзывы
                            div_Отзывы.insertAdjacentElement('beforebegin', details)

                            // Переместить существующий элемент ЕщёМожетПодойти внутрь <details>
                            if (ЕщёМожетПодойти)
                                details.appendChild(ЕщёМожетПодойти)
                            // Переместить существующий элемент ВамМожетПонравиться внутрь <details>
                            if (ВамМожетПонравиться)
                                details.appendChild(ВамМожетПонравиться)
                        }

                    }

                }, 200);

                // Получение информации из блока "Все характеристики" для десктопной версии
                // В десктопной версии присутствует нажимаемый span-ссылка
                const targetSpan = document.getElementById('/content/page/fancyPage/defaultPage/productSpecsList')?.querySelector('span[aria-label="Все характеристики"]')
                // Проверка найден ли span - значит, версия десктопная
                if (targetSpan) {
                    // элемент по ширине страницы или её левой части, до которого будет вставка блоков "О товаре" и "Общие характеристики"
                    const kitsOfferSet = document.getElementById('/content/page/fancyPage/defaultPage/kitsOfferSet');
                    if (kitsOfferSet) {
                        // О товаре
                        let О_Товаре = document.getElementById('/content/page/fancyPage/defaultPage/specFridge')?.querySelector('div[data-zone-name="MarketProductDescription"]')?.cloneNode(true);

                        // Общие характеристики
                        let ОбщиеХарактеристики = document.getElementById('/content/page/fancyPage/defaultPage/specFridge')?.querySelector('div[data-zone-name="ProductSpecsList"]')?.cloneNode(true);
                        if (О_Товаре || ОбщиеХарактеристики) {
                            if (О_Товаре) kitsOfferSet.insertAdjacentElement('beforebegin', О_Товаре)
                            if (ОбщиеХарактеристики) kitsOfferSet.insertAdjacentElement('beforebegin', ОбщиеХарактеристики)
                        }
                        else {
                            // Настраиваем наблюдение за изменениями в документе
                            const observer_specFridge = 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.getAttribute('data-zone-name') === 'MarketProductDescription') {
                                                    О_Товаре = node.cloneNode(true);
                                                    // почему-то не отслеживается появление
                                                    ОбщиеХарактеристики = document.getElementById('/content/page/fancyPage/defaultPage/specFridge')?.querySelector('div[data-zone-name="ProductSpecsList"]')?.cloneNode(true);
                                                }
                                                else if (node.getAttribute('data-zone-name') === 'ProductSpecsList') {
                                                    ОбщиеХарактеристики = node.cloneNode(true);
                                                }
                                                if (О_Товаре && ОбщиеХарактеристики) {
                                                    observer_specFridge.disconnect()
                                                }
                                            }
                                        });

                                    }
                                }
                                if (О_Товаре || ОбщиеХарактеристики) {
                                    if (О_Товаре) {
                                        const О_Товаре_productDescription = О_Товаре.querySelector('div[aria-label="product-description"]');
                                        if (О_Товаре_productDescription)
                                            О_Товаре_productDescription.style.maxHeight = 'unset'
                                        kitsOfferSet.insertAdjacentElement('beforebegin', О_Товаре)
                                    }
                                    if (ОбщиеХарактеристики) kitsOfferSet.insertAdjacentElement('beforebegin', ОбщиеХарактеристики)
                                    document.querySelector('div[data-apiary-widget-name="@light/StickyFridgeContent"]')?.
                                    nextElementSibling?.
                                    querySelector('button')?.
                                    click()
                                }


                            });
                            const observer_config_specFridge = { attributes: true, childList: true, subtree: true }
                            observer_specFridge.observe(document.getElementById('/content/page/fancyPage/defaultPage/specFridge'), observer_config_specFridge)
                            targetSpan.click()
                        }
                    }
                }
            }
        }
    }

    // Wildberries: определение совершения перехода на карточку товара с разделом отзывов
    // перехват событияй истории (кнопок назад-вперёд)
    window.onpopstate = () => {
        // получаем текущий адрес страницы
        // Wildberries
        if ((window.location.host === 'wildberries.ru' || window.location.host === 'www.wildberries.ru' || window.location.host === 'global.wildberries.ru') && new URL(window.location.href).pathname.startsWith('/catalog/') && window.location.href.includes('/feedbacks')) {
            sortWildberriesReviews();
            if (new URL(window.location.href).pathname.endsWith('/detail.aspx'))
                Wildberries__Показать_блок__Характеристики_и_описание__и_разместить_под_фото_товара()
        }
        else if (window.location.host === 'global.wildberries.ru' && window.location.pathname.startsWith('/product/') && window.location.pathname.includes('/feedbacks')) {
            WildberriesGlobal__Сортировка_отзывов_по_возрастанию()
        }
        // Яндекс.Маркет
        else if ((window.location.host === 'market.yandex.ru' || window.location.host === 'market.yandex.com') && new URL(window.location.href).pathname.startsWith('/product--') && window.location.href.includes('&uniqueId=') && window.location.href.includes('&do-waremd5=')) {
            // Сортировать на карточке товара нет возможсноти и смысла - отзывы по полезности вполне объективны
            Яндекс_Маркет__Показать_блок__Характеристики_и_описание__и_разместить_под_фото_товара()
        }
    };

    const originalPushState = history.pushState;
    history.pushState = function (state, ...args) {
        originalPushState.apply(this, [state, ...args]);
        // Вызываем функцию сортировки после пуша состояния
        if (window.location.host === 'wildberries.ru' || window.location.host === 'www.wildberries.ru') {
            sortWildberriesReviews();
        }
        // if (new URL(window.location.href).pathname.endsWith('/detail.aspx'))
        //     Wildberries__Показать_блок__Характеристики_и_описание__и_разместить_под_фото_товара()
        else if (window.location.host === 'global.wildberries.ru' && window.location.pathname.startsWith('/product/') && window.location.pathname.includes('/feedbacks')) {
            WildberriesGlobal__Сортировка_отзывов_по_возрастанию()
        }
    };

    history.replaceState = new Proxy(history.replaceState, {
        apply: function(target, thisArg, argArray) {
            target.apply(thisArg, argArray);
            if (window.location.host === 'wildberries.ru' || window.location.host === 'www.wildberries.ru') {
                sortWildberriesReviews();
                if (new URL(window.location.href).pathname.endsWith('/detail.aspx'))
                    Wildberries__Показать_блок__Характеристики_и_описание__и_разместить_под_фото_товара()
            }
        }
    });

    if (config.isRunningAsExtension) {
        // событие изменения адреса данной вкладки
        api.runtime.onMessage.addListener((request, sender, sendResponse) => {
            // получаем текущий адрес страницы
            // Wildberries
            if ((window.location.host === 'wildberries.ru' || window.location.host === 'www.wildberries.ru') && new URL(request.url).pathname.startsWith('/catalog/') && request.url.includes('/feedbacks')) {
                sortWildberriesReviews();
                if (new URL(window.location.href).pathname.endsWith('/detail.aspx'))
                    Wildberries__Показать_блок__Характеристики_и_описание__и_разместить_под_фото_товара()
            }
            // Яндекс.Маркет
            else if ((window.location.host === 'market.yandex.ru' || window.location.host === 'market.yandex.com') && new URL(window.location.href).pathname.startsWith('/product--') && window.location.href.includes('&uniqueId=') && window.location.href.includes('&do-waremd5=')) {
                // Сортировать на карточке товара нет возможсноти и смысла - отзывы по полезности вполне объективны
                Яндекс_Маркет__Показать_блок__Характеристики_и_описание__и_разместить_под_фото_товара()
            }
        });
    }

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



    // 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(summary_font_color = '#ff0000') {
        // Создание стилей с помощью 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: ${summary_font_color}; /* Изменение цвета текста */
        display: flex; /*использовали display: flex и align-items: center для summary, чтобы выровнять треугольник и текст по вертикали.*/
        align-items: center;
                }
    summary::before {
        content: '▶'; /* Треугольник вершиной вправо */
        margin-right: 8px;
        font-size: 12px;
    }
    details[open] summary::before {
        content: '▼'; /* Треугольник вершиной вниз */
    }
                .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
    }

})();