Select Specific Approval Branches & Custom City Sets

Adds buttons to select predefined test branches or a custom set of cities (case-insensitive), with multi-line error reporting for unactivated/unfound cities.

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Select Specific Approval Branches & Custom City Sets
// @namespace    http://tampermonkey.net/
// @version      2.7
// @description  Adds buttons to select predefined test branches or a custom set of cities (case-insensitive), with multi-line error reporting for unactivated/unfound cities.
// @author       Your Name
// @match        https://dodopizza.design-terminal.io/*
// @grant        none
// @license MIT
// ==/UserScript==

(function () {
    'use strict';

    const branchNames = [
        '.Branch All Global RU',
        '.Branch – b. Группа СПБ',
        '.Branch – a. Группа Москва'
    ];

    function addButton() {
        const summaryElements = document.querySelectorAll('summary');
        let targetSummary = null;

        summaryElements.forEach(summary => {
            if (summary.textContent.trim().startsWith('Russia 🇷🇺')) {
                targetSummary = summary;
            }
        });

        if (!targetSummary) {
            return;
        }

        // --- Первая кнопка: Выбрать только тестовые города ---
        const testCitiesButtonId = 'select-specific-branches-button';
        const defaultTestCitiesButtonText = 'Select test cities only';

        if (!document.querySelector(`#${testCitiesButtonId}`)) {
            const button = document.createElement('button');
            button.id = testCitiesButtonId;
            button.textContent = defaultTestCitiesButtonText;
            button.style.marginLeft = '0.4em';

            button.addEventListener('click', () => {
                button.disabled = true;
                button.textContent = 'Processing...';

                setTimeout(() => {
                    const checkboxes = document.querySelectorAll('label > input[type="checkbox"][name="branchIds"]');
                    if (checkboxes.length === 0) {
                        button.textContent = 'Checkboxes not found';
                        button.disabled = false;
                        setTimeout(() => { button.textContent = defaultTestCitiesButtonText; }, 1000);
                        return;
                    }

                    checkboxes.forEach(checkbox => {
                        if (checkbox.checked) checkbox.click();
                    });

                    let successfullySelectedCount = 0;
                    checkboxes.forEach(checkbox => {
                        const labelElement = checkbox.parentElement;
                        if (labelElement) {
                            const labelText = labelElement.textContent.trim();
                            if (branchNames.includes(labelText)) {
                                if (!checkbox.checked) checkbox.click();
                                if (checkbox.checked) successfullySelectedCount++;
                            }
                        }
                    });

                    if (successfullySelectedCount === branchNames.length) {
                        button.textContent = `Selected: ${successfullySelectedCount} (all)`;
                    } else {
                        button.textContent = `Selected: ${successfullySelectedCount} of ${branchNames.length}`;
                    }
                    button.disabled = false;
                    setTimeout(() => { button.textContent = defaultTestCitiesButtonText; }, 1000);
                }, 20); // 20ms delay
            });
            targetSummary.appendChild(button);
        }

        // --- Вторая кнопка: Выбрать набор городов и связанные элементы ---
        const selectCustomSetButtonId = 'select-custom-set-button';
        const customCitiesContainerId = 'custom-cities-input-container';
        const citiesTextareaId = 'custom-cities-textarea';
        const enableCustomCitiesButtonId = 'enable-custom-cities-button';
        const customCitiesErrorLogId = 'custom-cities-error-log'; // ID для элемента ошибок
        const defaultEnableCustomCitiesButtonText = 'Включить эти города';

        if (!document.querySelector(`#${selectCustomSetButtonId}`)) {
            const selectCustomSetButton = document.createElement('button');
            selectCustomSetButton.id = selectCustomSetButtonId;
            selectCustomSetButton.textContent = 'Select a set of cities';
            selectCustomSetButton.style.marginLeft = '0.4em';
            selectCustomSetButton.style.marginTop = '0.2em';

            const customCitiesContainer = document.createElement('div');
            customCitiesContainer.id = customCitiesContainerId;
            customCitiesContainer.style.display = 'none';
            customCitiesContainer.style.marginTop = '0.5em';
            customCitiesContainer.style.padding = '0.5em';
            customCitiesContainer.style.border = '1px solid #ccc';
            customCitiesContainer.style.borderRadius = '4px';

            const textareaLabel = document.createElement('div');
            textareaLabel.innerHTML = 'Поместите сюда список городов (один город на строку), скопированный из таблицы.';
            textareaLabel.style.marginBottom = '0.5em';

            const citiesTextarea = document.createElement('textarea');
            citiesTextarea.id = citiesTextareaId;
            citiesTextarea.rows = 5;
            citiesTextarea.placeholder = 'Город1-1\nГород2-1\nГород2-2...';
            citiesTextarea.style.width = 'calc(100% - 12px)'; // -12px to account for padding/border of parent
            citiesTextarea.style.marginBottom = '0.5em';

            const enableCustomCitiesButton = document.createElement('button');
            enableCustomCitiesButton.id = enableCustomCitiesButtonId;
            enableCustomCitiesButton.textContent = defaultEnableCustomCitiesButtonText;

            // Элемент для вывода ошибок
            const errorLogElement = document.createElement('div');
            errorLogElement.id = customCitiesErrorLogId;
            errorLogElement.style.color = 'red';
            errorLogElement.style.marginTop = '0.5em';
            errorLogElement.style.display = 'none'; // Изначально скрыт

            customCitiesContainer.appendChild(textareaLabel);
            customCitiesContainer.appendChild(citiesTextarea);
            customCitiesContainer.appendChild(enableCustomCitiesButton);
            customCitiesContainer.appendChild(errorLogElement); // Добавляем элемент ошибок в контейнер

            selectCustomSetButton.addEventListener('click', () => {
                const checkboxes = document.querySelectorAll('label > input[type="checkbox"][name="branchIds"]');
                checkboxes.forEach(checkbox => {
                    const labelElement = checkbox.parentElement;
                    if (labelElement) {
                        const labelText = labelElement.textContent.trim();
                        if (checkbox.checked && !branchNames.includes(labelText)) {
                            checkbox.click();
                        }
                    }
                });
                customCitiesContainer.style.display = (customCitiesContainer.style.display === 'none' ? 'block' : 'none');
            });

            enableCustomCitiesButton.addEventListener('click', function() {
                const buttonElement = this;
                buttonElement.disabled = true;
                buttonElement.textContent = 'Processing...';
                errorLogElement.textContent = ''; // Очищаем предыдущие ошибки
                errorLogElement.style.display = 'none'; // Скрываем область ошибок

                setTimeout(() => {
                    const cityListText = citiesTextarea.value;
                    const citiesToEnableInput = cityListText.split('\n')
                                               .map(name => name.trim())
                                               .filter(name => name.length > 0);
                    
                    // Обрабатываем уникальные города, сохраняя оригинал и версию в нижнем регистре
                    const cityMap = new Map(); // Для уникальности по нижнему регистру, сохраняя первый оригинал
                    citiesToEnableInput.forEach(name => {
                        const lowerName = name.toLowerCase();
                        if (!cityMap.has(lowerName)) {
                            cityMap.set(lowerName, { original: name, lower: lowerName });
                        }
                    });
                    const uniqueCitiesToProcess = Array.from(cityMap.values());

                    if (uniqueCitiesToProcess.length === 0) {
                        buttonElement.textContent = 'Список пуст';
                        buttonElement.disabled = false;
                        setTimeout(() => { buttonElement.textContent = defaultEnableCustomCitiesButtonText; }, 1500);
                        return;
                    }

                    const allCheckboxes = document.querySelectorAll('label > input[type="checkbox"][name="branchIds"]');
                    
                    // Шаг 1: Попытаться активировать все города из списка (сравнение без учета регистра)
                    uniqueCitiesToProcess.forEach(cityObj => {
                        allCheckboxes.forEach(checkbox => {
                            const labelElement = checkbox.parentElement;
                            if (labelElement) {
                                const labelTextLower = labelElement.textContent.trim().toLowerCase();
                                if (labelTextLower === cityObj.lower) {
                                    if (!checkbox.checked) {
                                        checkbox.click();
                                    }
                                }
                            }
                        });
                    });

                    // Шаг 2: Проверить, какие города из *уникального* списка действительно включены (сравнение без учета регистра)
                    let successfullyEnabledCount = 0;
                    const notFoundOrNotEnabledCities = [];

                    uniqueCitiesToProcess.forEach(cityObjFromList => {
                        let foundAndEnabledThisTime = false;
                        allCheckboxes.forEach(checkbox => {
                            if (checkbox.checked) {
                                const labelElement = checkbox.parentElement;
                                if (labelElement) {
                                    const labelTextLower = labelElement.textContent.trim().toLowerCase();
                                    if (labelTextLower === cityObjFromList.lower) {
                                        foundAndEnabledThisTime = true;
                                    }
                                }
                            }
                        });
                        if (foundAndEnabledThisTime) {
                            successfullyEnabledCount++;
                        } else {
                            let checkboxExists = false;
                            allCheckboxes.forEach(cb => {
                                const lbl = cb.parentElement;
                                if (lbl && lbl.textContent.trim().toLowerCase() === cityObjFromList.lower) {
                                    checkboxExists = true;
                                }
                            });
                            notFoundOrNotEnabledCities.push(cityObjFromList.original + (checkboxExists ? " (не вкл.)" : " (не найден)"));
                        }
                    });

                    buttonElement.textContent = `Включено: ${successfullyEnabledCount} из ${uniqueCitiesToProcess.length}`;

                    if (notFoundOrNotEnabledCities.length > 0) {
                        errorLogElement.innerHTML = `Эти рестораны из списка не были включены:<br>${notFoundOrNotEnabledCities.join('<br>')}`;
                        errorLogElement.style.display = 'block'; // Показываем ошибки
                    } else {
                        errorLogElement.textContent = ''; // На всякий случай, если что-то осталось
                        errorLogElement.style.display = 'none';
                    }

                    buttonElement.disabled = false;
                    setTimeout(() => {
                        buttonElement.textContent = defaultEnableCustomCitiesButtonText;
                        // Ошибки больше не скрываем и не очищаем здесь, они остаются до следующего нажатия
                    }, 2500);
                }, 50); // 50ms delay
            });
            
            const firstButton = document.querySelector(`#${testCitiesButtonId}`);
            if (firstButton && firstButton.parentNode === targetSummary) {
                firstButton.insertAdjacentElement('afterend', selectCustomSetButton);
                selectCustomSetButton.insertAdjacentElement('afterend', customCitiesContainer);
            } else {
                 targetSummary.appendChild(selectCustomSetButton);
                 targetSummary.appendChild(customCitiesContainer);
            }
        }

        if (document.querySelector(`#${testCitiesButtonId}`) && document.querySelector(`#${selectCustomSetButtonId}`)) {
            clearInterval(interval);
            console.log('Tampermonkey: All city selection buttons added successfully.');
        }
    }

    const interval = setInterval(addButton, 500);
})();