MediaWiki:Common.js: відмінності між версіями

Матеріал з darnytsa_hero
Перейти до навігації Перейти до пошуку
Немає опису редагування
Немає опису редагування
Рядок 108: Рядок 108:
     'use strict';
     'use strict';
      
      
     // Конфигурация в стиле MediaViewer
     // Конфигурація в стилі MediaViewer
     const config = {
     const config = {
        // Стиль оверлею
         overlayBg: 'rgba(0,0,0,0.95)',
         overlayBg: 'rgba(0,0,0,0.95)',
         imageMaxWidth: '90%',
        animationDuration: '0.3s',
         imageMaxHeight: '90%',
       
         closeBtnText: '×',
        // Стиль зображення
         closeBtnStyle: {
         imageMaxWidth: '90vw',
         imageMaxHeight: '80vh', // Зменшимо для місця під кнопки
       
        // Панель інформації
         infoPanel: {
            background: 'rgba(0,0,0,0.8)',
            color: '#fff',
            padding: '15px',
            borderRadius: '8px',
            marginTop: '15px',
            maxWidth: '600px',
            fontSize: '14px'
        },
       
        // Кнопки
         buttons: {
             background: 'rgba(0,0,0,0.7)',
             background: 'rgba(0,0,0,0.7)',
             color: 'white',
             color: '#fff',
             border: 'none',
             size: '40px',
            borderRadius: '50%',
             fontSize: '18px',
            width: '40px',
             borderRadius: '5px',
            height: '40px',
             margin: '5px'
             fontSize: '24px',
             cursor: 'pointer',
            position: 'absolute',
            top: '20px',
             right: '20px'
         },
         },
         zoomBtnStyle: {
          
            background: 'rgba(0,0,0,0.7)',
        // Винятки
            color: 'white',
        excludeSelectors: [
             border: 'none',
             '.no-overlay',
             borderRadius: '50%',
             '[data-no-overlay]',
             width: '40px',
             '.mw-editsection img',
             height: '40px',
             '.sprite',
             fontSize: '20px',
             '.icon',
             cursor: 'pointer',
             '.logo',
             position: 'absolute',
             '.nav-icon'
            right: '20px'
         ]
         }
     };
     };


    let currentOverlay = null;
    let currentImageIndex = 0;
    let imagesInGallery = [];
     let currentScale = 1;
     let currentScale = 1;
     const minScale = 0.5;
     const minScale = 0.5;
