MediaWiki:Common.js

Страница интерфейса MediaWiki

Замечание: Возможно, после публикации вам придётся очистить кэш своего браузера, чтобы увидеть изменения.

  • Firefox / Safari: Удерживая клавишу Shift, нажмите на панели инструментов Обновить либо нажмите Ctrl+F5 или Ctrl+R (⌘+R на Mac)
  • Google Chrome: Нажмите Ctrl+Shift+R (⌘+Shift+R на Mac)
  • Internet Explorer / Edge: Удерживая Ctrl, нажмите Обновить либо нажмите Ctrl+F5
  • Opera: Нажмите Ctrl+F5.
(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();
		                    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);
        }
    };
    
    function initAllModules() {
        SidebarModule.init();
        AccessTooltipsModule.init();
        LawTooltipsModule.init();
        DataTooltipsModule.init();
        CopyTextModule.init();
    }
    
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initAllModules);
    } else {
        initAllModules();
    }
    
})();