MediaWiki:Gadget-freezeAPNG.js: различия между версиями

Материал из Space Station 14 Вики
мНет описания правки
Метка: отменено
Нет описания правки
 
(не показаны 3 промежуточные версии этого же участника)
Строка 1: Строка 1:
( function ( $, mw ) {
(function($, mw){
    function parseChunks( buf ) {
  function detectAndPrepare(img){
        const dv = new DataView( buf );
    if (img.dataset.freezeProcessed) return;
        let pos = 8;
    var xhr = new XMLHttpRequest();
        const chunks = [];
    xhr.open('GET', img.src, true);
        while ( pos < buf.byteLength ) {
    xhr.responseType = 'arraybuffer';
            const length = dv.getUint32( pos );
    xhr.onload = function(){
            const typeBytes = new Uint8Array( buf, pos + 4, 4 );
      if (xhr.status < 200 || xhr.status >= 300) return;
            const type = String.fromCharCode.apply( null, typeBytes );
      var bytes = new Uint8Array(xhr.response);
            const dataStart = pos + 8;
      for (var i = 0; i < bytes.length - 4; i++){
            const dataEnd = dataStart + length;
        if (
            const crcEnd = dataEnd + 4;
          bytes[i]  === 0x61 &&
            chunks.push({
          bytes[i+1] === 0x63 &&
                type,
          bytes[i+2] === 0x54 &&
                start: pos,
          bytes[i+3] === 0x4C
                end: crcEnd
        ){
            });
          prepareSwap(img);
            pos = crcEnd;
          break;
         }
         }
         return chunks;
      }
    };
    xhr.onerror = function(){ /* ignore */ };
    xhr.send();
  }
 
  function prepareSwap(img){
    if (img.dataset.freezeProcessed) return;
    img.dataset.freezeProcessed = '1';
 
    var origW = img.getAttribute('width'),
        origH = img.getAttribute('height');
 
    var animated = img.cloneNode(true);
    animated.classList.add('freezeAPNG__animation');
    if (origW) animated.setAttribute('width', origW);
    if (origH) animated.setAttribute('height', origH);
 
    var ow = img.naturalWidth || img.width || 0,
         oh = img.naturalHeight || img.height || 0;
 
    if (!ow || !oh) {
      return;
     }
     }


     async function detectAndStrip( img ) {
     var canvas = document.createElement('canvas');
        try {
    canvas.width = ow;
            const resp = await fetch( img.src );
    canvas.height = oh;
            if ( !resp.ok ) return;
    var ctx = canvas.getContext('2d');
            const buf = await resp.arrayBuffer();
    try {
            const chunks = parseChunks( buf );
      ctx.drawImage(img, 0, 0, ow, oh);
    } catch (e) {
      return;
    }


            if ( !chunks.some( c => c.type === 'acTL' ) ) return;
    var frozenData;
    try {
      frozenData = canvas.toDataURL('image/png');
    } catch (e) {
      return;
    }


            const keep = [];
    var container = img.closest('.freezeAPNG') || img.parentNode;
            keep.push( buf.slice( 0, 8 ) );
    if (!container) return;
            for ( const c of chunks ) {
    container.classList.add('freezeAPNG');
                if ( c.type === 'acTL' || c.type === 'fcTL' ) continue;
                keep.push( buf.slice( c.start, c.end ) );
            }


            const blob = new Blob( keep, { type: 'image/png' } );
    img.classList.add('freezeAPNG__freeze');
            const url  = URL.createObjectURL( blob );
    try {
      img.src = frozenData;
    } catch (e){ /* ignore */ }
    if (origW) img.setAttribute('width', origW);
    if (origH) img.setAttribute('height', origH);


            img.src = url;
    container.appendChild(animated);
        } catch ( e ) {
    container.addEventListener('focusin', function(){ container.classList.add('freezeAPNG--active'); });
            console.error( 'freezeAPNG error:', e );
    container.addEventListener('focusout', function(){ container.classList.remove('freezeAPNG--active'); });
        }
 
     }
    var touchTimer = null;
    container.addEventListener('touchstart', function(e){
      container.classList.add('freezeAPNG--active');
      if (touchTimer) clearTimeout(touchTimer);
      touchTimer = setTimeout(function(){
        container.classList.remove('freezeAPNG--active');
        touchTimer = null;
      }, 1400);
    }, {passive: true});
     container.addEventListener('touchend', function(){ if (touchTimer) { clearTimeout(touchTimer); touchTimer = null; container.classList.remove('freezeAPNG--active'); } }, {passive: true});
  }


    $( () => {
  $(function(){
        $( '.freezeAPNG img[src$=".png"]' ).each( ( _, img ) => {
    $('.freezeAPNG img[src$=".png"]').each(function(){
            if ( img.complete ) {
      var img = this;
                detectAndStrip( img );
      if (img.dataset.freezeProcessed) return;
            } else {
      if (img.complete) {
                img.addEventListener( 'load', () => detectAndStrip( img ), { once: true } );
        detectAndPrepare(img);
            }
      } else {
        } );
        img.addEventListener('load', function(){ detectAndPrepare(this); });
    } );
      }
} )( jQuery, mediaWiki );
    });
  });
})(jQuery, mediaWiki);