Рядок 146: Рядок 159:
     const scaleStep = 0.25;
     const scaleStep = 0.25;


     // Функция для создания оверлея в стиле MediaViewer
     // Створення оверлею в стилі MediaViewer
     function showCustomOverlay(url) {
     function createMediaViewerStyleOverlay() {
         const overlay = document.createElement('div');
         const overlay = document.createElement('div');
         overlay.style.position = 'fixed';
         overlay.className = 'custom-media-viewer';
         overlay.style.top = '0';
         overlay.style.cssText = `
        overlay.style.left = '0';
            position: fixed;
        overlay.style.width = '100%';
            top: 0;
        overlay.style.height = '100%';
            left: 0;
        overlay.style.background = config.overlayBg;
            width: 100%;
        overlay.style.display = 'flex';
            height: 100%;
        overlay.style.justifyContent = 'center';
            background: ${config.overlayBg};
        overlay.style.alignItems = 'center';
            display: none;
        overlay.style.zIndex = '10000';
            justify-content: center;
         overlay.style.cursor = 'default';
            align-items: center;
            z-index: 10000;
            opacity: 0;
            transition: opacity ${config.animationDuration} ease;
         `;


         // Контейнер для изображения и кнопок
         // Контейнер для всього вмісту
         const container = document.createElement('div');
         const contentContainer = document.createElement('div');
         container.style.position = 'relative';
         contentContainer.style.cssText = `
        container.style.display = 'flex';
            position: relative;
        container.style.justifyContent = 'center';
            max-width: 95vw;
        container.style.alignItems = 'center';
            max-height: 95vh;
         container.style.maxWidth = '95vw';
            display: flex;
        container.style.maxHeight = '95vh';
            flex-direction: column;
            align-items: center;
         `;


         // Изображение
         // Верхня панель з кнопкою закриття
         const img = document.createElement('img');
         const topPanel = document.createElement('div');
         img.src = url;
         topPanel.style.cssText = `
        img.style.maxWidth = config.imageMaxWidth;
            width: 100%;
        img.style.maxHeight = config.imageMaxHeight;
            display: flex;
        img.style.objectFit = 'contain';
            justify-content: flex-end;
        img.style.borderRadius = '8px';
            margin-bottom: 15px;
        img.style.boxShadow = '0 10px 30px rgba(0,0,0,0.5)';
         `;
        img.style.transition = 'transform 0.3s ease';
         img.style.cursor = 'default'; // Убираем курсор лупы


        // Кнопка закрытия (как в MediaViewer)
         const closeBtn = document.createElement('button');
         const closeBtn = document.createElement('button');
         closeBtn.innerHTML = config.closeBtnText;
         closeBtn.innerHTML = '×';
         closeBtn.title = 'Закрити (Esc)';
         closeBtn.title = 'Закрити (Esc)';
         closeBtn.style.cssText = Object.entries(config.closeBtnStyle).map(([key, value]) =>
         closeBtn.style.cssText = `
             `${key}: ${value};`).join('');
            width: ${config.buttons.size};
        closeBtn.style.zIndex = '10001';
            height: ${config.buttons.size};
            background: ${config.buttons.background};
            color: ${config.buttons.color};
            border: none;
            border-radius: 50%;
            font-size: 20px;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: all 0.2s ease;
        `;
 
        // Контейнер для зображення
        const imageContainer = document.createElement('div');
        imageContainer.style.cssText = `
            position: relative;
            display: flex;
            justify-content: center;
            align-items: center;
            max-width: ${config.imageMaxWidth};
            max-height: ${config.imageMaxHeight};
            margin-bottom: 15px;
        `;
 
        const img = document.createElement('img');
        img.style.cssText = `
            max-width: 100%;
            max-height: 100%;
            object-fit: contain;
            border-radius: 8px;
            box-shadow: 0 10px 30px rgba(0,0,0,0.5);
            cursor: default;
            transition: transform 0.3s ease;
        `;
 
        // Кнопки навігації (зліва/справа від зображення)
        const prevBtn = createNavButton('‹', 'Попереднє зображення (←)');
        const nextBtn = createNavButton('›', 'Наступне зображення (→)');
        prevBtn.style.left = '15px';
        nextBtn.style.right = '15px';
 
        // Панель кнопок під зображенням
        const buttonPanel = document.createElement('div');
        buttonPanel.style.cssText = `
            display: flex;
            justify-content: center;
            align-items: center;
            gap: 10px;
             margin-top: 10px;
        `;
 
        // Кнопки масштабування
        const zoomOutBtn = createToolButton('−', 'Зменшити (Ctrl + -)');
        const resetZoomBtn = createToolButton('1:1', 'Скинути масштаб (Ctrl + 0)');
        const zoomInBtn = createToolButton('+', 'Збільшити (Ctrl + +)');
       
        // Кнопка інформації
        const infoBtn = createToolButton('i', 'Інформація (I)');
 
        // Панель інформації
        const infoPanel = document.createElement('div');
        infoPanel.className = 'image-info-panel';
        infoPanel.style.cssText = `
            background: ${config.infoPanel.background};
            color: ${config.infoPanel.color};
            padding: ${config.infoPanel.padding};
            border-radius: ${config.infoPanel.borderRadius};
            margin-top: 15px;
            max-width: ${config.infoPanel.maxWidth};
            width: 100%;
            text-align: center;
            font-size: ${config.infoPanel.fontSize};
            display: none;
        `;
 
        // Збірка інтерфейсу
        topPanel.appendChild(closeBtn);
       
        imageContainer.appendChild(img);
        imageContainer.appendChild(prevBtn);
        imageContainer.appendChild(nextBtn);
       
        buttonPanel.appendChild(zoomOutBtn);
        buttonPanel.appendChild(resetZoomBtn);
        buttonPanel.appendChild(zoomInBtn);
        buttonPanel.appendChild(infoBtn);
       
        contentContainer.appendChild(topPanel);
        contentContainer.appendChild(imageContainer);
        contentContainer.appendChild(buttonPanel);
        contentContainer.appendChild(infoPanel);
       
        overlay.appendChild(contentContainer);
        document.body.appendChild(overlay);
 
        // Обробники подій
        function setupEventListeners() {
            // Закриття
            const closeOverlay = () => {
                overlay.style.opacity = '0';
                setTimeout(() => {
                    overlay.style.display = 'none';
                    document.body.style.overflow = 'auto';
                    currentOverlay = null;
                    imagesInGallery = [];
                    currentScale = 1;
                }, 300);
            };
 
            closeBtn.addEventListener('click', closeOverlay);
            overlay.addEventListener('click', (e) => {
                if (e.target === overlay) closeOverlay();
            });
 
            // Навігація
            prevBtn.addEventListener('click', (e) => {
                e.stopPropagation();
                navigateImages(-1);
            });
 
            nextBtn.addEventListener('click', (e) => {
                e.stopPropagation();
                navigateImages(1);
            });
 
            // Масштабування
            zoomInBtn.addEventListener('click', (e) => {
                e.stopPropagation();
                zoomImage(currentScale + scaleStep);
            });
 
            zoomOutBtn.addEventListener('click', (e) => {
                e.stopPropagation();
                zoomImage(currentScale - scaleStep);
            });
 
            resetZoomBtn.addEventListener('click', (e) => {
                e.stopPropagation();
                currentScale = 1;
                img.style.transform = 'scale(1)';
                updateZoomButtons();
            });


        // Кнопки зума
            // Інформація
        const zoomInBtn = document.createElement('button');
            infoBtn.addEventListener('click', (e) => {
        zoomInBtn.innerHTML = '+';
                e.stopPropagation();
        zoomInBtn.title = 'Збільшити (Ctrl + +)';
                toggleInfoPanel();
        zoomInBtn.style.cssText = Object.entries(config.zoomBtnStyle).map(([key, value]) =>
             });
             `${key}: ${value};`).join('');
        zoomInBtn.style.top = '70px';
        zoomInBtn.style.zIndex = '10001';


        const zoomOutBtn = document.createElement('button');
            // Клавіатура
        zoomOutBtn.innerHTML = '';
            document.addEventListener('keydown', function keyHandler(e) {
        zoomOutBtn.title = 'Зменшити (Ctrl + -)';
                if (!currentOverlay) return;
        zoomOutBtn.style.cssText = Object.entries(config.zoomBtnStyle).map(([key, value]) =>
               
            `${key}: ${value};`).join('');
                switch(e.key) {
        zoomOutBtn.style.top = '120px';
                    case 'Escape':
        zoomOutBtn.style.zIndex = '10001';
                        closeOverlay();
                        break;
                    case 'ArrowLeft':
                        navigateImages(-1);
                        break;
                    case 'ArrowRight':
                        navigateImages(1);
                        break;
                    case 'i':
                    case 'І': // Українська розкладка
                        e.preventDefault();
                        toggleInfoPanel();
                        break;
                    case '+':
                    case '=':
                        if (e.ctrlKey) {
                            e.preventDefault();
                            zoomImage(currentScale + scaleStep);
                        }
                        break;
                    case '-':
                        if (e.ctrlKey) {
                            e.preventDefault();
                            zoomImage(currentScale - scaleStep);
                        }
                        break;
                    case '0':
                        if (e.ctrlKey) {
                            e.preventDefault();
                            currentScale = 1;
                            img.style.transform = 'scale(1)';
                            updateZoomButtons();
                        }
                        break;
                }
            });


        const resetZoomBtn = document.createElement('button');
            // Hover ефекти
        resetZoomBtn.innerHTML = '1:1';
            [closeBtn, prevBtn, nextBtn, zoomInBtn, zoomOutBtn, resetZoomBtn, infoBtn].forEach(btn => {
        resetZoomBtn.title = 'Скинути масштаб';
                btn.addEventListener('mouseenter', () => {
        resetZoomBtn.style.cssText = Object.entries(config.zoomBtnStyle).map(([key, value]) =>
                    if (!btn.disabled) {
            `${key}: ${value};`).join('');
                        btn.style.background = 'rgba(0,0,0,0.9)';
        resetZoomBtn.style.top = '170px';
                        btn.style.transform = 'scale(1.1)';
        resetZoomBtn.style.zIndex = '10001';
                    }
         resetZoomBtn.style.fontSize = '16px';
                });
                btn.addEventListener('mouseleave', () => {
                    btn.style.background = config.buttons.background;
                    btn.style.transform = 'scale(1)';
                });
            });
         }


         // Функции зума
         // Функції масштабування
         function zoomImage(scale) {
         function zoomImage(scale) {
             currentScale = Math.max(minScale, Math.min(maxScale, scale));
             currentScale = Math.max(minScale, Math.min(maxScale, scale));
Рядок 230: Рядок 426:
         }
         }


         // Обработчики зума
         setupEventListeners();
         zoomInBtn.addEventListener('click', (e) => {
 
             e.stopPropagation();
        return {
             zoomImage(currentScale + scaleStep);
            overlay,
         });
            img,
            infoPanel,
            prevBtn,
            nextBtn,
            zoomInBtn,
            zoomOutBtn,
            resetZoomBtn,
            infoBtn
        };
    }
 
    // Створення кнопки навігації
    function createNavButton(text, title) {
         const btn = document.createElement('button');
        btn.innerHTML = text;
        btn.title = title;
        btn.style.cssText = `
            position: absolute;
            top: 50%;
            transform: translateY(-50%);
            width: ${config.buttons.size};
            height: ${config.buttons.size};
            background: ${config.buttons.background};
            color: ${config.buttons.color};
            border: none;
            border-radius: 50%;
            font-size: ${config.buttons.fontSize};
             cursor: pointer;
            display: none;
            align-items: center;
            justify-content: center;
            transition: all 0.2s ease;
             z-index: 10001;
        `;
         return btn;
    }


         zoomOutBtn.addEventListener('click', (e) => {
    // Створення кнопки інструменту
             e.stopPropagation();
    function createToolButton(text, title) {
             zoomImage(currentScale - scaleStep);
         const btn = document.createElement('button');
         });
        btn.innerHTML = text;
        btn.title = title;
        btn.style.cssText = `
            width: ${config.buttons.size};
             height: ${config.buttons.size};
            background: ${config.buttons.background};
            color: ${config.buttons.color};
            border: none;
            border-radius: ${config.buttons.borderRadius};
            font-size: ${config.buttons.fontSize};
            cursor: pointer;
            display: flex;
            align-items: center;
             justify-content: center;
            transition: all 0.2s ease;
        `;
         return btn;
    }


        resetZoomBtn.addEventListener('click', (e) => {
    // Навігація по зображенням
            e.stopPropagation();
    function navigateImages(direction) {
            currentScale = 1;
        if (imagesInGallery.length <= 1) return;
             img.style.transform = 'scale(1)';
       
            updateZoomButtons();
        currentImageIndex += direction;
         });
       
        if (currentImageIndex < 0) {
             currentImageIndex = imagesInGallery.length - 1;
        } else if (currentImageIndex >= imagesInGallery.length) {
            currentImageIndex = 0;
         }
       
        showImage(imagesInGallery[currentImageIndex]);
    }


        // Закрытие оверлея
    // Показ інформації
        const closeOverlay = () => {
    function toggleInfoPanel() {
            document.body.removeChild(overlay);
        if (!currentOverlay) return;
            document.body.style.overflow = 'auto';
        const infoPanel = currentOverlay.infoPanel;
            currentScale = 1; // Сбрасываем масштаб
        infoPanel.style.display = infoPanel.style.display === 'none' ? 'block' : 'none';
        };
    }


         closeBtn.addEventListener('click', closeOverlay);
    // Збір всіх зображень на сторінці для галереї
    function collectAllImages(clickedImage) {
         const images = Array.from(document.querySelectorAll('img'))
            .filter(img => shouldOpenInOverlay(img) && !img.closest('.custom-media-viewer'))
            .map(img => ({
                src: img.src,
                alt: img.alt || 'Зображення',
                title: img.title || '',
                width: img.naturalWidth,
                height: img.naturalHeight
            }));
          
          
         // Закрытие по клику на фон (но не на изображение или кнопки)
         // Знаходимо індекс поточного зображення
         overlay.addEventListener('click', (e) => {
        currentImageIndex = images.findIndex(img => img.src === clickedImage.src);
             if (e.target === overlay) closeOverlay();
         return images;
         });
    }
 
    // Перевірка, чи повинна картинка відкриватися в оверлеї
    function shouldOpenInOverlay(element) {
        if (config.excludeSelectors.some(selector =>  
            element.matches(selector) || element.closest(selector))) {
             return false;
        }
 
        if (element.width < 50 || element.height < 50) {
            return false;
        }
 
        // Пропускаємо зображення з галерей
        if (element.closest('.gallery, .thumb, .mw-gallery')) {
            return false;
         }
 
        return true;
    }


        // Закрытие по ESC
    // Показ оверлею
        const keyHandler = (e) => {
    function showMediaViewerOverlay(imageElement) {
            if (e.key === 'Escape') {
        if (!currentOverlay) {
                closeOverlay();
             currentOverlay = createMediaViewerStyleOverlay();
                document.removeEventListener('keydown', keyHandler);
         }
             } else if (e.ctrlKey) {
                if (e.key === '+' || e.key === '=') {
                    e.preventDefault();
                    zoomImage(currentScale + scaleStep);
                } else if (e.key === '-') {
                    e.preventDefault();
                    zoomImage(currentScale - scaleStep);
                } else if (e.key === '0') {
                    e.preventDefault();
                    currentScale = 1;
                    img.style.transform = 'scale(1)';
                    updateZoomButtons();
                }
            }
         };
        document.addEventListener('keydown', keyHandler);


         // Hover эффекты для кнопок
         // Збираємо всі зображення для галереї
         [closeBtn, zoomInBtn, zoomOutBtn, resetZoomBtn].forEach(btn => {
         imagesInGallery = collectAllImages(imageElement);
            btn.addEventListener('mouseenter', () => {
       
                btn.style.background = 'rgba(0,0,0,0.9)';
        if (imagesInGallery.length === 0) return;
                btn.style.transform = 'scale(1.1)';
            });
            btn.addEventListener('mouseleave', () => {
                btn.style.background = config.zoomBtnStyle.background;
                btn.style.transform = 'scale(1)';
            });
        });


         // Сборка интерфейса
         showImage(imagesInGallery[currentImageIndex]);
        container.appendChild(img);
          
         container.appendChild(closeBtn);
         // Показуємо оверлей з анімацією
         container.appendChild(zoomInBtn);
        currentOverlay.overlay.style.display = 'flex';
         container.appendChild(zoomOutBtn);
         setTimeout(() => {
        container.appendChild(resetZoomBtn);
            currentOverlay.overlay.style.opacity = '1';
         overlay.appendChild(container);
         }, 10);
          
          
         document.body.appendChild(overlay);
         // Блокуємо прокрутку
         document.body.style.overflow = 'hidden';
         document.body.style.overflow = 'hidden';
          
          
         // Инициализация кнопок зума
         // Показуємо/ховаємо кнопки навігації
         updateZoomButtons();
         currentOverlay.prevBtn.style.display = imagesInGallery.length > 1 ? 'flex' : 'none';
        currentOverlay.nextBtn.style.display = imagesInGallery.length > 1 ? 'flex' : 'none';
       
        // Оновлюємо кнопки масштабування
        currentScale = 1;
        currentOverlay.img.style.transform = 'scale(1)';
        if (currentOverlay.updateZoomButtons) {
            currentOverlay.updateZoomButtons();
        }
     }
     }


     // Перехватываем клики на обычные картинки (без MediaViewer)
     // Показ конкретного зображення
     document.body.addEventListener('click', function(e) {
    function showImage(imageData) {
        if (!currentOverlay) return;
       
        currentOverlay.img.src = imageData.src;
        currentOverlay.img.alt = imageData.alt;
       
        // Оновлюємо інформацію
        currentOverlay.infoPanel.innerHTML = `
            <div><strong>${imageData.alt}</strong></div>
            <div>Розмір: ${imageData.width} × ${imageData.height}px</div>
            <div style="margin-top: 10px; opacity: 0.7;">
                ← → для навігації • I для інформації • Ctrl + +-/0 для масштабу • Esc для закриття
            </div>
        `;
       
        // Скидаємо масштаб для нового зображення
        currentScale = 1;
        currentOverlay.img.style.transform = 'scale(1)';
        if (currentOverlay.updateZoomButtons) {
            currentOverlay.updateZoomButtons();
        }
    }
 
    // Обробник кліків
     document.addEventListener('click', function(e) {
         const target = e.target;
         const target = e.target;


         // Если картинка не часть MediaViewer overlay и нет ссылки на /w/images/
         // Пропускаємо кліки всередині оверлею
         if (target.tagName === 'IMG' && !target.closest('.mediaViewerOverlay')) {
         if (target.closest('.custom-media-viewer')) {
             const parentLink = target.closest('a[href*="/w/images/"]');
             return;
            if (!parentLink) {
        }
                e.preventDefault();
 
                e.stopPropagation();
        // Клік на картинку
                showCustomOverlay(target.src);
        if (target.tagName === 'IMG' && shouldOpenInOverlay(target)) {
            }
            e.preventDefault();
            e.stopPropagation();
            showMediaViewerOverlay(target);
         }
         }


         // Ссылки на файлы, где MediaViewer не срабатывает
         // Клік на посилання з зображенням
         if (target.tagName === 'A' && target.href && target.href.includes('/w/images/')) {
         if (target.tagName === 'A' && target.href && target.href.match(/\.(jpg|jpeg|png|gif|webp)(\?|$)/i)) {
             if (!target.closest('.thumb')) {
             const img = target.querySelector('img');
            if (img && shouldOpenInOverlay(img)) {
                 e.preventDefault();
                 e.preventDefault();
                 e.stopPropagation();
                 e.stopPropagation();
                 showCustomOverlay(target.href);
                 showMediaViewerOverlay(img);
             }
             }
         }
         }
     }, true);
     });


     // Функция добавления кнопки "Закрити" к MediaViewer overlay
     // Функція додавання кнопки "Закрити" до MediaViewer overlay
     function addCloseButtonToMediaViewer() {
     function addCloseButtonToMediaViewer() {
         const overlay = document.querySelector('.mediaViewerOverlay, .mwe-popups');
         const overlay = document.querySelector('.mediaViewerOverlay, .mwe-popups');
Рядок 347: Рядок 644:
         closeBtn.style.right = '20px';
         closeBtn.style.right = '20px';
         closeBtn.style.padding = '10px 20px';
         closeBtn.style.padding = '10px 20px';
         closeBtn.style.fontSize = '18px';
         closeBtn.style.fontSize = '16px';
         closeBtn.style.cursor = 'pointer';
         closeBtn.style.cursor = 'pointer';
         closeBtn.style.background = '#f44336';
         closeBtn.style.background = '#f44336';
Рядок 362: Рядок 659:
     }
     }


     // MutationObserver отслеживает появление overlay MediaViewer
     // MutationObserver відстежує появу overlay MediaViewer
     const observer = new MutationObserver(() => addCloseButtonToMediaViewer());
     const observer = new MutationObserver(() => addCloseButtonToMediaViewer());
     observer.observe(document.body, { childList: true, subtree: true });
     observer.observe(document.body, { childList: true, subtree: true });


     // Стили для улучшения внешнего вида
     // Стилі для поліпшення зовнішнього вигляду
     const style = document.createElement('style');
     const style = document.createElement('style');
     style.textContent = `
     style.textContent = `
         button {
         .custom-media-viewer * {
             transition: all 0.2s ease !important;
             box-sizing: border-box;
         }
         }
          
          
         button:hover:not(:disabled) {
         .custom-media-viewer button:hover:not(:disabled) {
             transform: scale(1.1) !important;
             transform: scale(1.1) !important;
             background: rgba(0,0,0,0.9) !important;
             background: rgba(0,0,0,0.9) !important;
         }
         }
          
          
         button:disabled {
         .custom-media-viewer button:disabled {
             cursor: not-allowed !important;
             cursor: not-allowed !important;
            opacity: 0.5 !important;
        }
       
        .custom-media-viewer img {
            transition: transform 0.3s ease !important;
         }
         }
          
          
         @media (max-width: 768px) {
         @media (max-width: 768px) {
             button {
             .custom-media-viewer button {
                 width: 35px !important;
                 width: 35px !important;
                 height: 35px !important;
                 height: 35px !important;
                 font-size: 18px !important;
                 font-size: 16px !important;
            }
           
            .image-info-panel {
                font-size: 12px !important;
                padding: 10px !important;
             }
             }
         }
         }
     `;
     `;
     document.head.appendChild(style);
     document.head.appendChild(style);
    console.log('Custom MediaViewer loaded successfully');


})();
})();

