这是测试站点!!!!

不要保存重要内容!不要保存重要内容!不要保存重要内容!不要保存重要内容!不要保存重要内容!

MediaWiki:PD-intro.js

来自Limbo Wiki

注意:在发布之后,您可能需要清除浏览器缓存才能看到所作出的更改的影响。

  • Firefox或Safari:按住Shift的同时单击刷新,或按Ctrl-F5或Ctrl-R(Mac为⌘-R)
  • Google Chrome:按Ctrl-Shift-R(Mac为⌘-Shift-R)
  • Edge:按住Ctrl的同时单击刷新,或按Ctrl-F5。
(function () {
    'use strict';
    function init() {
        var marker = document.querySelector('.pd-intro-marker');
        if (!marker || marker.dataset.pdIntroReady) { return; }
        marker.dataset.pdIntroReady = '1';
        var engine = window.PDIntroEngine;
        if (!engine) { return; }
        marker.dataset.pdIntroVersion = engine.version || 'original';
        var test = marker.dataset.pdIntroTest === '1';
        var key = 'pd-intro-seen-v1', active = null, attempted = false;
        var reduced = window.matchMedia('(prefers-reduced-motion: reduce)');
        var controls = document.createElement('div'); controls.className = 'pd-intro-controls';
        marker.appendChild(controls);
        function staticPreview() {
            if (!test || controls.querySelector('.pd-intro-static')) { return; }
            var box = document.createElement('div'); box.className = 'pd-intro-static';
            var canvas = document.createElement('canvas'); canvas.width = 900; canvas.height = 360;
            canvas.setAttribute('role', 'img'); canvas.setAttribute('aria-label', '静态字符矩阵,中央白底黑字 PROJECT DIVIDE');
            box.appendChild(canvas); controls.appendChild(box);
            var ctx = canvas.getContext('2d'); if (ctx) { engine.draw(ctx, engine.create(12345), 5, 900, 360, 1); }
        }
        function start(forceMotion) {
            if (active) { return; }
            if (reduced.matches && !forceMotion) { staticPreview(); return; }
            attempted = true;
            try { sessionStorage.setItem(key, '1'); } catch (ignored) { /* Storage is optional. */ }
            var overlay, raf = 0, watchdog = 0, finished = false, observer;
            var oldFocus = document.activeElement, sx = window.scrollX, sy = window.scrollY;
            var saved = [], styles = [], inerted = new Set(), timings = [], previousFrame = 0;
            function finish(reason) {
                if (finished) { return; } finished = true;
                cancelAnimationFrame(raf); clearTimeout(watchdog);
                if (observer) { observer.disconnect(); }
                window.removeEventListener('resize', resize);
                window.removeEventListener('pagehide', pagehide);
                window.removeEventListener('beforeprint', beforeprint);
                document.removeEventListener('keydown', keydown, true);
                document.removeEventListener('visibilitychange', visibility);
                reduced.removeEventListener('change', preference);
                if (overlay) { overlay.remove(); }
                saved.forEach(function (item) { item[0].inert = item[1]; });
                styles.forEach(function (item) {
                    if (item[2]) { item[0].style.setProperty(item[1], item[2], item[3]); }
                    else { item[0].style.removeProperty(item[1]); }
                });
                active = null;
                if (oldFocus && oldFocus.isConnected && oldFocus.focus) { oldFocus.focus({preventScroll:true}); }
                window.scrollTo(sx, sy);
                marker.dataset.pdIntroLastExit = reason;
                marker.dataset.pdIntroRuns = String(Number(marker.dataset.pdIntroRuns || 0)+1);
                if (test && timings.length) {
                    marker.dataset.pdIntroTiming = JSON.stringify({frames:timings.length,
                        drawMeanMs:timings.reduce(function(sum,r){return sum+r.draw;},0)/timings.length,
                        maxDrawMs:Math.max.apply(null,timings.map(function(r){return r.draw;})),
                        maxIntervalMs:Math.max.apply(null,timings.map(function(r){return r.interval;}))});
                }
            }
            function saveStyle(el, prop, value) {
                styles.push([el, prop, el.style.getPropertyValue(prop), el.style.getPropertyPriority(prop)]);
                el.style.setProperty(prop, value, 'important');
            }
            function inertChild(el) {
                if (el === overlay || !(el instanceof HTMLElement) || inerted.has(el)) { return; }
                inerted.add(el);
                saved.push([el, el.inert]); el.inert = true;
            }
            function keydown(e) {
                if (e.key === 'Escape') { e.preventDefault(); finish('escape'); }
                else if (e.key === 'Tab') { e.preventDefault(); skip.focus(); }
            }
            function visibility() { if (document.hidden) { finish('hidden'); } }
            function preference() { if (reduced.matches) { finish('reduced-motion'); staticPreview(); } }
            function pagehide() { finish('pagehide'); }
            function beforeprint() { finish('print'); }
            var canvas, ctx, skip, width, height, dpr, model, began;
            function resize() {
                width = window.innerWidth; height = window.innerHeight;
                dpr = Math.min(window.devicePixelRatio || 1, 2);
                canvas.width = Math.round(width*dpr); canvas.height = Math.round(height*dpr);
            }
            function tick(now) {
                if (finished) { return; }
                try {
                    var time = (now-began)/1000;
                    if (time >= 7.3) { finish('complete'); return; }
                    var drawStart = test ? performance.now() : 0;
                    var frame = engine.draw(ctx, model, time, width, height, dpr);
                    if (test) {
                        timings.push({draw:performance.now()-drawStart,interval:previousFrame ? now-previousFrame : 0});
                        previousFrame = now;
                    }
                    overlay.style.opacity = String(frame.opacity);
                    if (test) {
                        overlay.dataset.time = time.toFixed(3); overlay.dataset.locked = frame.locked;
                        overlay.dataset.aligned = frame.aligned; overlay.dataset.scale = frame.scale.toFixed(4);
                    }
                    raf = requestAnimationFrame(tick);
                } catch (error) { finish('render-error'); console.error('Project Divide intro:', error); }
            }
            try {
                overlay = document.createElement('div'); overlay.className = 'pd-intro-overlay';
                overlay.setAttribute('role', 'dialog'); overlay.setAttribute('aria-modal', 'true');
                overlay.setAttribute('aria-label', 'Project Divide 开场动画');
                canvas = document.createElement('canvas'); canvas.className = 'pd-intro-canvas';
                canvas.setAttribute('aria-hidden', 'true'); overlay.appendChild(canvas);
                ctx = canvas.getContext('2d'); if (!ctx) { throw new Error('Canvas 2D unavailable'); }
                skip = document.createElement('button'); skip.type = 'button'; skip.className = 'pd-intro-skip';
                skip.textContent = '跳过开场 · Esc'; skip.addEventListener('click', function () { finish('skip'); });
                overlay.appendChild(skip);
                active = { finish: finish };
                // A loading/error stylesheet must never leave an invisible input trap.
                document.body.appendChild(overlay);
                if (getComputedStyle(overlay).position !== 'fixed') { finish('missing-styles'); return; }
                Array.from(document.body.children).forEach(inertChild);
                observer = new MutationObserver(function (records) {
                    records.forEach(function (r) { r.addedNodes.forEach(inertChild); });
                });
                observer.observe(document.body, { childList: true });
                saveStyle(document.documentElement, 'overflow', 'hidden');
                saveStyle(document.body, 'overflow', 'hidden');
                saveStyle(document.body, 'position', 'fixed');
                saveStyle(document.body, 'top', -sy+'px'); saveStyle(document.body, 'left', -sx+'px');
                saveStyle(document.body, 'width', '100%');
                resize(); model = engine.create(Math.floor(Math.random()*4294967296)); began = performance.now();
                document.addEventListener('keydown', keydown, true);
                document.addEventListener('visibilitychange', visibility);
                window.addEventListener('resize', resize); window.addEventListener('pagehide', pagehide);
                window.addEventListener('beforeprint', beforeprint); reduced.addEventListener('change', preference);
                skip.focus({preventScroll:true});
                watchdog = setTimeout(function () { finish('watchdog'); }, 10000);
                if (document.hidden) { finish('hidden'); return; }
                raf = requestAnimationFrame(tick);
            } catch (error) { finish('init-error'); console.error('Project Divide intro:', error); }
        }
        if (test) {
            var replay = document.createElement('button'); replay.className = 'pd-intro-replay'; replay.type = 'button';
            replay.textContent = '重播开场'; replay.addEventListener('click', function () { start(false); }); controls.appendChild(replay);
            if (reduced.matches) {
                var notice = document.createElement('p'); notice.className = 'pd-intro-notice';
                notice.textContent = '当前启用了减少动态效果,自动开场已跳过。下方保留静态画面;动态试播仅作用于这一次。';
                controls.appendChild(notice); staticPreview();
                var motion = document.createElement('button'); motion.className = 'pd-intro-replay'; motion.type = 'button';
                motion.textContent = '动态试播(仅本次)'; motion.addEventListener('click', function () { start(true); }); controls.appendChild(motion);
            }
        }
        var seen = false; try { seen = sessionStorage.getItem(key) === '1'; } catch (ignored) { /* No persistence. */ }
        if (!attempted && !seen && !window.location.hash && !document.hidden) { start(false); }
    }
    if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init, {once:true}); }
    else { init(); }
}());