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

Страница интерфейса MediaWiki
Нет описания правки
Нет описания правки
(не показаны 4 промежуточные версии этого же участника)
Строка 640: Строка 640:
    },
    },
     
     
    fillDocumentContent: function(content, fields) {
fillDocumentContent: function(content, fields) {
        var currentDateTime = this.getCurrentDateTime();
    var currentDateTime = this.getCurrentDateTime();
       
   
        content = content.replace(
    content = content.replace(
            /(\[bold\]Дата и время:\[\/bold\])([^\n]*)/g,  
        /(\[bold\]Дата и время:\[\/bold\])([^\n]*)/g,  
            '$1 ' + currentDateTime
        '$1 ' + currentDateTime
        );
    );
       
   
        if (fields.siteNumber) {
    if (fields.siteNumber) {
            content = content.replace(
        content = content.replace(
                /Участок-([^|\n]*)/g,  
            /Участок-([^|\n\[\]]*)/g,  
                'Участок-' + fields.siteNumber + ' '
            'Участок-' + fields.siteNumber + ' '
            );
        );
        }
    }
       
   
        if (fields.author) {
    if (fields.author) {
            content = content.replace(
        content = content.replace(
                /(\[bold\]Автор документа:\[\/bold\])([^\n]*)/g,  
            /(\[bold\]Автор документа:\[\/bold\])([^\n]*)/g,  
                '$1 ' + fields.author
            '$1 ' + fields.author
            );
        );
        } else {
    } else {
            content = content.replace(
        content = content.replace(
                /(\[bold\]Автор документа:\[\/bold\])([^\n]*)/g,  
            /(\[bold\]Автор документа:\[\/bold\])([^\n]*)/g,  
                '$1'
            '$1'
            );
        );
        }
    }
       
   
        if (fields.position) {
    if (fields.position) {
            content = content.replace(
        content = content.replace(
                /(\[bold\]Должность:\[\/bold\])([^\n]*)/g,  
            /(\[bold\]Должность:\[\/bold\])([^\n]*)/g,  
                '$1 ' + fields.position
            '$1 ' + fields.position
            );
        );
        } else {
    } else {
            content = content.replace(
        content = content.replace(
                /(\[bold\]Должность:\[\/bold\])([^\n]*)/g,  
            /(\[bold\]Должность:\[\/bold\])([^\n]*)/g,  
                '$1'
            '$1'
            );
        );
        }
    }
       
   
        if (fields.signature) {
    if (fields.signature) {
            content = content.replace(
        content = content.replace(
                /(\[bold\]Подпись:\[\/bold\])[^\n]*/g,  
            /(\[bold\]Подпись:\[\/bold\])[^\n]*/g,  
                '$1 ' + fields.signature
            '$1 ' + fields.signature
            );
        );
        } else {
    } else {
            content = content.replace(
        content = content.replace(
                /(\[bold\]Подпись:\[\/bold\])([^\n]*)/g,  
            /(\[bold\]Подпись:\[\/bold\])([^\n]*)/g,  
                '$1_____'
            '$1_____'
            );
        );
        }
    }
       
   
        return content;
    return content;
    },
},
     
     
    getCurrentDateTime: function() {
    getCurrentDateTime: function() {
Строка 1098: Строка 1098:
            if (!wrapper || wrapper.querySelector('.law-mode-toggle')) return;
            if (!wrapper || wrapper.querySelector('.law-mode-toggle')) return;
             
             
            var toggleContainer = document.createElement('div');
            var toggleContainer = document.createElement('div');
            toggleContainer.className = 'law-mode-toggle';
            toggleContainer.className = 'law-mode-toggle';
            toggleContainer.innerHTML = `
            toggleContainer.innerHTML =  
                <div class="mode-toggle-buttons">
                '<div class="mode-toggle-buttons">' +
                    <button class="mode-btn active" data-mode="navigation">Навигация</button>
                    '<button class="mode-btn active" data-mode="navigation">Навигация</button>' +
                    <button class="mode-btn" data-mode="calculator">Калькулятор</button>
                    '<button class="mode-btn" data-mode="calculator">Калькулятор</button>' +
                </div>
                '</div>';
            `;
             
             
            wrapper.appendChild(toggleContainer);
            wrapper.appendChild(toggleContainer);
Строка 1129: Строка 1128:
        if (document.getElementById('law-calculator-styles')) return;
        if (document.getElementById('law-calculator-styles')) return;
         
         
        var style = document.createElement('style');
        var style = document.createElement('style');
        style.id = 'law-calculator-styles';
        style.id = 'law-calculator-styles';
        style.textContent = `
        style.textContent =  
            .law-mode-toggle {
            '.law-mode-toggle {' +
                margin: 10px 0;
                'margin: 10px 0;' +
                text-align: center;
                'text-align: center;' +
            }
            '}' +
           
            '.mode-toggle-buttons {' +
            .mode-toggle-buttons {
                'display: inline-flex;' +
                display: inline-flex;
                'background: #f0f0f0;' +
                background: #f0f0f0;
                'border-radius: 5px;' +
                border-radius: 5px;
                'padding: 2px;' +
                padding: 2px;
                'border: 1px solid #ccc;' +
                border: 1px solid #ccc;
            '}' +
            }
            '.mode-btn {' +
           
                'padding: 8px 16px;' +
            .mode-btn {
                'border: none;' +
                padding: 8px 16px;
                'background: transparent;' +
                border: none;
                'cursor: pointer;' +
                background: transparent;
                'border-radius: 3px;' +
                cursor: pointer;
                'font-size: 14px;' +
                border-radius: 3px;
                'transition: all 0.2s;' +
                font-size: 14px;
            '}' +
                transition: all 0.2s;
            '.mode-btn.active {' +
            }
                'background: #007cba;' +
           
                'color: white;' +
            .mode-btn.active {
            '}' +
                background: #007cba;
            '.mode-btn:hover:not(.active) {' +
                color: white;
                'background: #e0e0e0;' +
            }
            '}' +
           
            '.calculator-interface {' +
            .mode-btn:hover:not(.active) {
                'margin-top: 15px;' +
                background: #e0e0e0;
                'padding: 15px;' +
            }
                'background: #f9f9f9;' +
           
                'border: 1px solid #ddd;' +
            .calculator-interface {
                'border-radius: 5px;' +
                margin-top: 15px;
                'display: none;' +
                padding: 15px;
            '}' +
                background: #f9f9f9;
            '.calculator-interface.active {' +
                border: 1px solid #ddd;
                'display: block;' +
                border-radius: 5px;
            '}' +
                display: none;
            '.selected-violations {' +
            }
                'margin: 10px 0;' +
           
            '}' +
            .calculator-interface.active {
            '.violation-item {' +
                display: block;
                'display: inline-block;' +
            }
                'margin: 5px;' +
           
                'padding: 5px 10px;' +
            .selected-violations {
                'background: #e3f2fd;' +
                margin: 10px 0;
                'border: 1px solid #2196f3;' +
            }
                'border-radius: 15px;' +
           
                'font-size: 12px;' +
            .violation-item {
            '}' +
                display: inline-block;
            '.violation-item .remove-btn {' +
                margin: 5px;
                'margin-left: 5px;' +
                padding: 5px 10px;
                'cursor: pointer;' +
                background: #e3f2fd;
                'color: #f44336;' +
                border: 1px solid #2196f3;
                'font-weight: bold;' +
                border-radius: 15px;
            '}' +
                font-size: 12px;
            '.calculation-result {' +
            }
                'margin-top: 15px;' +
           
                'padding: 10px;' +
            .violation-item .remove-btn {
                'background: #fff3cd;' +
                margin-left: 5px;
                'border: 1px solid #ffeaa7;' +
                cursor: pointer;
                'border-radius: 5px;' +
                color: #f44336;
                'font-weight: bold;' +
                font-weight: bold;
                'white-space: pre-line;' +
            }
            '}' +
           
            '.calculation-result.critical {' +
            .calculation-result {
                'background: #f8d7da;' +
                margin-top: 15px;
                'border-color: #f5c6cb;' +
                padding: 10px;
                'color: #721c24;' +
                background: #fff3cd;
            '}' +
                border: 1px solid #ffeaa7;
            '.law-cell-calculator {' +
                border-radius: 5px;
                'cursor: pointer;' +
                font-weight: bold;
                'transition: background-color 0.2s;' +
                white-space: pre-line;
            '}' +
            }
            '.law-cell-calculator:hover {' +
           
                'background-color: rgba(0, 124, 186, 0.1) !important;' +
            .calculation-result.critical {
            '}' +
                background: #f8d7da;
            '.law-cell-calculator.selected {' +
                border-color: #f5c6cb;
                'background-color: rgba(0, 124, 186, 0.3) !important;' +
                color: #721c24;
            '}' +
            }
            '.calculator-actions {' +
           
                'margin-top: 10px;' +
            .law-cell-calculator {
            '}' +
                cursor: pointer;
            '.calculator-actions button {' +
                transition: background-color 0.2s;
                'padding: 8px 16px;' +
            }
                'border: 1px solid #ccc;' +
           
                'background: white;' +
            .law-cell-calculator:hover {
                'cursor: pointer;' +
                background-color: rgba(0, 124, 186, 0.1) !important;
                'border-radius: 3px;' +
            }
                'font-size: 14px;' +
           
            '}' +
            .law-cell-calculator.selected {
            '.calculator-actions button:hover {' +
                background-color: rgba(0, 124, 186, 0.3) !important;
                'background: #f0f0f0;' +
            }
            '}' +
           
            '.calculator-actions .calculate-btn {' +
            .calculator-actions {
                'background: #007cba;' +
                margin-top: 10px;
                'color: white;' +
            }
                'border-color: #007cba;' +
           
            '}' +
            .calculator-actions button {
            '.calculator-actions .calculate-btn:hover {' +
                padding: 8px 16px;
                'background: #005a87;' +
                border: 1px solid #ccc;
            '}';
                background: white;
                cursor: pointer;
                border-radius: 3px;
                font-size: 14px;
            }
           
            .calculator-actions button:hover {
                background: #f0f0f0;
            }
           
            .calculator-actions .calculate-btn {
                background: #007cba;
                color: white;
                border-color: #007cba;
            }
           
            .calculator-actions .calculate-btn:hover {
                background: #005a87;
            }
        `;
         
         
        document.head.appendChild(style);
        document.head.appendChild(style);
Строка 1280: Строка 1259:
     
     
    createCalculatorInterface: function() {
    createCalculatorInterface: function() {
        var calculatorInterface = document.createElement('div');
        var calculatorInterface = document.createElement('div');
        calculatorInterface.className = 'calculator-interface';
        calculatorInterface.className = 'calculator-interface';
        calculatorInterface.innerHTML = `
        calculatorInterface.innerHTML =  
            <h4>Калькулятор сроков заключения</h4>
            '<h4>Калькулятор сроков заключения</h4>' +
            <p>Выберите нарушения, кликая по статьям в таблице выше:</p>
            '<p>Выберите нарушения, кликая по статьям в таблице выше:</p>' +
            <div class="selected-violations">
            '<div class="selected-violations">' +
                <div class="violations-list"></div>
                '<div class="violations-list"></div>' +
            </div>
            '</div>' +
            <div class="calculation-result" style="display: none;"></div>
            '<div class="calculation-result" style="display: none;"></div>' +
            <div class="calculator-actions">
            '<div class="calculator-actions">' +
                <button class="clear-btn" style="margin-right: 10px;">Очистить</button>
                '<button class="clear-btn" style="margin-right: 10px;">Очистить</button>' +
                <button class="calculate-btn">Рассчитать</button>
                '<button class="calculate-btn">Рассчитать</button>' +
            </div>
            '</div>';
        `;
         
         
        // Обработчики событий
        // Обработчики событий
Строка 1375: Строка 1353:
            if (!law) return;
            if (!law) return;
             
             
            var item = document.createElement('div');
            var item = document.createElement('div');
            item.className = 'violation-item';
            item.className = 'violation-item';
            item.innerHTML = `
            item.innerHTML =  
                ${lawCode} - ${law.title}
                lawCode + ' - ' + law.title +
                <span class="remove-btn" data-law-code="${lawCode}">×</span>
                '<span class="remove-btn" data-law-code="' + lawCode + '">×</span>';
            `;
             
             
            item.querySelector('.remove-btn').addEventListener('click', function() {
            item.querySelector('.remove-btn').addEventListener('click', function() {
Строка 1395: Строка 1372:
            this.selectedViolations.splice(index, 1);
            this.selectedViolations.splice(index, 1);
             
             
            // Убираем выделение с ячейки
            // Убираем выделение с ячейки
            var cell = document.querySelector(`[data-law-code="${lawCode}"]`);
            var cell = document.querySelector('[data-law-code="' + lawCode + '"]');
            if (cell) {
            if (cell) {
                cell.classList.remove('selected');
                cell.classList.remove('selected');
            }
            }
             
             
            this.updateViolationsList();
            this.updateViolationsList();
Строка 1456: Строка 1433:
                var categoryName = this.getCategoryName(categoryKey);
                var categoryName = this.getCategoryName(categoryKey);
                 
                 
                if (category.isCritical) {
                if (category.isCritical) {
                    hasCritical = true;
                    hasCritical = true;
                    resultText += `${categoryName}: ${category.punishment || 'Перевод в Д-класс/казнь'}\n`;
                    resultText += '' + categoryName + ': ' + (category.punishment || 'Перевод в Д-класс/казнь') + '\n';
                } else {
                } else {
                    // Для одной категории берем самую тяжкую статью
                    // Для одной категории берем самую тяжкую статью
                    var maxLaw = laws.reduce(function(max, current) {
                    var maxLaw = laws.reduce(function(max, current) {
Строка 1480: Строка 1457:
                    }
                    }
                     
                     
                    resultText += `${categoryName}: ${punishmentText} (статья ${lawCode})\n`;
                    resultText += '' + categoryName + ': ' + punishmentText + ' (статья ' + lawCode + ')\n';
                }
                }
            }.bind(this));
            }.bind(this));
Строка 1492: Строка 1469:
                // Для Д-класса показываем штрафы и время отдельно
                // Для Д-класса показываем штрафы и время отдельно
                var summaryText = '';
                var summaryText = '';
                if (totalFine > 0) {
                if (totalFine > 0) {
                    summaryText += `Общий штраф: ${totalFine} кредитов\n`;
                    summaryText += 'Общий штраф: ' + totalFine + ' кредитов\n';
                }
                }
                if (totalMinTime > 0 || totalMaxTime > 0) {
                if (totalMinTime > 0 || totalMaxTime > 0) {
                    summaryText += `Общее время: ${this.formatTime(totalMinTime, totalMaxTime)}\n`;
                    summaryText += 'Общее время: ' + this.formatTime(totalMinTime, totalMaxTime) + '\n';
                }
                }
                 
                 
                return {
                return {
Строка 1615: Строка 1592:
         CopyTextModule.init();
         CopyTextModule.init();
         DocumentAutoFillModule.init();
         DocumentAutoFillModule.init();
         LawCalculatorModule.init();
         // LawCalculatorModule.init();
     }
     }
      
      

Версия от 23:10, 3 октября 2025

(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://unpkg.com/@popperjs/core@2/dist/umd/popper.min.js';
            popperScript.onload = function() {
                var tippyScript = document.createElement('script');
                tippyScript.src = 'https://unpkg.com/tippy.js@6/dist/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://unpkg.com/tippy.js@6/dist/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() {
            var tableCells = document.querySelectorAll('.law-tooltips td, .law-tooltips th');
            if (tableCells.length === 0) return;
            
            MediaWikiTooltips.load(function() {
                var lawData = LawTooltipsModule.extractLawData();
                LawTooltipsModule.initCellTooltips(tableCells, lawData);
            });
        },
        
        extractLawData: function() {
		    var lawData = {};
		    var detailTables = document.querySelectorAll('.mw-collapsible-content table');
		    
		    detailTables.forEach(function(table) {
		        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}$/)) {
		                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();
						    // Удаляем все <br> теги
						    html = html.replace(/<br\s*\/?>/gi, '');
						    if (html) examples.push(html);
						});
		                
		                lawData[lawCode] = {
		                    title: lawTitle,
		                    description: description,
		                    examples: examples
		                };
		            }
		        });
		    });
		    
		    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>'; // Теперь example содержит HTML
	        });
	        html += '</ul></div>';
	    }
	    html += '</div>';
	    
	    return html;
	},
        
        initCellTooltips: function(tableCells, lawData) {
            tableCells.forEach(function(cell) {
                var link = cell.querySelector('a[href*="#"]');
                if (!link) return;
                
                var href = link.getAttribute('href');
                var match = href.match(/#(\d{3})/);
                if (!match) return;
                
                var lawCode = match[1];
                var tooltipContent = LawTooltipsModule.createTooltipContent(lawCode, lawData);
                if (!tooltipContent) return;
                
                cell.classList.add('law-cell-with-tooltip');
                
                cell.addEventListener('click', function(e) {
                    e.preventDefault();
                    window.location.hash = lawCode;
                });
                
                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();
                            }
                        });
                    }
                });
            });
        }
    };
    
    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.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.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.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.setupElement(pre);
                }
            });
        },
        
        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.trim();
            
            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 LawCalculatorModule = {
	    isCalculatorMode: false,
	    selectedViolations: [],
	    lawData: {},
	    
	    init: function() {
	        this.extractLawData();
	        this.createModeToggle();
	        this.observeTables();
	    },
	    
	    extractLawData: function() {
	        // Используем данные из существующего LawTooltipsModule
	        if (window.LawTooltipsModule && window.LawTooltipsModule.extractLawData) {
	            this.lawData = window.LawTooltipsModule.extractLawData();
	        } else {
	            // Fallback - извлекаем данные самостоятельно
	            this.lawData = this.extractLawDataFallback();
	        }
	        
	        // Добавляем информацию о категориях и сроках
	        this.addCategoryInfo();
	    },
	    
	    extractLawDataFallback: function() {
	        var lawData = {};
	        var detailTables = document.querySelectorAll('.mw-collapsible-content table');
	        
	        detailTables.forEach(function(table) {
	            var rows = table.querySelectorAll('tr');
	            
	            rows.forEach(function(row) {
	                var cells = row.querySelectorAll('td');
	                if (cells.length < 3) return;
	                
	                var crimeCell = cells[0];
	                var anchor = crimeCell.querySelector('[id]');
	                if (!anchor) return;
	                
	                var lawCode = anchor.id;
	                var titleElement = crimeCell.querySelector('b');
	                
	                if (titleElement && lawCode.match(/^\d{3}$/)) {
	                    var titleText = titleElement.textContent.trim();
	                    var lawTitle = titleText.replace(/^\d{3}\s*/, '').replace(/^\d{3}/, '').trim();
	                    var description = cells[1].innerHTML.trim();
	                    
	                    var examples = [];
	                    var exampleItems = cells[2].querySelectorAll('li');
	                    exampleItems.forEach(function(item) {
	                        var html = item.innerHTML.trim();
	                        html = html.replace(/<br\s*\/?>/gi, '');
	                        if (html) examples.push(html);
	                    });
	                    
	                    lawData[lawCode] = {
	                        title: lawTitle,
	                        description: description,
	                        examples: examples
	                    };
	                }
	            });
	        });
	        
	        return lawData;
	    },
	    
	    addCategoryInfo: function() {
	        // Определяем тип страницы и извлекаем информацию о наказаниях
	        this.pageType = this.detectPageType();
	        this.extractPunishmentInfo();
	    },
	    
	    detectPageType: function() {
	        // Проверяем заголовки страницы для определения типа
	        var pageTitle = document.title.toLowerCase();
	        var headings = document.querySelectorAll('h1, h2, h3');
	        
	        for (var i = 0; i < headings.length; i++) {
	            var headingText = headings[i].textContent.toLowerCase();
	            if (headingText.includes('д-класс') || headingText.includes('d-class')) {
	                return 'd-class';
	            }
	            if (headingText.includes('персонал') || headingText.includes('сотрудник')) {
	                return 'personnel';
	            }
	        }
	        
	        // Проверяем по URL или другим признакам
	        if (window.location.href.toLowerCase().includes('d-class') || 
	            window.location.href.toLowerCase().includes('д-класс')) {
	            return 'd-class';
	        }
	        
	        return 'personnel'; // По умолчанию
	    },
	    
	    extractPunishmentInfo: function() {
	        // Извлекаем информацию о наказаниях из текста на странице
	        var punishmentSections = document.querySelectorAll('.mw-collapsible-content p');
	        var categories = {};
	        
	        console.log('LawCalculator: Найдено секций с наказаниями:', punishmentSections.length);
	        console.log('LawCalculator: Тип страницы:', this.pageType);
	        
	        punishmentSections.forEach(function(section) {
	            var text = section.textContent;
	            var punishmentMatch = text.match(/Наказание[:\s]*(.+?)(?:\n|$)/i);
	            
	            if (punishmentMatch) {
	                var punishmentText = punishmentMatch[1].trim();
	                console.log('LawCalculator: Найдено наказание:', punishmentText);
	                
	                var categoryInfo = this.parsePunishmentText(punishmentText);
	                
	                if (categoryInfo) {
	                    // Находим соответствующую категорию по цвету или другим признакам
	                    var categoryKey = this.findCategoryByContext(section);
	                    if (categoryKey) {
	                        categories[categoryKey] = categoryInfo;
	                        console.log('LawCalculator: Применено к категории:', categoryKey, categoryInfo);
	                    }
	                }
	            }
	        }.bind(this));
	        
	        console.log('LawCalculator: Итоговые категории:', categories);
	        
	        // Применяем найденную информацию к законам
	        this.applyCategoryInfo(categories);
	    },
	    
	    parsePunishmentText: function(text) {
	        // Парсим текст наказания
	        var originalText = text;
	        text = text.toLowerCase();
	        
	        // Проверяем на критические нарушения
	        if (text.includes('д-класс') || text.includes('казнь') || text.includes('перевод')) {
	            return {
	                isCritical: true,
	                punishment: originalText.trim()
	            };
	        }
	        
	        // Для Д-класса ищем штрафы
	        if (this.pageType === 'd-class') {
	            return this.parseDClassPunishment(originalText);
	        }
	        
	        // Для персонала ищем временные рамки
	        return this.parsePersonnelPunishment(originalText);
	    },
	    
	    parseDClassPunishment: function(text) {
	        // Парсим наказания для Д-класса (штрафы, дополнительные наказания)
	        var lowerText = text.toLowerCase();
	        
	        // Ищем штрафы в кредитах
	        var creditMatch = text.match(/(\d+[\s,.]?\d*)\s*кредит/);
	        if (creditMatch) {
	            var amount = creditMatch[1].replace(/[\s,]/g, '');
	            return {
	                isCritical: false,
	                punishment: 'Штраф ' + amount + ' кредитов',
	                fine: parseInt(amount)
	            };
	        }
	        
	        // Ищем временные наказания для Д-класса
	        var timeMatch = text.match(/(\d+)\s*до\s*(\d+)\s*минут/);
	        if (timeMatch) {
	            return {
	                minTime: parseInt(timeMatch[1]),
	                maxTime: parseInt(timeMatch[2]),
	                isCritical: false,
	                punishment: timeMatch[1] + '-' + timeMatch[2] + ' минут'
	            };
	        }
	        
	        var rangeMatch = text.match(/от\s*(\d+)\s*до\s*(\d+)\s*минут/);
	        if (rangeMatch) {
	            return {
	                minTime: parseInt(rangeMatch[1]),
	                maxTime: parseInt(rangeMatch[2]),
	                isCritical: false,
	                punishment: rangeMatch[1] + '-' + rangeMatch[2] + ' минут'
	            };
	        }
	        
	        var fixedMatch = text.match(/(\d+)\s*минут/);
	        if (fixedMatch) {
	            var time = parseInt(fixedMatch[1]);
	            return {
	                minTime: time,
	                maxTime: time,
	                isCritical: false,
	                punishment: time + ' минут'
	            };
	        }
	        
	        // Если не нашли конкретные наказания, возвращаем текст как есть
	        return {
	            isCritical: false,
	            punishment: text.trim()
	        };
	    },
	    
	    parsePersonnelPunishment: function(text) {
	        // Парсим наказания для персонала
	        var lowerText = text.toLowerCase();
	        
	        // Ищем временные рамки
	        var timeMatch = text.match(/(\d+)\s*до\s*(\d+)\s*минут/);
	        if (timeMatch) {
	            return {
	                minTime: parseInt(timeMatch[1]),
	                maxTime: parseInt(timeMatch[2]),
	                isCritical: false
	            };
	        }
	        
	        // Ищем диапазон времени
	        var rangeMatch = text.match(/от\s*(\d+)\s*до\s*(\d+)\s*минут/);
	        if (rangeMatch) {
	            return {
	                minTime: parseInt(rangeMatch[1]),
	                maxTime: parseInt(rangeMatch[2]),
	                isCritical: false
	            };
	        }
	        
	        // Ищем фиксированное время
	        var fixedMatch = text.match(/(\d+)\s*минут/);
	        if (fixedMatch) {
	            var time = parseInt(fixedMatch[1]);
	            return {
	                minTime: time,
	                maxTime: time,
	                isCritical: false
	            };
	        }
	        
	        return null;
	    },
	    
	    findCategoryByContext: function(section) {
	        // Находим категорию по контексту (заголовок секции)
	        var collapsible = section.closest('.mw-collapsible');
	        if (!collapsible) return null;
	        
	        var toggle = collapsible.querySelector('.mw-collapsible-toggle');
	        if (!toggle) return null;
	        
	        var titleElement = toggle.querySelector('.рамка-название');
	        if (!titleElement) return null;
	        
	        var title = titleElement.textContent.trim();
	        
	        // Определяем диапазон статей по заголовку
	        if (title.includes('Лёгкие')) return '100-109';
	        if (title.includes('Средние')) return '200-211';
	        if (title.includes('Тяжкие') && !title.includes('Особо')) return '300-311';
	        if (title.includes('Особо тяжкие')) return '400-411';
	        if (title.includes('Критические')) return '500-511';
	        
	        return null;
	    },
	    
	    applyCategoryInfo: function(categories) {
	        // Применяем информацию о категориях к законам
	        Object.keys(this.lawData).forEach(function(lawCode) {
	            var code = parseInt(lawCode);
	            var categoryKey = null;
	            
	            // Определяем категорию по номеру статьи
	            if (code >= 100 && code <= 109) categoryKey = '100-109';
	            else if (code >= 200 && code <= 211) categoryKey = '200-211';
	            else if (code >= 300 && code <= 311) categoryKey = '300-311';
	            else if (code >= 400 && code <= 411) categoryKey = '400-411';
	            else if (code >= 500 && code <= 511) categoryKey = '500-511';
	            
	            if (categoryKey && categories[categoryKey]) {
	                this.lawData[lawCode].category = categories[categoryKey];
	            }
	        }.bind(this));
	    },
	    
	    createModeToggle: function() {
	        var tables = document.querySelectorAll('.citizen-table-wrapper table');
	        
	        tables.forEach(function(table) {
	            var wrapper = table.closest('.citizen-table-wrapper');
	            if (!wrapper || wrapper.querySelector('.law-mode-toggle')) return;
	            
            var toggleContainer = document.createElement('div');
            toggleContainer.className = 'law-mode-toggle';
            toggleContainer.innerHTML = 
                '<div class="mode-toggle-buttons">' +
                    '<button class="mode-btn active" data-mode="navigation">Навигация</button>' +
                    '<button class="mode-btn" data-mode="calculator">Калькулятор</button>' +
                '</div>';
	            
	            wrapper.appendChild(toggleContainer);
	            
	            // Добавляем стили
	            this.addToggleStyles();
	            
	            // Обработчики событий
	            var buttons = toggleContainer.querySelectorAll('.mode-btn');
	            buttons.forEach(function(btn) {
	                btn.addEventListener('click', function() {
	                    buttons.forEach(function(b) { b.classList.remove('active'); });
	                    this.classList.add('active');
	                    
	                    var mode = this.dataset.mode;
	                    LawCalculatorModule.setMode(mode, table);
	                });
	            });
	        }.bind(this));
	    },
	    
	    addToggleStyles: function() {
	        if (document.getElementById('law-calculator-styles')) return;
	        
        var style = document.createElement('style');
        style.id = 'law-calculator-styles';
        style.textContent = 
            '.law-mode-toggle {' +
                'margin: 10px 0;' +
                'text-align: center;' +
            '}' +
            '.mode-toggle-buttons {' +
                'display: inline-flex;' +
                'background: #f0f0f0;' +
                'border-radius: 5px;' +
                'padding: 2px;' +
                'border: 1px solid #ccc;' +
            '}' +
            '.mode-btn {' +
                'padding: 8px 16px;' +
                'border: none;' +
                'background: transparent;' +
                'cursor: pointer;' +
                'border-radius: 3px;' +
                'font-size: 14px;' +
                'transition: all 0.2s;' +
            '}' +
            '.mode-btn.active {' +
                'background: #007cba;' +
                'color: white;' +
            '}' +
            '.mode-btn:hover:not(.active) {' +
                'background: #e0e0e0;' +
            '}' +
            '.calculator-interface {' +
                'margin-top: 15px;' +
                'padding: 15px;' +
                'background: #f9f9f9;' +
                'border: 1px solid #ddd;' +
                'border-radius: 5px;' +
                'display: none;' +
            '}' +
            '.calculator-interface.active {' +
                'display: block;' +
            '}' +
            '.selected-violations {' +
                'margin: 10px 0;' +
            '}' +
            '.violation-item {' +
                'display: inline-block;' +
                'margin: 5px;' +
                'padding: 5px 10px;' +
                'background: #e3f2fd;' +
                'border: 1px solid #2196f3;' +
                'border-radius: 15px;' +
                'font-size: 12px;' +
            '}' +
            '.violation-item .remove-btn {' +
                'margin-left: 5px;' +
                'cursor: pointer;' +
                'color: #f44336;' +
                'font-weight: bold;' +
            '}' +
            '.calculation-result {' +
                'margin-top: 15px;' +
                'padding: 10px;' +
                'background: #fff3cd;' +
                'border: 1px solid #ffeaa7;' +
                'border-radius: 5px;' +
                'font-weight: bold;' +
                'white-space: pre-line;' +
            '}' +
            '.calculation-result.critical {' +
                'background: #f8d7da;' +
                'border-color: #f5c6cb;' +
                'color: #721c24;' +
            '}' +
            '.law-cell-calculator {' +
                'cursor: pointer;' +
                'transition: background-color 0.2s;' +
            '}' +
            '.law-cell-calculator:hover {' +
                'background-color: rgba(0, 124, 186, 0.1) !important;' +
            '}' +
            '.law-cell-calculator.selected {' +
                'background-color: rgba(0, 124, 186, 0.3) !important;' +
            '}' +
            '.calculator-actions {' +
                'margin-top: 10px;' +
            '}' +
            '.calculator-actions button {' +
                'padding: 8px 16px;' +
                'border: 1px solid #ccc;' +
                'background: white;' +
                'cursor: pointer;' +
                'border-radius: 3px;' +
                'font-size: 14px;' +
            '}' +
            '.calculator-actions button:hover {' +
                'background: #f0f0f0;' +
            '}' +
            '.calculator-actions .calculate-btn {' +
                'background: #007cba;' +
                'color: white;' +
                'border-color: #007cba;' +
            '}' +
            '.calculator-actions .calculate-btn:hover {' +
                'background: #005a87;' +
            '}';
	        
	        document.head.appendChild(style);
	    },
	    
	    setMode: function(mode, table) {
	        this.isCalculatorMode = (mode === 'calculator');
	        
	        var wrapper = table.closest('.citizen-table-wrapper');
	        var calculatorInterface = wrapper.querySelector('.calculator-interface');
	        
	        if (this.isCalculatorMode) {
	            if (!calculatorInterface) {
	                calculatorInterface = this.createCalculatorInterface();
	                wrapper.appendChild(calculatorInterface);
	            }
	            calculatorInterface.classList.add('active');
	            this.makeTableInteractive(table);
	        } else {
	            if (calculatorInterface) {
	                calculatorInterface.classList.remove('active');
	            }
	            this.makeTableNormal(table);
	        }
	    },
	    
	    createCalculatorInterface: function() {
        var calculatorInterface = document.createElement('div');
        calculatorInterface.className = 'calculator-interface';
        calculatorInterface.innerHTML = 
            '<h4>Калькулятор сроков заключения</h4>' +
            '<p>Выберите нарушения, кликая по статьям в таблице выше:</p>' +
            '<div class="selected-violations">' +
                '<div class="violations-list"></div>' +
            '</div>' +
            '<div class="calculation-result" style="display: none;"></div>' +
            '<div class="calculator-actions">' +
                '<button class="clear-btn" style="margin-right: 10px;">Очистить</button>' +
                '<button class="calculate-btn">Рассчитать</button>' +
            '</div>';
	        
	        // Обработчики событий
	        calculatorInterface.querySelector('.clear-btn').addEventListener('click', function() {
	            LawCalculatorModule.clearSelection();
	        });
	        
	        calculatorInterface.querySelector('.calculate-btn').addEventListener('click', function() {
	            LawCalculatorModule.calculateSentence();
	        });
	        
	        return calculatorInterface;
	    },
	    
	    makeTableInteractive: function(table) {
	        var cells = table.querySelectorAll('td');
	        cells.forEach(function(cell) {
	            var link = cell.querySelector('a[href*="#"]');
	            if (!link) return;
	            
	            var href = link.getAttribute('href');
	            var match = href.match(/#(\d{3})/);
	            if (!match) return;
	            
	            var lawCode = match[1];
	            if (!this.lawData[lawCode]) return;
	            
	            cell.classList.add('law-cell-calculator');
	            cell.dataset.lawCode = lawCode;
	            
	            // Сохраняем оригинальный обработчик клика
	            var originalClickHandler = cell.onclick;
	            
	            cell.addEventListener('click', function(e) {
	                e.preventDefault();
	                e.stopPropagation();
	                LawCalculatorModule.toggleViolation(lawCode, cell);
	            });
	        }.bind(this));
	    },
	    
	    makeTableNormal: function(table) {
	        var cells = table.querySelectorAll('.law-cell-calculator');
	        cells.forEach(function(cell) {
	            cell.classList.remove('law-cell-calculator', 'selected');
	            // Восстанавливаем оригинальную функциональность навигации
	            var lawCode = cell.dataset.lawCode;
	            if (lawCode) {
	                cell.addEventListener('click', function(e) {
	                    e.preventDefault();
	                    window.location.hash = lawCode;
	                });
	            }
	        });
	    },
	    
	    toggleViolation: function(lawCode, cell) {
	        var index = this.selectedViolations.indexOf(lawCode);
	        
	        if (index > -1) {
	            // Убираем нарушение
	            this.selectedViolations.splice(index, 1);
	            cell.classList.remove('selected');
	        } else {
	            // Добавляем нарушение
	            this.selectedViolations.push(lawCode);
	            cell.classList.add('selected');
	        }
	        
	        this.updateViolationsList();
	    },
	    
	    updateViolationsList: function() {
	        var violationsList = document.querySelector('.violations-list');
	        if (!violationsList) return;
	        
	        violationsList.innerHTML = '';
	        
	        this.selectedViolations.forEach(function(lawCode) {
	            var law = this.lawData[lawCode];
	            if (!law) return;
	            
            var item = document.createElement('div');
            item.className = 'violation-item';
            item.innerHTML = 
                lawCode + ' - ' + law.title +
                '<span class="remove-btn" data-law-code="' + lawCode + '">×</span>';
	            
	            item.querySelector('.remove-btn').addEventListener('click', function() {
	                LawCalculatorModule.removeViolation(lawCode);
	            });
	            
	            violationsList.appendChild(item);
	        }.bind(this));
	    },
	    
	    removeViolation: function(lawCode) {
	        var index = this.selectedViolations.indexOf(lawCode);
	        if (index > -1) {
	            this.selectedViolations.splice(index, 1);
	            
            // Убираем выделение с ячейки
            var cell = document.querySelector('[data-law-code="' + lawCode + '"]');
            if (cell) {
                cell.classList.remove('selected');
            }
	            
	            this.updateViolationsList();
	        }
	    },
	    
	    clearSelection: function() {
	        this.selectedViolations = [];
	        
	        // Убираем выделение со всех ячеек
	        var selectedCells = document.querySelectorAll('.law-cell-calculator.selected');
	        selectedCells.forEach(function(cell) {
	            cell.classList.remove('selected');
	        });
	        
	        this.updateViolationsList();
	        this.hideResult();
	    },
	    
	    calculateSentence: function() {
	        if (this.selectedViolations.length === 0) {
	            alert('Выберите хотя бы одно нарушение');
	            return;
	        }
	        
	            var result = this.calculateSentenceLogic(this.selectedViolations);
	            this.showResult(result);
	        },
	        
	        calculateSentenceLogic: function(violations) {
	            // Группируем нарушения по категориям
	            var categories = {};
	            
	            violations.forEach(function(lawCode) {
	                var law = this.lawData[lawCode];
	                if (!law || !law.category) return;
	                
	                // Используем номер статьи как ключ категории
	                var categoryKey = this.getCategoryKeyByLawCode(lawCode);
	                if (!categories[categoryKey]) {
	                    categories[categoryKey] = [];
	                }
	                categories[categoryKey].push(law);
	            }.bind(this));
	            
	            var totalMinTime = 0;
	            var totalMaxTime = 0;
	            var totalFine = 0;
	            var hasCritical = false;
	            var resultText = '';
	            
	            // Обрабатываем каждую категорию
	            Object.keys(categories).forEach(function(categoryKey) {
	                var laws = categories[categoryKey];
	                var category = laws[0].category;
	                var categoryName = this.getCategoryName(categoryKey);
	                
                if (category.isCritical) {
                    hasCritical = true;
                    resultText += '• ' + categoryName + ': ' + (category.punishment || 'Перевод в Д-класс/казнь') + '\n';
                } else {
	                    // Для одной категории берем самую тяжкую статью
	                    var maxLaw = laws.reduce(function(max, current) {
	                        var currentCode = parseInt(lawCode);
	                        var maxCode = parseInt(max.title.match(/\d{3}/)[0]);
	                        return currentCode > maxCode ? current : max;
	                    });
	                    
	                    totalMinTime += category.minTime || 0;
	                    totalMaxTime += category.maxTime || 0;
	                    totalFine += category.fine || 0;
	                    
	                    var punishmentText = '';
	                    if (category.punishment) {
	                        punishmentText = category.punishment;
	                    } else if (category.minTime !== undefined) {
	                        punishmentText = category.minTime === category.maxTime ? 
	                            category.minTime + ' минут' : 
	                            category.minTime + '-' + category.maxTime + ' минут';
	                    }
	                    
	                    resultText += '• ' + categoryName + ': ' + punishmentText + ' (статья ' + lawCode + ')\n';
	                }
	            }.bind(this));
	            
	            if (hasCritical) {
	                return {
	                    isCritical: true,
	                    text: 'КРИТИЧЕСКИЕ НАРУШЕНИЯ\n' + resultText + '\nПриговор: Перевод в Д-класс или казнь'
	                };
	            } else if (this.pageType === 'd-class') {
	                // Для Д-класса показываем штрафы и время отдельно
	                var summaryText = '';
                if (totalFine > 0) {
                    summaryText += 'Общий штраф: ' + totalFine + ' кредитов\n';
                }
                if (totalMinTime > 0 || totalMaxTime > 0) {
                    summaryText += 'Общее время: ' + this.formatTime(totalMinTime, totalMaxTime) + '\n';
                }
	                
	                return {
	                    isCritical: false,
	                    text: 'РАСЧЕТ НАКАЗАНИЙ Д-КЛАССА\n' + resultText + '\n' + summaryText
	                };
	            } else if (totalMinTime > 0 || totalMaxTime > 0) {
	                var timeText = this.formatTime(totalMinTime, totalMaxTime);
	                return {
	                    isCritical: false,
	                    text: 'РАСЧЕТ СРОКА ЗАКЛЮЧЕНИЯ\n' + resultText + '\nОбщий срок: ' + timeText
	                };
	            } else {
	                return {
	                    isCritical: false,
	                    text: 'РАСЧЕТ НАКАЗАНИЙ\n' + resultText + '\nНе удалось определить наказания'
	                };
	            }
	        },
	        
	        getCategoryKeyByLawCode: function(lawCode) {
	            var code = parseInt(lawCode);
	            if (code >= 100 && code <= 109) return '100-109';
	            else if (code >= 200 && code <= 211) return '200-211';
	            else if (code >= 300 && code <= 311) return '300-311';
	            else if (code >= 400 && code <= 411) return '400-411';
	            else if (code >= 500 && code <= 511) return '500-511';
	            return 'unknown';
	        },
	        
	        getCategoryName: function(categoryKey) {
	            var names = {
	                '100-109': 'Лёгкие нарушения',
	                '200-211': 'Средние нарушения',
	                '300-311': 'Тяжкие нарушения',
	                '400-411': 'Особо тяжкие нарушения',
	                '500-511': 'Критические нарушения'
	            };
	            return names[categoryKey] || 'Неизвестная категория';
	        },
	        
	        formatTime: function(minTime, maxTime) {
	            if (minTime === maxTime) {
	                return this.formatMinutes(minTime);
	            } else {
	                return this.formatMinutes(minTime) + ' - ' + this.formatMinutes(maxTime);
	            }
	        },
	        
	        formatMinutes: function(minutes) {
	            if (minutes < 60) {
	                return minutes + ' минут';
	            } else {
	                var hours = Math.floor(minutes / 60);
	                var remainingMinutes = minutes % 60;
	                var result = hours + ' час';
	                if (hours > 1 && hours < 5) result += 'а';
	                if (hours >= 5) result += 'ов';
	                if (remainingMinutes > 0) {
	                    result += ' ' + remainingMinutes + ' минут';
	                }
	                return result;
	            }
	        },
	        
	        showResult: function(result) {
	            var resultDiv = document.querySelector('.calculation-result');
	            if (!resultDiv) return;
	            
	            resultDiv.textContent = result.text;
	            resultDiv.className = 'calculation-result' + (result.isCritical ? ' critical' : '');
	            resultDiv.style.display = 'block';
	        },
	        
	        hideResult: function() {
	            var resultDiv = document.querySelector('.calculation-result');
	            if (resultDiv) {
	                resultDiv.style.display = 'none';
	            }
	        },
	        
	        observeTables: 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('citizen-table-wrapper')) {
	                                setTimeout(function() {
	                                    LawCalculatorModule.createModeToggle();
	                                }, 100);
	                            } else if (node.querySelectorAll) {
	                                var tables = node.querySelectorAll('.citizen-table-wrapper');
	                                if (tables.length > 0) {
	                                    setTimeout(function() {
	                                        LawCalculatorModule.createModeToggle();
	                                    }, 100);
	                                }
	                            }
	                        }
	                    });
	                });
	            });
	            
	            observer.observe(document.body, {
	                childList: true,
	                subtree: true
	            });
	        }
	    };
    
    function initAllModules() {
        SidebarModule.init();
        AccessTooltipsModule.init();
        LawTooltipsModule.init();
        DataTooltipsModule.init();
        CopyTextModule.init();
        DocumentAutoFillModule.init();
        // LawCalculatorModule.init();
    }
    
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initAllModules);
    } else {
        initAllModules();
    }
    
})();