Версія за 16:29, 24 вересня 2025

$(function () {
    // Теми
    var themes = {
        light: '/w/index.php?title=MediaWiki:Light.css&action=raw&ctype=text/css',
        dark: '/w/index.php?title=MediaWiki:Dark.css&action=raw&ctype=text/css'
    };

    var theme = localStorage.getItem('selectedTheme');
    if (!theme) {
        theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
    }
    if (themes[theme]) mw.loader.load(themes[theme], 'text/css');

    function createButton(text, bottom, onClick, title) {
        var $btn = $('<button>').text(text).attr('title', title).css({
            position: 'fixed',
            bottom: bottom + 'px',
            right: '10px',
            padding: '10px 16px',
            border: 'none',
            borderRadius: '25px',
            background: '#1a73e8',
            color: '#ffffff',
            fontWeight: 'bold',
            fontSize: '14px',
            cursor: 'pointer',
            zIndex: 9999,
            textAlign: 'center',
            boxShadow: '0 2px 6px rgba(0,0,0,0.3)',
            whiteSpace: 'nowrap'
        }).click(onClick);
        $('body').append($btn);
        return $btn;
    }

    // Кнопка Темна/Світла тема
    var $themeBtn = createButton(
        theme === 'dark' ? 'Світла тема ☀️' : 'Темна тема 🌙',
        10,
        function () {
            var newTheme = theme === 'dark' ? 'light' : 'dark';
            localStorage.setItem('selectedTheme', newTheme);
            location.reload();
        },
        'Змінити тему'
    );

    // Змінна для зберігання розміру шрифту
    var fontSize = parseInt($('body').css('font-size'), 10) || 16;
    
    // Функція для застосування розміру шрифту
    function applyFontSize() {
        $('body').css('font-size', fontSize + 'px');
    }

    // Кнопка доступності
    var $accessBtn = createButton(
        'Доступність',
        70,
        function () {
            if (!$('body').hasClass('accessibility-mode')) {
                $('body').addClass('accessibility-mode');
                localStorage.setItem('accessibilityMode', 'on');
                $accessBtn.css('background', '#ff6600');
                $accessBtn.text('Доступність ON');
            } else {
                $('body').removeClass('accessibility-mode');
                localStorage.setItem('accessibilityMode', 'off');
                $accessBtn.css('background', '#1a73e8');
                $accessBtn.text('Доступність OFF');
            }
        },
        'Увімкнути/вимкнути режим доступності'
    );

    // Відновлення стану доступності
    if (localStorage.getItem('accessibilityMode') === 'on') {
        $('body').addClass('accessibility-mode');
        $accessBtn.css('background', '#ff6600');
        $accessBtn.text('Доступність ON');
    }

    // Лупа
    createButton('🔍 +', 130, function () {
        fontSize += 2;
        if (fontSize > 30) fontSize = 30;
        localStorage.setItem('fontSize', fontSize);
        applyFontSize();
    }, 'Збільшити шрифт');

    createButton('🔍 -', 170, function () {
        fontSize -= 2;
        if (fontSize < 12) fontSize = 12;
        localStorage.setItem('fontSize', fontSize);
        applyFontSize();
    }, 'Зменшити шрифт');

    // Відновлення розміру шрифту
    if (localStorage.getItem('fontSize')) {
        fontSize = parseInt(localStorage.getItem('fontSize'), 10);
    }
    applyFontSize();
});


