MediaWiki:Common.js

From Toon Wiki
Revision as of 22:52, 22 December 2025 by Admin (talk | contribs) (Add interactive features)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
/* ============================================
   TOON WIKI - INTERACTIVE FEATURES
   ============================================ */

(function() {
    'use strict';
    
    // Wait for DOM ready
    document.addEventListener('DOMContentLoaded', function() {
        
        // ===== Smooth Scroll for TOC links =====
        document.querySelectorAll('.toc a, a[href^="#"]').forEach(function(link) {
            link.addEventListener('click', function(e) {
                var targetId = this.getAttribute('href');
                if (targetId && targetId.startsWith('#')) {
                    var target = document.querySelector(targetId);
                    if (target) {
                        e.preventDefault();
                        target.scrollIntoView({ behavior: 'smooth', block: 'start' });
                        history.pushState(null, null, targetId);
                    }
                }
            });
        });
        
        // ===== Lazy load images =====
        if ('IntersectionObserver' in window) {
            var imageObserver = new IntersectionObserver(function(entries) {
                entries.forEach(function(entry) {
                    if (entry.isIntersecting) {
                        var img = entry.target;
                        if (img.dataset.src) {
                            img.src = img.dataset.src;
                            img.removeAttribute('data-src');
                        }
                        imageObserver.unobserve(img);
                    }
                });
            }, { rootMargin: '50px' });
            
            document.querySelectorAll('img[data-src]').forEach(function(img) {
                imageObserver.observe(img);
            });
        }
        
        // ===== Image lightbox effect =====
        document.querySelectorAll('.mw-parser-output figure img').forEach(function(img) {
            img.style.cursor = 'zoom-in';
            img.addEventListener('click', function(e) {
                e.preventDefault();
                var overlay = document.createElement('div');
                overlay.style.cssText = 'position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.9);z-index:10000;display:flex;align-items:center;justify-content:center;cursor:zoom-out;opacity:0;transition:opacity 0.3s';
                
                var largeImg = document.createElement('img');
                largeImg.src = this.closest('a') ? this.closest('a').href : this.src;
                largeImg.style.cssText = 'max-width:90vw;max-height:90vh;border-radius:8px;box-shadow:0 4px 32px rgba(0,0,0,0.5)';
                
                overlay.appendChild(largeImg);
                document.body.appendChild(overlay);
                document.body.style.overflow = 'hidden';
                
                requestAnimationFrame(function() { overlay.style.opacity = '1'; });
                
                overlay.addEventListener('click', function() {
                    overlay.style.opacity = '0';
                    setTimeout(function() {
                        overlay.remove();
                        document.body.style.overflow = '';
                    }, 300);
                });
            });
        });
        
        // ===== Collapsible sections =====
        document.querySelectorAll('.mw-parser-output h2, .mw-parser-output h3').forEach(function(header) {
            header.style.cursor = 'pointer';
            header.title = 'Click to collapse/expand';
            
            var collapseBtn = document.createElement('span');
            collapseBtn.textContent = ' ▼';
            collapseBtn.style.cssText = 'font-size:0.7em;opacity:0.5;transition:transform 0.2s';
            header.appendChild(collapseBtn);
            
            header.addEventListener('click', function() {
                var content = [];
                var next = this.nextElementSibling;
                var nextHeaderLevel = this.tagName;
                
                while (next && !next.matches(nextHeaderLevel + ', h2')) {
                    content.push(next);
                    next = next.nextElementSibling;
                }
                
                var isCollapsed = content[0] && content[0].style.display === 'none';
                content.forEach(function(el) {
                    el.style.display = isCollapsed ? '' : 'none';
                });
                collapseBtn.style.transform = isCollapsed ? '' : 'rotate(-90deg)';
            });
        });
        
        // ===== Reading time estimate =====
        var content = document.querySelector('.mw-parser-output');
        if (content) {
            var text = content.textContent;
            var words = text.trim().split(/\s+/).length;
            var minutes = Math.ceil(words / 200);
            
            var readingTime = document.createElement('div');
            readingTime.style.cssText = 'background:linear-gradient(135deg,#f8f9fa,#eaecf0);padding:8px 16px;border-radius:8px;margin-bottom:1em;font-size:0.9em;color:#555;display:flex;align-items:center;gap:8px';
            readingTime.innerHTML = '<span style="font-size:1.2em">📖</span> <strong>' + minutes + ' min read</strong> · ' + words.toLocaleString() + ' words';
            
            var firstElement = content.firstElementChild;
            if (firstElement) {
                content.insertBefore(readingTime, firstElement);
            }
        }
        
        // ===== Highlight current section while scrolling =====
        var headings = document.querySelectorAll('.mw-parser-output h2[id], .mw-parser-output h3[id]');
        var tocLinks = document.querySelectorAll('.toc a');
        
        if (headings.length > 0 && tocLinks.length > 0) {
            var highlightCurrentSection = function() {
                var scrollPos = window.scrollY + 100;
                var current = null;
                
                headings.forEach(function(heading) {
                    if (heading.offsetTop <= scrollPos) {
                        current = heading.id;
                    }
                });
                
                tocLinks.forEach(function(link) {
                    link.style.fontWeight = '';
                    link.style.color = '';
                    if (link.getAttribute('href') === '#' + current) {
                        link.style.fontWeight = 'bold';
                        link.style.color = '#1a4d7a';
                    }
                });
            };
            
            window.addEventListener('scroll', highlightCurrentSection);
            highlightCurrentSection();
        }
        
        // ===== Back to top button =====
        var backToTop = document.createElement('button');
        backToTop.textContent = '↑';
        backToTop.style.cssText = 'position:fixed;bottom:20px;right:20px;width:50px;height:50px;border-radius:50%;background:linear-gradient(135deg,#1a4d7a,#2c5aa0);color:white;border:none;font-size:24px;cursor:pointer;opacity:0;transition:all 0.3s;z-index:1000;box-shadow:0 4px 12px rgba(0,0,0,0.3)';
        backToTop.title = 'Back to top';
        document.body.appendChild(backToTop);
        
        backToTop.addEventListener('click', function() {
            window.scrollTo({ top: 0, behavior: 'smooth' });
        });
        
        window.addEventListener('scroll', function() {
            backToTop.style.opacity = window.scrollY > 300 ? '1' : '0';
            backToTop.style.pointerEvents = window.scrollY > 300 ? 'auto' : 'none';
        });
        
    });
})();