Mediawiki:common.js

Вернуться

Строка 2222: Строка 2222:


var AprilFoolsCubeTransitionModule = {
var AprilFoolsCubeTransitionModule = {
     FORCE_FOR_ALL: false,
     config: {
    ENABLE_APRIL_FIRST: false,
        // Пока только по флагу:
    DURATION_BEFORE_TRANSITION: 6500,
        enableForAll: false,       // <-- чтобы включить всем, просто поставь true
        enableOnAprilFirst: false, // <-- если потом захочешь автозапуск 1 апреля
        onlyMainPage: true,        // запуск только на главной
        runOncePerSession: true,   // работает только для обычного режима (НЕ для ?prank=1)


        overlayDurationMs: 4200,    // сколько показывать картинку до куб-перехода
        cubeDurationMs: 1200,
        wikiImageUrl: 'https://upload.wikimedia.org/wikipedia/commons/d/d4/2019_Screenshot_of_English_Wikipedia_homepage.png',
        clockAudioUrl: 'https://zvukogram.com/mp3/34/the-ticking-of-a-quartz-clock.mp3',
        lampAudioUrl: 'https://zvukitop.com/wp-content/uploads/2021/04/luminesc-lampa-r4fh.mp3'
    },
    started: false,
     overlay: null,
     overlay: null,
    cube: null,
    frontImage: null,
    rightFrame: null,
     clockAudio: null,
     clockAudio: null,
     lampAudio: null,
     lampAudio: null,
     started: false,
     needsGestureUnlock: false,


     init: function () {
     init: function () {
Строка 2238: Строка 2247:
         this.started = true;
         this.started = true;


         if (!window.mw || !mw.config || !mw.config.get('wgIsMainPage')) {
         if (this.config.onlyMainPage) {
            return;
            if (!window.mw || !mw.config || !mw.config.get('wgIsMainPage')) {
                return;
            }
         }
         }


         var url = new URL(window.location.href);
         var url = new URL(window.location.href);
         var isPreview = url.searchParams.get('prank_preview') === '1';
         var prankFlag = url.searchParams.get('prank') === '1';
        if (isPreview) {
            return;
        }


        var isPrankFlag = url.searchParams.get('prank') === '1';
         var now = new Date();
         var now = new Date();
         var isAprilFirst = now.getMonth() === 3 && now.getDate() === 1;
         var isAprilFirst = now.getMonth() === 3 && now.getDate() === 1;


         var shouldRun = isPrankFlag || this.FORCE_FOR_ALL || (this.ENABLE_APRIL_FIRST && isAprilFirst);
         var shouldRun =
         if (!shouldRun) {
            prankFlag ||
             return;
            this.config.enableForAll ||
            (this.config.enableOnAprilFirst && isAprilFirst);
 
         if (!shouldRun) return;
 
        // Важно: для ?prank=1 НЕ ограничиваем одним показом
        if (!prankFlag && this.config.runOncePerSession) {
             if (sessionStorage.getItem('april-fools-cube-shown') === '1') {
                return;
            }
            sessionStorage.setItem('april-fools-cube-shown', '1');
         }
         }


         this.injectStyles();
         this.injectStyles();
         this.createDom();
         this.createOverlay();
         this.createAudio();
         this.prepareAudio();
         this.show();
         this.startSequence();
 
        var self = this;
        this.tryPlayClockNow();
        this.bindAudioUnlock();
 
        setTimeout(function () {
            self.startCubeTransition();
        }, this.DURATION_BEFORE_TRANSITION);
     },
     },


     injectStyles: function () {
     injectStyles: function () {
         if (document.getElementById('april-cube-prank-styles')) return;
         if (document.getElementById('april-fools-cube-v2-styles')) return;


         var style = document.createElement('style');
         var style = document.createElement('style');
         style.id = 'april-cube-prank-styles';
         style.id = 'april-fools-cube-v2-styles';
         style.textContent =
         style.textContent =
             '#april-cube-prank-overlay{' +
             '#april-fools-cube-overlay {' +
                 'position:fixed;' +
                 'position: fixed;' +
                 'inset:0;' +
                 'inset: 0;' +
                 'z-index:2147483647;' +
                 'z-index: 2147483647;' +
                 'background:#000;' +
                 'pointer-events: auto;' +
                 'opacity:0;' +
                 'background: #000;' +
                'visibility:hidden;' +
                 'overflow: hidden;' +
                 'overflow:hidden;' +
                'transition:opacity .2s linear;' +
             '}' +
             '}' +
             '#april-cube-prank-overlay.active{' +
             '#april-fools-cube-overlay .af-scene {' +
                 'opacity:1;' +
                 'position: absolute;' +
                 'visibility:visible;' +
                'inset: 0;' +
                'perspective: 1800px;' +
                'perspective-origin: 50% 50%;' +
                 'overflow: hidden;' +
             '}' +
             '}' +
             '#april-cube-prank-scene{' +
             '#april-fools-cube-overlay .af-cube {' +
                 'position:absolute;' +
                 'position: absolute;' +
                 'inset:0;' +
                 'inset: 0;' +
                 'perspective:1800px;' +
                 'transform-style: preserve-3d;' +
                 'perspective-origin:50% 50%;' +
                 'transform-origin: right center;' +
                 '--cube-depth:50vw;' +
                 'will-change: transform, opacity;' +
             '}' +
             '}' +
             '#april-cube-prank-cube{' +
             '#april-fools-cube-overlay.af-exit .af-cube {' +
                 'position:absolute;' +
                 'animation: af-cube-rotate 1200ms cubic-bezier(0.2, 0.8, 0.2, 1) forwards;' +
                'inset:0;' +
                'transform-style:preserve-3d;' +
                'transform:translateZ(calc(-1 * var(--cube-depth))) rotateY(0deg);' +
                'will-change:transform,opacity;' +
             '}' +
             '}' +
             '#april-cube-prank-cube.exiting{' +
             '#april-fools-cube-overlay .af-face {' +
                 'animation:aprilCubeRotateOut 1100ms cubic-bezier(.2,.8,.2,1) forwards;' +
                 'position: absolute;' +
                'inset: 0;' +
                'backface-visibility: hidden;' +
                '-webkit-backface-visibility: hidden;' +
                'overflow: hidden;' +
             '}' +
             '}' +
             '@keyframes aprilCubeRotateOut{' +
             '#april-fools-cube-overlay .af-front {' +
                '0%{' +
                 'transform: translateZ(1px);' +
                    'transform:translateZ(calc(-1 * var(--cube-depth))) rotateY(0deg);' +
                'background: #000;' +
                    'opacity:1;' +
                '}' +
                 '100%{' +
                    'transform:translateZ(calc(-1 * var(--cube-depth))) rotateY(-90deg);' +
                    'opacity:1;' +
                '}' +
             '}' +
             '}' +
             '.april-cube-face{' +
             '#april-fools-cube-overlay .af-front img {' +
                 'position:absolute;' +
                 'display: block;' +
                 'inset:0;' +
                'width: 100%;' +
                 'backface-visibility:hidden;' +
                'height: 100%;' +
                 'overflow:hidden;' +
                'object-fit: cover;' +
                 'background:#000;' +
                 'object-position: center top;' +
                 'user-select: none;' +
                 '-webkit-user-drag: none;' +
                 'pointer-events: none;' +
             '}' +
             '}' +
             '.april-cube-face.front{' +
             '#april-fools-cube-overlay .af-right {' +
                 'transform:translateZ(var(--cube-depth));' +
                 'transform-origin: left center;' +
                'transform: rotateY(90deg) translateX(0);' +
                // прозрачная грань: видна реальная страница как "другая сторона куба"
                'background: transparent;' +
                'box-shadow: inset 0 0 120px rgba(0, 0, 0, 0.35);' +
             '}' +
             '}' +
             '.april-cube-face.right{' +
             '#april-fools-cube-overlay .af-edge {' +
                 'transform:rotateY(90deg) translateZ(var(--cube-depth));' +
                'position: absolute;' +
                'top: 0;' +
                'right: 0;' +
                'width: 36px;' +
                'height: 100%;' +
                 'background: linear-gradient(to left, rgba(0,0,0,0.45), rgba(0,0,0,0));' +
                'pointer-events: none;' +
             '}' +
             '}' +
             '.april-cube-face.front img{' +
             '@keyframes af-cube-rotate {' +
                 'width:100%;' +
                 '0% {' +
                'height:100%;' +
                    'transform: translateZ(0) rotateY(0deg);' +
                'object-fit:cover;' +
                    'opacity: 1;' +
                'object-position:center center;' +
                 '}' +
                'display:block;' +
                 '100% {' +
                 'user-select:none;' +
                    'transform: translateZ(0) rotateY(-90deg);' +
                '-webkit-user-drag:none;' +
                    'opacity: 0.02;' +
                'pointer-events:none;' +
                 '}' +
            '}' +
            '.april-cube-face.right iframe{' +
                 'width:100%;' +
                'height:100%;' +
                'border:0;' +
                 'display:block;' +
                'background:#111;' +
             '}';
             '}';
         document.head.appendChild(style);
         document.head.appendChild(style);
     },
     },


     createDom: function () {
     createOverlay: function () {
         var overlay = document.createElement('div');
         var overlay = document.createElement('div');
         overlay.id = 'april-cube-prank-overlay';
         overlay.id = 'april-fools-cube-overlay';


         var scene = document.createElement('div');
         var scene = document.createElement('div');
         scene.id = 'april-cube-prank-scene';
         scene.className = 'af-scene';


         var cube = document.createElement('div');
         var cube = document.createElement('div');
         cube.id = 'april-cube-prank-cube';
         cube.className = 'af-cube';


         var front = document.createElement('div');
         var front = document.createElement('div');
         front.className = 'april-cube-face front';
         front.className = 'af-face af-front';


         var img = document.createElement('img');
         var img = document.createElement('img');
         img.src = 'https://upload.wikimedia.org/wikipedia/commons/d/d4/2019_Screenshot_of_English_Wikipedia_homepage.png';
         img.src = this.config.wikiImageUrl;
         img.alt = 'Wikipedia home';
         img.alt = 'Wikipedia homepage screenshot';
 
        front.appendChild(img);


         var right = document.createElement('div');
         var right = document.createElement('div');
         right.className = 'april-cube-face right';
         right.className = 'af-face af-right';


         var iframe = document.createElement('iframe');
         var edge = document.createElement('div');
         iframe.setAttribute('loading', 'eager');
         edge.className = 'af-edge';
        iframe.setAttribute('referrerpolicy', 'no-referrer-when-downgrade');
        iframe.src = this.buildPreviewUrl();
 
        right.appendChild(iframe);


        front.appendChild(img);
         cube.appendChild(front);
         cube.appendChild(front);
         cube.appendChild(right);
         cube.appendChild(right);
        cube.appendChild(edge);
         scene.appendChild(cube);
         scene.appendChild(cube);
         overlay.appendChild(scene);
         overlay.appendChild(scene);
         document.body.appendChild(overlay);
         document.body.appendChild(overlay);
         this.overlay = overlay;
         this.overlay = overlay;
        this.cube = cube;
        this.frontImage = img;
        this.rightFrame = iframe;
     },
     },


     buildPreviewUrl: function () {
     prepareAudio: function () {
         var url = new URL(window.location.href);
         this.clockAudio = new Audio(this.config.clockAudioUrl);
         url.searchParams.delete('prank');
         this.lampAudio = new Audio(this.config.lampAudioUrl);
         url.searchParams.set('prank_preview', '1');
 
         return url.toString();
         this.clockAudio.preload = 'auto';
    },
         this.lampAudio.preload = 'auto';


    createAudio: function () {
        this.clockAudio = new Audio('https://zvukogram.com/mp3/34/the-ticking-of-a-quartz-clock.mp3');
         this.clockAudio.loop = true;
         this.clockAudio.loop = true;
        this.clockAudio.preload = 'auto';
         this.clockAudio.volume = 0.45;
         this.clockAudio.volume = 0.45;
        this.lampAudio = new Audio('https://zvukitop.com/wp-content/uploads/2021/04/luminesc-lampa-r4fh.mp3');
         this.lampAudio.loop = false;
         this.lampAudio.loop = false;
        this.lampAudio.preload = 'auto';
         this.lampAudio.volume = 0.6;
         this.lampAudio.volume = 0.9;
     },
     },


     show: function () {
     startSequence: function () {
         if (!this.overlay) return;
         var self = this;
         this.overlay.classList.add('active');
 
        // Пробуем запустить сразу оба звука одновременно
        this.playBothSoundsNow();
 
        setTimeout(function () {
            self.startCubeTransition();
         }, this.config.overlayDurationMs);
     },
     },


     tryPlayClockNow: function () {
     playBothSoundsNow: function () {
         if (!this.clockAudio) return;
         var self = this;
         this.clockAudio.currentTime = 0;
        var playClock = this.clockAudio ? this.clockAudio.play() : Promise.resolve();
         var playLamp = this.lampAudio ? this.lampAudio.play() : Promise.resolve();


         var playPromise = this.clockAudio.play();
         Promise.allSettled([playClock, playLamp]).then(function (results) {
        if (playPromise && typeof playPromise.catch === 'function') {
            var hasRejected = results.some(function (r) { return r.status === 'rejected'; });
             playPromise.catch(function () {});
             if (hasRejected) {
         }
                self.enableGestureUnlock();
            }
         });
     },
     },


     bindAudioUnlock: function () {
     enableGestureUnlock: function () {
        if (this.needsGestureUnlock) return;
        this.needsGestureUnlock = true;
 
         var self = this;
         var self = this;
        function unlockAndPlay() {
            self.needsGestureUnlock = false;


        function unlockAndPlay() {
             if (self.clockAudio) {
             if (self.clockAudio) {
                self.clockAudio.currentTime = 0;
                 self.clockAudio.play().catch(function () {});
                 self.clockAudio.play().catch(function () {});
             }
             }
            if (self.lampAudio) {
                self.lampAudio.currentTime = 0;
                self.lampAudio.play().catch(function () {});
            }
             document.removeEventListener('pointerdown', unlockAndPlay);
             document.removeEventListener('pointerdown', unlockAndPlay);
             document.removeEventListener('keydown', unlockAndPlay);
             document.removeEventListener('keydown', unlockAndPlay);
Строка 2444: Строка 2460:


     startCubeTransition: function () {
     startCubeTransition: function () {
         if (!this.cube || !this.overlay) return;
         if (!this.overlay) return;
 
        // В момент вращения ещё раз запускаем "лампу", часы продолжают тикать
        if (this.lampAudio) {
            try {
                this.lampAudio.currentTime = 0;
                this.lampAudio.play().catch(function () {});
            } catch (e) {}
        }


        this.overlay.classList.add('af-exit');
        var self = this;
        setTimeout(function () {
            self.finish();
        }, this.config.cubeDurationMs + 80);
    },
    finish: function () {
         if (this.clockAudio) {
         if (this.clockAudio) {
             this.clockAudio.pause();
             this.clockAudio.pause();
Строка 2451: Строка 2484:
         }
         }


         if (this.lampAudio) {
         if (this.overlay && this.overlay.parentNode) {
             this.lampAudio.currentTime = 0;
             this.overlay.parentNode.removeChild(this.overlay);
            this.lampAudio.play().catch(function () {});
         }
         }
 
         this.overlay = null;
        var self = this;
        this.cube.classList.add('exiting');
 
         this.cube.addEventListener('animationend', function handleEnd() {
            self.cube.removeEventListener('animationend', handleEnd);
 
            if (self.overlay && self.overlay.parentNode) {
                self.overlay.parentNode.removeChild(self.overlay);
            }
 
            if (self.lampAudio) {
                self.lampAudio.pause();
                self.lampAudio.currentTime = 0;
            }
 
            self.overlay = null;
            self.cube = null;
            self.frontImage = null;
            self.rightFrame = null;
        });
     }
     }
};
};