User:Monster Domosed/common.js: Difference between revisions

No edit summary
No edit summary
Line 1: Line 1:
document.querySelectorAll('.HeroCard2').forEach(function(el) {
( function () {
  el.style.transition = 'none';
    'use strict';
  el.style.transformStyle = 'preserve-3d';
  el.style.willChange = 'transform';


  var animFrame;
    /* ---- bootstrap one viewer element ---- */
  var current = { x: 0, y: 0 };
    function boot( el ) {
  var target = { x: 0, y: 0 };
  var mouseX = 0, mouseY = 0;
  var isOver = false;


  document.addEventListener('mousemove', function(e) {
        if ( el.dataset.rmReady ) return;  // already initialised
    mouseX = e.clientX;
        el.dataset.rmReady = '1';
    mouseY = e.clientY;
  });


  var tick = function() {
        /* --- config --- */
    var rect = el.getBoundingClientRect();
        var imageUrl    = el.dataset.image,
    isOver = (
            fw          = +el.dataset.frameWidth  || 300,
      mouseX >= rect.left &&
            fh          = +el.dataset.frameHeight || 400,
       mouseX <= rect.right &&
            count       = +el.dataset.frameCount  || 24,
      mouseY >= rect.top &&
            startFrame  = +el.dataset.startFrame  || 0,
      mouseY <= rect.bottom
            sensitivity = +el.dataset.sensitivity || 5;
    );


    if (isOver) {
        if ( !imageUrl ) return;
      var cx = rect.left + rect.width / 2;
 
       var cy = rect.top + rect.height / 2;
        var cur  = startFrame,
      var dx = (mouseX - cx) / (rect.width / 2);
            hint = el.querySelector( '.rotatable-model-hint' ),
      var dy = (mouseY - cy) / (rect.height / 2);
            load = el.querySelector( '.rotatable-model-loading' );
      target.x = dy * -12;
 
      target.y = dx * 12;
        /* --- build the <img> strip --- */
     } else {
        var img  = document.createElement( 'img' );
      target.x = 0;
        img.className = 'rm-strip';
      target.y = 0;
        img.alt       = '';
        img.draggable = false;
        img.style.height = fh + 'px';
        img.style.width  = ( fw * count ) + 'px';
 
        img.onload = function () {
            if ( load ) load.style.display = 'none';
        };
        img.onerror = function () {
            if ( load ) load.textContent = 'Image failed to load';
        };
 
        img.src = imageUrl;
        el.insertBefore( img, el.firstChild );
 
        /* --- helpers --- */
        function show( idx ) {
            cur = ( ( idx % count ) + count ) % count;
            img.style.left = -( cur * fw ) + 'px';
        }
 
        function nudge( d ) { show( cur + d ); hideHint(); }
 
        function reset() { show( startFrame ); }
 
        function hideHint() {
            if ( hint ) hint.classList.add( 'rm-hidden' );
        }
 
        /* --- drag (mouse + touch) --- */
        function startDrag( x0 ) {
            var acc = 0;
            hideHint();
 
            function move( cx ) {
                acc += cx - x0;
                x0  = cx;
                var fd = ( acc / sensitivity ) | 0;      // truncate → 0
                if ( fd ) {
                    acc -= fd * sensitivity;
                    show( cur + fd );
                }
            }
 
            function onMM( e ) { move( e.clientX ); e.preventDefault(); }
            function onTM( e ) {
                if ( e.touches.length === 1 ) {
                    move( e.touches[0].clientX );
                    e.preventDefault();
                }
            }
            function stop() {
                el.classList.remove( 'rm-dragging' );
                document.removeEventListener( 'mousemove', onMM );
                document.removeEventListener( 'mouseup',  stop );
                document.removeEventListener( 'touchmove', onTM );
                document.removeEventListener( 'touchend',  stop );
                document.removeEventListener( 'touchcancel', stop );
            }
 
            el.classList.add( 'rm-dragging' );
            document.addEventListener( 'mousemove', onMM );
            document.addEventListener( 'mouseup',  stop );
            document.addEventListener( 'touchmove', onTM, { passive: false } );
            document.addEventListener( 'touchend',  stop );
            document.addEventListener( 'touchcancel', stop );
        }
 
        el.addEventListener( 'mousedown', function ( e ) {
            if ( e.button === 0 ) { startDrag( e.clientX ); e.preventDefault(); }
        });
        el.addEventListener( 'touchstart', function ( e ) {
            if ( e.touches.length === 1 ) { startDrag( e.touches[0].clientX ); e.preventDefault(); }
        }, { passive: false } );
 
        /* --- mouse-wheel --- */
        el.addEventListener( 'wheel', function ( e ) {
            var d = e.deltaY > 0 ? 1 : e.deltaY < 0 ? -1 : 0;
            if ( d ) { nudge( d ); e.preventDefault(); }
        }, { passive: false } );
 
        /* --- keyboard (element must be focusable) --- */
        el.setAttribute( 'tabindex', '0' );
        el.addEventListener( 'keydown', function ( e ) {
            switch ( e.key ) {
                case 'ArrowLeft':  nudge( -1 ); e.preventDefault(); break;
                case 'ArrowRight': nudge(  1 ); e.preventDefault(); break;
                case 'Home':      reset();     e.preventDefault(); break;
            }
        });
 
        /* --- nav buttons (outside .rotatable-model, inside wrapper) --- */
        var wrap = el.closest( '.rotatable-model-wrapper' );
        if ( wrap ) {
            var bL = wrap.querySelector( '.rm-btn-left' ),
                bR = wrap.querySelector( '.rm-btn-right' ),
                bO = wrap.querySelector( '.rm-btn-reset' );
 
            if ( bL ) bL.addEventListener( 'click', function () { nudge( -1 ); } );
            if ( bR ) bR.addEventListener( 'click', function () { nudge(  1 ); } );
            if ( bO ) bO.addEventListener( 'click', reset );
        }
 
        /* --- initial frame --- */
        show( startFrame );
     }
     }


     current.x += (target.x - current.x) * 0.12;
     /* ---- scan & initialise ---- */
    current.y += (target.y - current.y) * 0.12;
    function initAll( root ) {
        var els = ( root || document ).querySelectorAll(
                '.rotatable-model:not([data-rm-ready])' );
        for ( var i = 0; i < els.length; i++ ) boot( els[i] );
    }


     el.style.transform = 'perspective(400px) rotateX(' + current.x + 'deg) rotateY(' + current.y + 'deg) scale(' + (isOver ? 1.05 : 1) + ')';
     if ( document.readyState === 'loading' ) {
        document.addEventListener( 'DOMContentLoaded', function () { initAll(); } );
    } else {
        initAll();
    }


     requestAnimationFrame(tick);
     // re-scan when MediaWiki injects content (VE save, live-preview, etc.)
  };
    if ( typeof mw !== 'undefined' && mw.hook ) {
 
        mw.hook( 'wikipage.content' ).add( function ( $c ) { initAll( $c[0] ); } );
  tick();
    }
});
}() );