Текущая версия от 20:46, 17 марта 2026

(function($, mw){
  function detectAndPrepare(img){
    if (img.dataset.freezeProcessed) return;
    var xhr = new XMLHttpRequest();
    xhr.open('GET', img.src, true);
    xhr.responseType = 'arraybuffer';
    xhr.onload = function(){
      if (xhr.status < 200 || xhr.status >= 300) return;
      var bytes = new Uint8Array(xhr.response);
      for (var i = 0; i < bytes.length - 4; i++){
        if (
          bytes[i]   === 0x61 &&
          bytes[i+1] === 0x63 &&
          bytes[i+2] === 0x54 &&
          bytes[i+3] === 0x4C
        ){
          prepareSwap(img);
          break;
        }
      }
    };
    xhr.onerror = function(){ /* ignore */ };
    xhr.send();
  }

  function prepareSwap(img){
    if (img.dataset.freezeProcessed) return;
    img.dataset.freezeProcessed = '1';

    var origW = img.getAttribute('width'),
        origH = img.getAttribute('height');

    var animated = img.cloneNode(true);
    animated.classList.add('freezeAPNG__animation');
    if (origW) animated.setAttribute('width', origW);
    if (origH) animated.setAttribute('height', origH);

    var ow = img.naturalWidth || img.width || 0,
        oh = img.naturalHeight || img.height || 0;

    if (!ow || !oh) {
      return;
    }

    var canvas = document.createElement('canvas');
    canvas.width = ow;
    canvas.height = oh;
    var ctx = canvas.getContext('2d');
    try {
      ctx.drawImage(img, 0, 0, ow, oh);
    } catch (e) {
      return;
    }

    var frozenData;
    try {
      frozenData = canvas.toDataURL('image/png');
    } catch (e) {
      return;
    }

    var container = img.closest('.freezeAPNG') || img.parentNode;
    if (!container) return;
    container.classList.add('freezeAPNG');

    img.classList.add('freezeAPNG__freeze');
    try {
      img.src = frozenData;
    } catch (e){ /* ignore */ }
    if (origW) img.setAttribute('width', origW);
    if (origH) img.setAttribute('height', origH);

    container.appendChild(animated);
    container.addEventListener('focusin', function(){ container.classList.add('freezeAPNG--active'); });
    container.addEventListener('focusout', function(){ container.classList.remove('freezeAPNG--active'); });

    var touchTimer = null;
    container.addEventListener('touchstart', function(e){
      container.classList.add('freezeAPNG--active');
      if (touchTimer) clearTimeout(touchTimer);
      touchTimer = setTimeout(function(){
        container.classList.remove('freezeAPNG--active');
        touchTimer = null;
      }, 1400);
    }, {passive: true});
    container.addEventListener('touchend', function(){ if (touchTimer) { clearTimeout(touchTimer); touchTimer = null; container.classList.remove('freezeAPNG--active'); } }, {passive: true});
  }

  $(function(){
    $('.freezeAPNG img[src$=".png"]').each(function(){
      var img = this;
      if (img.dataset.freezeProcessed) return;
      if (img.complete) {
        detectAndPrepare(img);
      } else {
        img.addEventListener('load', function(){ detectAndPrepare(this); });
      }
    });
  });
})(jQuery, mediaWiki);