这是测试站点!!!!
不要保存重要内容!不要保存重要内容!不要保存重要内容!不要保存重要内容!不要保存重要内容!
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(); }
}());