//OVERLAY 
(function() {
    'use strict';
    
    // Конфигурація в стилі MediaViewer
    const config = {
        // Стиль оверлею
        overlayBg: 'rgba(0,0,0,0.95)',
        animationDuration: '0.3s',
        
        // Стиль зображення
        imageMaxWidth: '90vw',
        imageMaxHeight: '80vh', // Зменшимо для місця під кнопки
        
        // Панель інформації
        infoPanel: {
            background: 'rgba(0,0,0,0.8)',
            color: '#fff',
            padding: '15px',
            borderRadius: '8px',
            marginTop: '15px',
            maxWidth: '600px',
            fontSize: '14px'
        },
        
        // Кнопки
        buttons: {
            background: 'rgba(0,0,0,0.7)',
            color: '#fff',
            size: '40px',
            fontSize: '18px',
            borderRadius: '5px',
            margin: '5px'
        },
        
        // Винятки
        excludeSelectors: [
            '.no-overlay',
            '[data-no-overlay]',
            '.mw-editsection img',
            '.sprite',
            '.icon',
            '.logo',
            '.nav-icon'
        ]
    };

    let currentOverlay = null;
    let currentImageIndex = 0;
    let imagesInGallery = [];
    let currentScale = 1;
    const minScale = 0.5;
    const maxScale = 3;
    const scaleStep = 0.25;

    // Створення оверлею в стилі MediaViewer
    function createMediaViewerStyleOverlay() {
        const overlay = document.createElement('div');
        overlay.className = 'custom-media-viewer';
        overlay.style.cssText = `
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: ${config.overlayBg};
            display: none;
            justify-content: center;
            align-items: center;
            z-index: 10000;
            opacity: 0;
            transition: opacity ${config.animationDuration} ease;
        `;

        // Контейнер для всього вмісту
        const contentContainer = document.createElement('div');
        contentContainer.style.cssText = `
            position: relative;
            max-width: 95vw;
            max-height: 95vh;
            display: flex;
            flex-direction: column;
            align-items: center;
        `;

        // Верхня панель з кнопкою закриття
        const topPanel = document.createElement('div');
        topPanel.style.cssText = `
            width: 100%;
            display: flex;
            justify-content: flex-end;
            margin-bottom: 15px;
        `;

        const closeBtn = document.createElement('button');
        closeBtn.innerHTML = '×';
        closeBtn.title = 'Закрити (Esc)';
        closeBtn.style.cssText = `
            width: ${config.buttons.size};
            height: ${config.buttons.size};
            background: ${config.buttons.background};
            color: ${config.buttons.color};
            border: none;
            border-radius: 50%;
            font-size: 20px;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: all 0.2s ease;
        `;

        // Контейнер для зображення
        const imageContainer = document.createElement('div');
        imageContainer.style.cssText = `
            position: relative;
            display: flex;
            justify-content: center;
            align-items: center;
            max-width: ${config.imageMaxWidth};
            max-height: ${config.imageMaxHeight};
            margin-bottom: 15px;
        `;

        const img = document.createElement('img');
        img.style.cssText = `
            max-width: 100%;
            max-height: 100%;
            object-fit: contain;
            border-radius: 8px;
            box-shadow: 0 10px 30px rgba(0,0,0,0.5);
            cursor: default;
            transition: transform 0.3s ease;
        `;

        // Кнопки навігації (зліва/справа від зображення)
        const prevBtn = createNavButton('‹', 'Попереднє зображення (←)');
        const nextBtn = createNavButton('›', 'Наступне зображення (→)');
        prevBtn.style.left = '15px';
        nextBtn.style.right = '15px';

        // Панель кнопок під зображенням
        const buttonPanel = document.createElement('div');
        buttonPanel.style.cssText = `
            display: flex;
            justify-content: center;
            align-items: center;
            gap: 10px;
            margin-top: 10px;
        `;

        // Кнопки масштабування
        const zoomOutBtn = createToolButton('−', 'Зменшити (Ctrl + -)');
        const resetZoomBtn = createToolButton('1:1', 'Скинути масштаб (Ctrl + 0)');
        const zoomInBtn = createToolButton('+', 'Збільшити (Ctrl + +)');
        
        // Кнопка інформації
        const infoBtn = createToolButton('i', 'Інформація (I)');

        // Панель інформації
        const infoPanel = document.createElement('div');
        infoPanel.className = 'image-info-panel';
        infoPanel.style.cssText = `
            background: ${config.infoPanel.background};
            color: ${config.infoPanel.color};
            padding: ${config.infoPanel.padding};
            border-radius: ${config.infoPanel.borderRadius};
            margin-top: 15px;
            max-width: ${config.infoPanel.maxWidth};
            width: 100%;
            text-align: center;
            font-size: ${config.infoPanel.fontSize};
            display: none;
        `;

        // Збірка інтерфейсу
        topPanel.appendChild(closeBtn);
        
        imageContainer.appendChild(img);
        imageContainer.appendChild(prevBtn);
        imageContainer.appendChild(nextBtn);
        
        buttonPanel.appendChild(zoomOutBtn);
        buttonPanel.appendChild(resetZoomBtn);
        buttonPanel.appendChild(zoomInBtn);
        buttonPanel.appendChild(infoBtn);
        
        contentContainer.appendChild(topPanel);
        contentContainer.appendChild(imageContainer);
        contentContainer.appendChild(buttonPanel);
        contentContainer.appendChild(infoPanel);
        
        overlay.appendChild(contentContainer);
        document.body.appendChild(overlay);

        // Обробники подій
        function setupEventListeners() {
            // Закриття
            const closeOverlay = () => {
                overlay.style.opacity = '0';
                setTimeout(() => {
                    overlay.style.display = 'none';
                    document.body.style.overflow = 'auto';
                    currentOverlay = null;
                    imagesInGallery = [];
                    currentScale = 1;
                }, 300);
            };

            closeBtn.addEventListener('click', closeOverlay);
            overlay.addEventListener('click', (e) => {
                if (e.target === overlay) closeOverlay();
            });

            // Навігація
            prevBtn.addEventListener('click', (e) => {
                e.stopPropagation();
                navigateImages(-1);
            });

            nextBtn.addEventListener('click', (e) => {
                e.stopPropagation();
                navigateImages(1);
            });

            // Масштабування
            zoomInBtn.addEventListener('click', (e) => {
                e.stopPropagation();
                zoomImage(currentScale + scaleStep);
            });

            zoomOutBtn.addEventListener('click', (e) => {
                e.stopPropagation();
                zoomImage(currentScale - scaleStep);
            });

            resetZoomBtn.addEventListener('click', (e) => {
                e.stopPropagation();
                currentScale = 1;
                img.style.transform = 'scale(1)';
                updateZoomButtons();
            });

            // Інформація
            infoBtn.addEventListener('click', (e) => {
                e.stopPropagation();
                toggleInfoPanel();
            });

            // Клавіатура
            document.addEventListener('keydown', function keyHandler(e) {
                if (!currentOverlay) return;
                
                switch(e.key) {
                    case 'Escape':
                        closeOverlay();
                        break;
                    case 'ArrowLeft':
                        navigateImages(-1);
                        break;
                    case 'ArrowRight':
                        navigateImages(1);
                        break;
                    case 'i':
                    case 'І': // Українська розкладка
                        e.preventDefault();
                        toggleInfoPanel();
                        break;
                    case '+':
                    case '=':
                        if (e.ctrlKey) {
                            e.preventDefault();
                            zoomImage(currentScale + scaleStep);
                        }
                        break;
                    case '-':
                        if (e.ctrlKey) {
                            e.preventDefault();
                            zoomImage(currentScale - scaleStep);
                        }
                        break;
                    case '0':
                        if (e.ctrlKey) {
                            e.preventDefault();
                            currentScale = 1;
                            img.style.transform = 'scale(1)';
                            updateZoomButtons();
                        }
                        break;
                }
            });

            // Hover ефекти
            [closeBtn, prevBtn, nextBtn, zoomInBtn, zoomOutBtn, resetZoomBtn, infoBtn].forEach(btn => {
                btn.addEventListener('mouseenter', () => {
                    if (!btn.disabled) {
                        btn.style.background = 'rgba(0,0,0,0.9)';
                        btn.style.transform = 'scale(1.1)';
                    }
                });
                btn.addEventListener('mouseleave', () => {
                    btn.style.background = config.buttons.background;
                    btn.style.transform = 'scale(1)';
                });
            });
        }

        // Функції масштабування
        function zoomImage(scale) {
            currentScale = Math.max(minScale, Math.min(maxScale, scale));
            img.style.transform = `scale(${currentScale})`;
            updateZoomButtons();
        }

        function updateZoomButtons() {
            zoomInBtn.disabled = currentScale >= maxScale;
            zoomOutBtn.disabled = currentScale <= minScale;
            
            zoomInBtn.style.opacity = zoomInBtn.disabled ? '0.5' : '1';
            zoomOutBtn.style.opacity = zoomOutBtn.disabled ? '0.5' : '1';
        }

        setupEventListeners();

        return { 
            overlay, 
            img, 
            infoPanel, 
            prevBtn, 
            nextBtn,
            zoomInBtn,
            zoomOutBtn,
            resetZoomBtn,
            infoBtn
        };
    }

    // Створення кнопки навігації
    function createNavButton(text, title) {
        const btn = document.createElement('button');
        btn.innerHTML = text;
        btn.title = title;
        btn.style.cssText = `
            position: absolute;
            top: 50%;
            transform: translateY(-50%);
            width: ${config.buttons.size};
            height: ${config.buttons.size};
            background: ${config.buttons.background};
            color: ${config.buttons.color};
            border: none;
            border-radius: 50%;
            font-size: ${config.buttons.fontSize};
            cursor: pointer;
            display: none;
            align-items: center;
            justify-content: center;
            transition: all 0.2s ease;
            z-index: 10001;
        `;
        return btn;
    }

    // Створення кнопки інструменту
    function createToolButton(text, title) {
        const btn = document.createElement('button');
        btn.innerHTML = text;
        btn.title = title;
        btn.style.cssText = `
            width: ${config.buttons.size};
            height: ${config.buttons.size};
            background: ${config.buttons.background};
            color: ${config.buttons.color};
            border: none;
            border-radius: ${config.buttons.borderRadius};
            font-size: ${config.buttons.fontSize};
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: all 0.2s ease;
        `;
        return btn;
    }

    // Навігація по зображенням
    function navigateImages(direction) {
        if (imagesInGallery.length <= 1) return;
        
        currentImageIndex += direction;
        
        if (currentImageIndex < 0) {
            currentImageIndex = imagesInGallery.length - 1;
        } else if (currentImageIndex >= imagesInGallery.length) {
            currentImageIndex = 0;
        }
        
        showImage(imagesInGallery[currentImageIndex]);
    }

    // Показ інформації
    function toggleInfoPanel() {
        if (!currentOverlay) return;
        const infoPanel = currentOverlay.infoPanel;
        infoPanel.style.display = infoPanel.style.display === 'none' ? 'block' : 'none';
    }

    // Збір всіх зображень на сторінці для галереї
    function collectAllImages(clickedImage) {
        const images = Array.from(document.querySelectorAll('img'))
            .filter(img => shouldOpenInOverlay(img) && !img.closest('.custom-media-viewer'))
            .map(img => ({
                src: img.src,
                alt: img.alt || 'Зображення',
                title: img.title || '',
                width: img.naturalWidth,
                height: img.naturalHeight
            }));
        
        // Знаходимо індекс поточного зображення
        currentImageIndex = images.findIndex(img => img.src === clickedImage.src);
        return images;
    }

    // Перевірка, чи повинна картинка відкриватися в оверлеї
    function shouldOpenInOverlay(element) {
        if (config.excludeSelectors.some(selector => 
            element.matches(selector) || element.closest(selector))) {
            return false;
        }

        if (element.width < 50 || element.height < 50) {
            return false;
        }

        // Пропускаємо зображення з галерей
        if (element.closest('.gallery, .thumb, .mw-gallery')) {
            return false;
        }

        return true;
    }

    // Показ оверлею
    function showMediaViewerOverlay(imageElement) {
        if (!currentOverlay) {
            currentOverlay = createMediaViewerStyleOverlay();
        }

        // Збираємо всі зображення для галереї
        imagesInGallery = collectAllImages(imageElement);
        
        if (imagesInGallery.length === 0) return;

        showImage(imagesInGallery[currentImageIndex]);
        
        // Показуємо оверлей з анімацією
        currentOverlay.overlay.style.display = 'flex';
        setTimeout(() => {
            currentOverlay.overlay.style.opacity = '1';
        }, 10);
        
        // Блокуємо прокрутку
        document.body.style.overflow = 'hidden';
        
        // Показуємо/ховаємо кнопки навігації
        currentOverlay.prevBtn.style.display = imagesInGallery.length > 1 ? 'flex' : 'none';
        currentOverlay.nextBtn.style.display = imagesInGallery.length > 1 ? 'flex' : 'none';
        
        // Оновлюємо кнопки масштабування
        currentScale = 1;
        currentOverlay.img.style.transform = 'scale(1)';
        if (currentOverlay.updateZoomButtons) {
            currentOverlay.updateZoomButtons();
        }
    }

    // Показ конкретного зображення
    function showImage(imageData) {
        if (!currentOverlay) return;
        
        currentOverlay.img.src = imageData.src;
        currentOverlay.img.alt = imageData.alt;
        
        // Оновлюємо інформацію
        currentOverlay.infoPanel.innerHTML = `
            <div><strong>${imageData.alt}</strong></div>
            <div>Розмір: ${imageData.width} × ${imageData.height}px</div>
            <div style="margin-top: 10px; opacity: 0.7;">
                ← → для навігації • I для інформації • Ctrl + +-/0 для масштабу • Esc для закриття
            </div>
        `;
        
        // Скидаємо масштаб для нового зображення
        currentScale = 1;
        currentOverlay.img.style.transform = 'scale(1)';
        if (currentOverlay.updateZoomButtons) {
            currentOverlay.updateZoomButtons();
        }
    }

    // Обробник кліків
    document.addEventListener('click', function(e) {
        const target = e.target;

        // Пропускаємо кліки всередині оверлею
        if (target.closest('.custom-media-viewer')) {
            return;
        }

        // Клік на картинку
        if (target.tagName === 'IMG' && shouldOpenInOverlay(target)) {
            e.preventDefault();
            e.stopPropagation();
            showMediaViewerOverlay(target);
        }

        // Клік на посилання з зображенням
        if (target.tagName === 'A' && target.href && target.href.match(/\.(jpg|jpeg|png|gif|webp)(\?|$)/i)) {
            const img = target.querySelector('img');
            if (img && shouldOpenInOverlay(img)) {
                e.preventDefault();
                e.stopPropagation();
                showMediaViewerOverlay(img);
            }
        }
    });

    // Функція додавання кнопки "Закрити" до MediaViewer overlay
    function addCloseButtonToMediaViewer() {
        const overlay = document.querySelector('.mediaViewerOverlay, .mwe-popups');
        if (!overlay || overlay.dataset.closeBtnAdded) return;
        overlay.dataset.closeBtnAdded = true;

        const closeBtn = document.createElement('button');
        closeBtn.innerText = 'Закрити';
        closeBtn.style.position = 'absolute';
        closeBtn.style.top = '20px';
        closeBtn.style.right = '20px';
        closeBtn.style.padding = '10px 20px';
        closeBtn.style.fontSize = '16px';
        closeBtn.style.cursor = 'pointer';
        closeBtn.style.background = '#f44336';
        closeBtn.style.color = 'white';
        closeBtn.style.border = 'none';
        closeBtn.style.borderRadius = '5px';
        closeBtn.style.zIndex = '10001';
        
        closeBtn.addEventListener('click', () => {
            overlay.style.display = 'none';
        });

        overlay.appendChild(closeBtn);
    }

    // MutationObserver відстежує появу overlay MediaViewer
    const observer = new MutationObserver(() => addCloseButtonToMediaViewer());
    observer.observe(document.body, { childList: true, subtree: true });

    // Стилі для поліпшення зовнішнього вигляду
    const style = document.createElement('style');
    style.textContent = `
        .custom-media-viewer * {
            box-sizing: border-box;
        }
        
        .custom-media-viewer button:hover:not(:disabled) {
            transform: scale(1.1) !important;
            background: rgba(0,0,0,0.9) !important;
        }
        
        .custom-media-viewer button:disabled {
            cursor: not-allowed !important;
            opacity: 0.5 !important;
        }
        
        .custom-media-viewer img {
            transition: transform 0.3s ease !important;
        }
        
        @media (max-width: 768px) {
            .custom-media-viewer button {
                width: 35px !important;
                height: 35px !important;
                font-size: 16px !important;
            }
            
            .image-info-panel {
                font-size: 12px !important;
                padding: 10px !important;
            }
        }
    `;
    document.head.appendChild(style);

    console.log('Custom MediaViewer loaded successfully');

})();