Открыть меню
Переключить меню настроек
Открыть персональное меню
Вы не представились системе
Ваш IP-адрес будет виден всем, если вы внесёте какие-либо изменения.

MediaWiki:Common.js: различия между версиями

Страница интерфейса MediaWiki
Нет описания правки
Метка: отменено
Нет описания правки
Метка: отменено
Строка 174: Строка 174:
                     }
                     }
                     setTimeout(function () {
                     setTimeout(function () {
                         if (run())
                         if (run()) {
                             console.log(
                             console.log(
                                 "[LawTooltips] Инициализация после 800ms",
                                 "[LawTooltips] Инициализация после 800ms",
                             );
                             );
                         else
                         } else {
                             console.warn(
                             console.warn(
                                 "[LawTooltips] Данные законов не найдены после всех попыток",
                                 "[LawTooltips] Данные законов не найдены после всех попыток",
                             );
                             );
                        }
                     }, 500);
                     }, 500);
                 }, 300);
                 }, 300);

Версия от 18:33, 6 февраля 2026

(function () {
    "use strict";

    window.MediaWikiTooltips = {
        loaded: false,
        callbacks: [],

        load: function (callback) {
            if (this.loaded && window.tippy) {
                callback();
                return;
            }

            this.callbacks.push(callback);

            if (this.loading) return;
            this.loading = true;

            var self = this;
            var popperScript = document.createElement("script");
            popperScript.src =
                "https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.11.8/umd/popper.min.js";
            popperScript.onload = function () {
                var tippyScript = document.createElement("script");
                tippyScript.src =
                    "https://cdnjs.cloudflare.com/ajax/libs/tippy.js/6.3.7/tippy-bundle.umd.min.js";
                tippyScript.onload = function () {
                    self.loaded = true;
                    self.loading = false;
                    self.callbacks.forEach(function (cb) {
                        cb();
                    });
                    self.callbacks = [];
                };
                document.head.appendChild(tippyScript);
            };
            document.head.appendChild(popperScript);

            var tippyCSS = document.createElement("link");
            tippyCSS.rel = "stylesheet";
            tippyCSS.href =
                "https://cdnjs.cloudflare.com/ajax/libs/tippy.js/6.3.7/tippy.css";
            document.head.appendChild(tippyCSS);
        },
    };

    var SidebarModule = {
        init: function () {
            var buttons = document.querySelectorAll(".боковая-панель-кнопка");
            var sections = document.querySelectorAll(".боковая-панель-раздел");

            if (buttons.length === 0) return;

            buttons.forEach(function (button) {
                button.addEventListener("click", function () {
                    var targetId = this.dataset.target;

                    buttons.forEach(function (btn) {
                        btn.classList.remove("active");
                    });
                    this.classList.add("active");

                    sections.forEach(function (section) {
                        section.classList.remove("default");
                    });
                    var targetSection = document.getElementById(targetId);
                    if (targetSection) {
                        targetSection.classList.add("default");
                    }
                });
            });

            buttons[0].click();
        },
    };

    var AccessTooltipsModule = {
        init: function () {
            var containers = document.querySelectorAll(".допуск-контейнер");
            if (containers.length === 0) return;

            MediaWikiTooltips.load(function () {
                containers.forEach(function (container) {
                    var contentElement =
                        container.querySelector(".допуск-подсказка");
                    if (!contentElement) return;

                    var content = contentElement.innerHTML;
                    tippy(container, {
                        content: content,
                        allowHTML: true,
                        interactive: true,
                        placement: "auto",
                        maxWidth: 500,
                        theme: "dark",
                        arrow: true,
                        duration: [200, 200],
                        popperOptions: {
                            modifiers: [
                                {
                                    name: "preventOverflow",
                                    options: { padding: 8 },
                                },
                                {
                                    name: "flip",
                                    options: {
                                        fallbackPlacements: [
                                            "top",
                                            "bottom",
                                            "right",
                                            "left",
                                        ],
                                    },
                                },
                            ],
                        },
                    });
                });
            });
        },
    };

    var LawTooltipsModule = {
        init: function () {
            console.log("[LawTooltips] init()");
            var tableCells = document.querySelectorAll(
                ".law-tooltips td, .law-tooltips th",
            );
            console.log(
                "[LawTooltips] .law-tooltips ячеек:",
                tableCells.length,
            );
            if (tableCells.length === 0) {
                console.warn("[LawTooltips] Нет ячеек .law-tooltips — выход");
                return;
            }

            function run() {
                console.log("[LawTooltips] run() — извлечение данных...");
                var lawData = LawTooltipsModule.extractLawData();
                var count = Object.keys(lawData).length;
                console.log(
                    "[LawTooltips] Загружено записей законов:",
                    count,
                    count
                        ? Object.keys(lawData).slice(0, 10).join(", ") +
                              (count > 10 ? "..." : "")
                        : "",
                );
                if (count > 0) {
                    LawTooltipsModule.initCellTooltips(tableCells, lawData);
                    return true;
                }
                return false;
            }

            if (typeof MediaWikiTooltips === "undefined") {
                console.error(
                    "[LawTooltips] MediaWikiTooltips не найден — тултипы не загрузятся",
                );
                run();
                return;
            }
            MediaWikiTooltips.load(function () {
                console.log("[LawTooltips] MediaWikiTooltips.load вызван");
                if (run()) {
                    console.log("[LawTooltips] Инициализация с первой попытки");
                    return;
                }
                setTimeout(function () {
                    if (run()) {
                        console.log("[LawTooltips] Инициализация после 300ms");
                        return;
                    }
                    setTimeout(function () {
                        if (run()) {
                            console.log(
                                "[LawTooltips] Инициализация после 800ms",
                            );
                        } else {
                            console.warn(
                                "[LawTooltips] Данные законов не найдены после всех попыток",
                            );
                        }
                    }, 500);
                }, 300);
            });
        },

        extractLawData: function () {
            var lawData = {};
            var containers = document.querySelectorAll(".mw-collapsible");
            console.log(
                "[LawTooltips] extractLawData: коллапсибл-блоков:",
                containers.length,
            );
            containers.forEach(function (block) {
                var content = block.querySelector(".mw-collapsible-content");
                if (content && block.classList.contains("mw-collapsed")) {
                    block.classList.remove("mw-collapsed");
                    var toggle = content.querySelector(
                        ".mw-collapsible-toggle",
                    );
                    if (toggle) toggle.setAttribute("aria-expanded", "true");
                }
            });

            var detailTables = document.querySelectorAll(
                ".mw-collapsible-content table",
            );
            console.log(
                "[LawTooltips] extractLawData: таблиц в .mw-collapsible-content:",
                detailTables.length,
            );
            detailTables.forEach(function (table, tableIndex) {
                if (table.classList.contains("law-tooltips")) {
                    console.log(
                        "[LawTooltips] extractLawData: таблица",
                        tableIndex,
                        "— пропуск (law-tooltips)",
                    );
                    return;
                }
                var rows = table.querySelectorAll("tr");

                rows.forEach(function (row) {
                    var cells = row.querySelectorAll("td");
                    if (cells.length < 3) return;

                    var crimeCell = cells[0];
                    var descriptionCell = cells[1];
                    var exampleCell = cells[2];

                    var anchor = crimeCell.querySelector("[id]");
                    if (!anchor) return;

                    var lawCode = anchor.id;
                    var titleElement = crimeCell.querySelector("b");
                    if (!titleElement || !lawCode.match(/^\d{3}$/)) return;

                    var titleText = titleElement.textContent.trim();
                    var lawTitle = titleText
                        .replace(/^\d{3}\s*/, "")
                        .replace(/^\d{3}/, "")
                        .trim();
                    var description = descriptionCell.innerHTML.trim();

                    var examples = [];
                    var exampleItems = exampleCell.querySelectorAll("li");
                    exampleItems.forEach(function (item) {
                        var html = item.innerHTML
                            .trim()
                            .replace(/<br\s*\/?>/gi, "");
                        if (html) examples.push(html);
                    });

                    lawData[lawCode] = {
                        title: lawTitle,
                        description: description,
                        examples: examples,
                    };
                });
            });

            console.log(
                "[LawTooltips] extractLawData: итого кодов:",
                Object.keys(lawData).length,
            );
            return lawData;
        },

        createTooltipContent: function (lawCode, lawData) {
            var data = lawData[lawCode];
            if (!data) return null;

            var html = '<div class="law-tooltip">';
            html +=
                '<h4 class="law-tooltip-title">' +
                lawCode +
                " - " +
                data.title +
                "</h4>";
            html +=
                '<p class="law-tooltip-description">' +
                data.description +
                "</p>";

            if (data.examples && data.examples.length > 0) {
                html += '<div class="law-tooltip-examples">';
                html += "<strong>Примеры:</strong><ul>";
                data.examples.slice(0, 5).forEach(function (example) {
                    html += "<li>" + example + "</li>";
                });
                html += "</ul></div>";
            }
            html += "</div>";

            return html;
        },

        initCellTooltips: function (tableCells, lawData) {
            var withLink = 0,
                withMatch = 0,
                withContent = 0,
                tooltipsCreated = 0;
            tableCells.forEach(function (cell) {
                var link = cell.querySelector('a[href*="#"]');
                if (!link) return;
                withLink++;

                var href = link.getAttribute("href");
                var match = href.match(/#(\d{3})/);
                if (!match) return;
                withMatch++;

                var lawCode = match[1];
                var tooltipContent = LawTooltipsModule.createTooltipContent(
                    lawCode,
                    lawData,
                );
                if (!tooltipContent) return;
                withContent++;

                cell.classList.add("law-cell-with-tooltip");
                tooltipsCreated++;

                cell.addEventListener("click", function (e) {
                    e.preventDefault();
                    window.location.hash = lawCode;
                });

                if (typeof tippy === "undefined") {
                    console.error(
                        "[LawTooltips] tippy не найден — подключи библиотеку Tippy.js",
                    );
                    return;
                }
                tippy(cell, {
                    content: tooltipContent,
                    allowHTML: true,
                    interactive: true,
                    placement: "top",
                    maxWidth: 400,
                    theme: "law-theme",
                    arrow: true,
                    duration: [200, 150],
                    delay: [0, 50],
                    appendTo: document.body,
                    boundary: "viewport",
                    popperOptions: {
                        strategy: "fixed",
                        modifiers: [
                            {
                                name: "preventOverflow",
                                options: {
                                    boundary: "viewport",
                                    padding: 20,
                                    altAxis: true,
                                    altBoundary: true,
                                },
                            },
                            {
                                name: "flip",
                                options: {
                                    fallbackPlacements: [
                                        "bottom",
                                        "left",
                                        "right",
                                    ],
                                },
                            },
                            {
                                name: "computeStyles",
                                options: { adaptive: false },
                            },
                        ],
                    },
                    onShow: function (instance) {
                        document
                            .querySelectorAll("[data-tippy-root]")
                            .forEach(function (tooltip) {
                                if (
                                    tooltip._tippy &&
                                    tooltip._tippy !== instance
                                ) {
                                    tooltip._tippy.hide();
                                }
                            });
                    },
                });
            });
            console.log(
                "[LawTooltips] initCellTooltips: ячеек с ссылкой",
                withLink,
                "| с #XXX",
                withMatch,
                "| с данными",
                withContent,
                "| тултипов создано",
                tooltipsCreated,
            );
        },
    };

    var DataTooltipsModule = {
        init: function () {
            var elements = document.querySelectorAll(
                ".data-tooltip[data-text]",
            );
            if (elements.length === 0) return;

            MediaWikiTooltips.load(function () {
                elements.forEach(function (element) {
                    var tooltipText = element.getAttribute("data-text");
                    if (!tooltipText || !tooltipText.trim()) return;

                    tippy(element, {
                        content: tooltipText,
                        allowHTML: true,
                        interactive: false,
                        placement: "top",
                        maxWidth: 300,
                        theme: "data-tooltip-theme",
                        arrow: true,
                        duration: [200, 150],
                        delay: [0, 50],
                    });
                });
            });

            var observer = new MutationObserver(function (mutations) {
                var shouldReinit = false;
                mutations.forEach(function (mutation) {
                    mutation.addedNodes.forEach(function (node) {
                        if (node.nodeType === 1) {
                            if (
                                node.classList &&
                                node.classList.contains("data-tooltip") &&
                                node.hasAttribute("data-text")
                            ) {
                                shouldReinit = true;
                            } else if (node.querySelectorAll) {
                                var newElements = node.querySelectorAll(
                                    ".data-tooltip[data-text]",
                                );
                                if (newElements.length > 0) {
                                    shouldReinit = true;
                                }
                            }
                        }
                    });
                });

                if (shouldReinit) {
                    setTimeout(function () {
                        DataTooltipsModule.init();
                    }, 100);
                }
            });

            observer.observe(document.body, {
                childList: true,
                subtree: true,
            });
        },
    };

    var CopyTextModule = {
        init: function () {
            CopyTextModule.initDirectElements();
            CopyTextModule.initAutoContainers();
        },

        initDirectElements: function () {
            var elements = document.querySelectorAll(".copyable-text");
            if (elements.length === 0) return;

            elements.forEach(function (element) {
                CopyTextModule.cleanPreContent(element);
                CopyTextModule.setupElement(element);
            });
        },

        initAutoContainers: function () {
            var containers = document.querySelectorAll(
                ".copyable-pre-container",
            );
            if (containers.length === 0) return;

            containers.forEach(function (container) {
                CopyTextModule.processContainerPre(container);
            });

            // Наблюдатель за динамически появляющимися элементами
            var observer = new MutationObserver(function (mutations) {
                mutations.forEach(function (mutation) {
                    mutation.addedNodes.forEach(function (node) {
                        if (node.nodeType === 1) {
                            // Проверяем сам элемент
                            if (node.tagName === "PRE") {
                                var container = node.closest(
                                    ".copyable-pre-container",
                                );
                                if (
                                    container &&
                                    !node.classList.contains("copyable-text")
                                ) {
                                    node.classList.add("copyable-text");
                                    CopyTextModule.cleanPreContent(node);
                                    CopyTextModule.setupElement(node);
                                }
                            }
                            // Проверяем дочерние элементы
                            else if (node.querySelectorAll) {
                                var containers = node.querySelectorAll(
                                    ".copyable-pre-container",
                                );
                                containers.forEach(function (container) {
                                    CopyTextModule.processContainerPre(
                                        container,
                                    );
                                });

                                // Также проверяем pre внутри уже существующих контейнеров
                                var preElements = node.querySelectorAll(
                                    ".copyable-pre-container pre",
                                );
                                preElements.forEach(function (pre) {
                                    if (
                                        !pre.classList.contains("copyable-text")
                                    ) {
                                        pre.classList.add("copyable-text");
                                        CopyTextModule.cleanPreContent(pre);
                                        CopyTextModule.setupElement(pre);
                                    }
                                });
                            }
                        }
                    });

                    // Обрабатываем изменения атрибутов (например, style="display: none" -> "")
                    if (
                        mutation.type === "attributes" &&
                        mutation.attributeName === "style"
                    ) {
                        var target = mutation.target;
                        if (target.style.display !== "none") {
                            var containers = target.querySelectorAll(
                                ".copyable-pre-container",
                            );
                            containers.forEach(function (container) {
                                CopyTextModule.processContainerPre(container);
                            });
                        }
                    }
                });
            });

            observer.observe(document.body, {
                childList: true,
                subtree: true,
                attributes: true,
                attributeFilter: ["style"],
            });
        },

        processContainerPre: function (container) {
            var preElements = container.querySelectorAll("pre");
            preElements.forEach(function (pre) {
                if (!pre.classList.contains("copyable-text")) {
                    pre.classList.add("copyable-text");
                    CopyTextModule.cleanPreContent(pre);
                    CopyTextModule.setupElement(pre);
                }
            });
        },

        cleanPreContent: function (preElement) {
            var text = preElement.textContent || preElement.innerText;

            var cleanedText = text
                .split("\n")
                .map(function (line) {
                    return line.replace(/^\s*\|\s*/, "");
                })
                .join("\n");

            if (cleanedText !== text) {
                preElement.textContent = cleanedText;
            }
        },

        setupElement: function (element) {
            element.style.cursor = "pointer";
            element.addEventListener("click", CopyTextModule.handleClick);

            var isIOS =
                /iPad|iPhone|iPod/.test(navigator.userAgent) &&
                !window.MSStream;
            if (isIOS) {
                element.style.webkitUserSelect = "text";
                element.style.userSelect = "text";
            }
        },

        handleClick: function (e) {
            e.preventDefault();

            var element = this;
            var textToCopy = element.textContent;

            if (navigator.clipboard && window.isSecureContext) {
                navigator.clipboard
                    .writeText(textToCopy)
                    .then(function () {
                        CopyTextModule.showNotification(element);
                    })
                    .catch(function (err) {
                        console.error("Ошибка при копировании: ", err);
                        CopyTextModule.fallbackCopy(textToCopy, element);
                    });
            } else {
                CopyTextModule.fallbackCopy(textToCopy, element);
            }

            element.classList.add("copying");
            setTimeout(function () {
                element.classList.remove("copying");
            }, 200);
        },

        fallbackCopy: function (text, element) {
            var textArea = document.createElement("textarea");
            textArea.value = text;
            textArea.style.position = "fixed";
            textArea.style.top = "-9999px";
            textArea.style.left = "-9999px";
            textArea.style.width = "2em";
            textArea.style.height = "2em";
            textArea.style.padding = "0";
            textArea.style.border = "none";
            textArea.style.outline = "none";
            textArea.style.boxShadow = "none";
            textArea.style.background = "transparent";

            document.body.appendChild(textArea);
            textArea.focus();
            textArea.select();

            try {
                var successful = document.execCommand("copy");
                if (successful) {
                    CopyTextModule.showNotification(element);
                } else {
                    console.error("Не удалось скопировать текст");
                }
            } catch (err) {
                console.error("Ошибка при копировании: ", err);
            }

            document.body.removeChild(textArea);
        },

        showNotification: function (element) {
            var existingNotifications =
                document.querySelectorAll(".copy-notification");
            existingNotifications.forEach(function (notification) {
                notification.remove();
            });

            var notification = document.createElement("div");
            notification.className = "copy-notification";
            notification.textContent = "Текст скопирован!";
            document.body.appendChild(notification);

            var rect = element.getBoundingClientRect();
            var isMobile = window.innerWidth <= 768;

            if (isMobile) {
                notification.style.position = "fixed";
                notification.style.top = "20px";
                notification.style.left = "50%";
                notification.style.transform =
                    "translateX(-50%) translateY(-10px)";
                notification.style.zIndex = "10000";
            } else {
                notification.style.position = "absolute";
                notification.style.top = rect.top + window.scrollY - 40 + "px";
                notification.style.left = rect.left + window.scrollX + "px";
                notification.style.zIndex = "9999";
            }

            setTimeout(function () {
                notification.classList.add("show");
            }, 10);

            setTimeout(function () {
                notification.classList.remove("show");
                setTimeout(function () {
                    if (notification.parentNode) {
                        notification.remove();
                    }
                }, 300);
            }, 2000);
        },
    };

    var DocumentAutoFillModule = {
        init: function () {
            this.processExistingContainers();
            this.observeNewContainers();
            this.startTimeUpdateTimer();
        },

        processExistingContainers: function () {
            var containers = document.querySelectorAll(
                ".copyable-pre-container.auto-fill-enabled",
            );

            containers.forEach(
                function (container) {
                    this.setupAutoFillContainer(container);
                }.bind(this),
            );
        },

        setupAutoFillContainer: function (container) {
            if (container.querySelector(".document-fields-container")) {
                return;
            }

            var fieldsContainer = document.createElement("div");
            fieldsContainer.className = "document-fields-container";

            var gridContainer = document.createElement("div");
            gridContainer.className = "fields-grid";

            var siteNumberField = this.createField(
                "site-number",
                "Номер участка:",
                "Введите номер участка...",
                false,
            );
            var authorField = this.createField(
                "author",
                "Автор документа:",
                "Введите ваше имя...",
                true,
            );
            var positionField = this.createField(
                "position",
                "Должность:",
                "Введите вашу должность...",
                true,
            );
            var signatureField = this.createField(
                "signature",
                "Подпись:",
                "Введите подпись...",
                true,
            );

            gridContainer.appendChild(siteNumberField.container);
            gridContainer.appendChild(authorField.container);
            gridContainer.appendChild(positionField.container);
            gridContainer.appendChild(signatureField.container);

            fieldsContainer.appendChild(gridContainer);

            if (container.firstChild) {
                container.insertBefore(fieldsContainer, container.firstChild);
            } else {
                container.appendChild(fieldsContainer);
            }

            setTimeout(
                function () {
                    this.applyAllFieldsToContainer(container);
                }.bind(this),
                100,
            );
        },

        createField: function (fieldType, labelText, placeholder, shouldCache) {
            var fieldContainer = document.createElement("div");
            fieldContainer.className = "field-container";

            var label = document.createElement("label");
            label.textContent = labelText;
            label.htmlFor = fieldType + "-input";

            var input = document.createElement("input");
            input.type = "text";
            input.id = fieldType + "-input";
            input.className = "field-input " + fieldType + "-input";
            input.placeholder = placeholder;

            if (shouldCache) {
                var savedValue = localStorage.getItem(
                    "document" + this.capitalizeFirstLetter(fieldType),
                );
                if (savedValue) {
                    input.value = savedValue;
                }
            }

            input.addEventListener(
                "input",
                function () {
                    var value = input.value.trim();
                    if (shouldCache) {
                        localStorage.setItem(
                            "document" + this.capitalizeFirstLetter(fieldType),
                            value,
                        );
                    }
                }.bind(this),
            );

            fieldContainer.appendChild(label);
            fieldContainer.appendChild(input);

            return {
                container: fieldContainer,
                input: input,
                type: fieldType,
                shouldCache: shouldCache,
            };
        },

        capitalizeFirstLetter: function (string) {
            return string.charAt(0).toUpperCase() + string.slice(1);
        },

        applyAllFieldsToContainer: function (container) {
            var fieldsContainer = container.querySelector(
                ".document-fields-container",
            );
            if (!fieldsContainer) return;

            var siteNumber = fieldsContainer
                .querySelector(".site-number-input")
                .value.trim();
            var author = fieldsContainer
                .querySelector(".author-input")
                .value.trim();
            var position = fieldsContainer
                .querySelector(".position-input")
                .value.trim();
            var signature = fieldsContainer
                .querySelector(".signature-input")
                .value.trim();

            this.autoFillAllDocumentsInContainer(container, {
                siteNumber: siteNumber,
                author: author,
                position: position,
                signature: signature,
            });
        },

        autoFillAllDocumentsInContainer: function (container, fields) {
            var preElements = container.querySelectorAll("pre");

            preElements.forEach(
                function (preElement) {
                    this.autoFillDocument(preElement, fields);
                }.bind(this),
            );
        },

        autoFillDocument: function (preElement, fields) {
            if (!preElement) return;

            var originalContent =
                preElement.textContent || preElement.innerText;

            if (!this.isDocumentTemplate(originalContent)) {
                return;
            }

            var updatedContent = this.fillDocumentContent(
                originalContent,
                fields,
            );

            if (updatedContent !== originalContent) {
                preElement.textContent = updatedContent;
            }
        },

        isDocumentTemplate: function (text) {
            return (
                text.includes("SCP") &&
                text.includes("Обезопасить. Удержать. Сохранить.") &&
                text.includes("Автор документа:") &&
                text.includes("Дата и время:")
            );
        },

        fillDocumentContent: function (content, fields) {
            var currentDateTime = this.getCurrentDateTime();

            content = content.replace(
                /(\[bold\]Дата и время:\[\/bold\])([^\n]*)/g,
                "$1 " + currentDateTime,
            );

            if (fields.siteNumber) {
                content = content.replace(
                    /Участок-([^|\n\[\]]*)/g,
                    "Участок-" + fields.siteNumber + " ",
                );
            }

            if (fields.author) {
                content = content.replace(
                    /(\[bold\]Автор документа:\[\/bold\])([^\n]*)/g,
                    "$1 " + fields.author,
                );
            } else {
                content = content.replace(
                    /(\[bold\]Автор документа:\[\/bold\])([^\n]*)/g,
                    "$1",
                );
            }

            if (fields.position) {
                content = content.replace(
                    /(\[bold\]Должность:\[\/bold\])([^\n]*)/g,
                    "$1 " + fields.position,
                );
            } else {
                content = content.replace(
                    /(\[bold\]Должность:\[\/bold\])([^\n]*)/g,
                    "$1",
                );
            }

            if (fields.signature) {
                content = content.replace(
                    /(\[bold\]Подпись:\[\/bold\])[^\n]*/g,
                    "$1 " + fields.signature,
                );
            } else {
                content = content.replace(
                    /(\[bold\]Подпись:\[\/bold\])([^\n]*)/g,
                    "$1_____",
                );
            }

            return content;
        },

        getCurrentDateTime: function () {
            var now = new Date();

            var day = String(now.getDate()).padStart(2, "0");
            var month = String(now.getMonth() + 1).padStart(2, "0");
            var year = now.getFullYear();

            var hours = String(now.getHours()).padStart(2, "0");
            var minutes = String(now.getMinutes()).padStart(2, "0");

            return (
                hours + ":" + minutes + ", " + day + "." + month + "." + year
            );
        },

        startTimeUpdateTimer: function () {
            var self = this;

            function updateTimeIfNeeded() {
                var containers = document.querySelectorAll(
                    ".copyable-pre-container.auto-fill-enabled",
                );

                if (containers.length > 0) {
                    containers.forEach(function (container) {
                        var fieldsContainer = container.querySelector(
                            ".document-fields-container",
                        );
                        if (fieldsContainer) {
                            self.applyAllFieldsToContainer(container);
                        }
                    });
                }
            }

            this.timeUpdateInterval = setInterval(updateTimeIfNeeded, 5000);

            document.addEventListener("visibilitychange", function () {
                if (!document.hidden) {
                    updateTimeIfNeeded();
                }
            });

            window.addEventListener("focus", updateTimeIfNeeded);
        },

        stopTimeUpdateTimer: function () {
            if (this.timeUpdateInterval) {
                clearInterval(this.timeUpdateInterval);
                this.timeUpdateInterval = null;
            }
        },

        observeNewContainers: function () {
            var observer = new MutationObserver(function (mutations) {
                mutations.forEach(function (mutation) {
                    mutation.addedNodes.forEach(function (node) {
                        if (node.nodeType === 1) {
                            if (
                                node.classList &&
                                node.classList.contains(
                                    "copyable-pre-container",
                                ) &&
                                node.classList.contains("auto-fill-enabled")
                            ) {
                                setTimeout(function () {
                                    DocumentAutoFillModule.setupAutoFillContainer(
                                        node,
                                    );
                                }, 100);
                            } else if (node.querySelectorAll) {
                                var containers = node.querySelectorAll(
                                    ".copyable-pre-container.auto-fill-enabled",
                                );
                                containers.forEach(function (container) {
                                    setTimeout(function () {
                                        DocumentAutoFillModule.setupAutoFillContainer(
                                            container,
                                        );
                                    }, 100);
                                });
                            }
                        }
                    });
                });
            });

            observer.observe(document.body, {
                childList: true,
                subtree: true,
            });
        },
    };

    window.DocumentAutoFill = {
        refreshAll: function () {
            var containers = document.querySelectorAll(
                ".copyable-pre-container.auto-fill-enabled",
            );
            containers.forEach(function (container) {
                DocumentAutoFillModule.applyAllFieldsToContainer(container);
            });
        },

        clearAllNames: function () {
            localStorage.removeItem("documentAuthor");
            localStorage.removeItem("documentPosition");
            localStorage.removeItem("documentSignature");

            var inputs = document.querySelectorAll(
                ".author-input, .position-input, .signature-input",
            );
            inputs.forEach(function (input) {
                input.value = "";
            });

            window.DocumentAutoFill.refreshAll();
        },

        startTimeUpdates: function () {
            DocumentAutoFillModule.startTimeUpdateTimer();
        },

        stopTimeUpdates: function () {
            DocumentAutoFillModule.stopTimeUpdateTimer();
        },
    };

    var SnowflakesModule = {
        snowflakes: [],
        createInterval: null,
        isActive: false,
        snowflakeCount: 30,

        random: function (min, max) {
            return Math.random() * (max - min) + min;
        },

        init: function () {
            if (this.isActive) return;

            this.addStyles();
            this.startContinuousCreation();
            this.isActive = true;
        },

        addStyles: function () {
            if (document.getElementById("snowflakes-styles")) return;

            var style = document.createElement("style");
            style.id = "snowflakes-styles";
            style.textContent =
                ".snowflake {" +
                "position: fixed;" +
                "top: -10px;" +
                "color: #fff;" +
                "font-family: Arial, sans-serif;" +
                "user-select: none;" +
                "pointer-events: none;" +
                "z-index: 1;" +
                "animation-name: snowflake-fall;" +
                "animation-timing-function: linear;" +
                "animation-iteration-count: infinite;" +
                "will-change: transform;" +
                "}" +
                "@keyframes snowflake-fall {" +
                "0% {" +
                "transform: translateY(0) translateX(0) rotate(0deg);" +
                "}" +
                "25% {" +
                "transform: translateY(25vh) translateX(10px) rotate(90deg);" +
                "}" +
                "50% {" +
                "transform: translateY(50vh) translateX(-10px) rotate(180deg);" +
                "}" +
                "75% {" +
                "transform: translateY(75vh) translateX(10px) rotate(270deg);" +
                "}" +
                "100% {" +
                "transform: translateY(calc(100vh + 100px)) translateX(0) rotate(360deg);" +
                "}" +
                "}" +
                ".snowflake.flare {" +
                "text-shadow: 0 0 5px rgba(255, 255, 255, 0.4), 0 0 10px rgba(255, 255, 255, 0.2);" +
                "}" +
                ".snowflake.blurred {" +
                "filter: blur(2px);" +
                "}";

            document.head.appendChild(style);
        },

        createSnowflake: function () {
            var snowflake = document.createElement("div");
            snowflake.className = "snowflake";

            var symbol = this.getSnowflakeSymbol();
            snowflake.textContent = symbol;

            var fontSize = this.random(0.5, 1.2);
            snowflake.style.fontSize = fontSize + "em";
            snowflake.style.left = this.random(0, 100) + "vw";
            snowflake.style.opacity = this.random(0.25, 0.5);

            var fallDuration = this.random(10, 30);
            snowflake.style.animationDuration = fallDuration + "s";
            snowflake.style.animationDelay = this.random(0, 2) + "s";

            if (Math.random() > 0.95) {
                snowflake.classList.add("flare");
            }

            if (Math.random() > 0.4) {
                snowflake.classList.add("blurred");
            }

            document.body.appendChild(snowflake);
            this.snowflakes.push(snowflake);

            var self = this;
            var checkRemove = setInterval(function () {
                var rect = snowflake.getBoundingClientRect();
                if (rect.top > window.innerHeight + 50) {
                    if (snowflake.parentNode) {
                        snowflake.remove();
                    }
                    var index = self.snowflakes.indexOf(snowflake);
                    if (index > -1) {
                        self.snowflakes.splice(index, 1);
                    }
                    clearInterval(checkRemove);
                }
            }, 100);
        },

        getSnowflakeSymbol: function () {
            var symbols = ["❄", "❅", "❆"];
            return symbols[Math.floor(Math.random() * symbols.length)];
        },

        startContinuousCreation: function () {
            var self = this;
            this.createInterval = setInterval(function () {
                if (
                    self.isActive &&
                    self.snowflakes.length < self.snowflakeCount * 1.5
                ) {
                    self.createSnowflake();
                }
            }, 500);
        },

        stop: function () {
            this.isActive = false;

            if (this.createInterval) {
                clearInterval(this.createInterval);
                this.createInterval = null;
            }

            this.snowflakes.forEach(function (snowflake) {
                if (snowflake && snowflake.parentNode) {
                    snowflake.remove();
                }
            });
            this.snowflakes = [];

            var styles = document.getElementById("snowflakes-styles");
            if (styles) {
                styles.remove();
            }
        },

        toggle: function () {
            if (this.isActive) {
                this.stop();
            } else {
                this.init();
            }
        },
    };

    window.SnowflakesModule = SnowflakesModule;

    function initAllModules() {
        SidebarModule.init();
        AccessTooltipsModule.init();
        LawTooltipsModule.init();
        DataTooltipsModule.init();
        CopyTextModule.init();
        DocumentAutoFillModule.init();
        // SnowflakesModule.init()
    }

    if (document.readyState === "loading") {
        document.addEventListener("DOMContentLoaded", initAllModules);
    } else {
        initAllModules();
    }
})();