Zum Inhalt springen

MediaWiki:Gadget-aew-liststyles.js

aus AufEinWort, der freien Forschung

Hinweis: Leere nach dem Veröffentlichen den Browser-Cache, um die Änderungen sehen zu können.

  • Firefox/Safari: Umschalttaste drücken und gleichzeitig Aktualisieren anklicken oder entweder Strg+F5 oder Strg+R (⌘+R auf dem Mac) drücken
  • Google Chrome: Umschalttaste+Strg+R (⌘+Umschalttaste+R auf dem Mac) drücken
  • Edge: Strg+F5 drücken oder Strg drücken und gleichzeitig Aktualisieren anklicken
/*
 * Gadget: aew-liststyles.js — Entwurf v0.7
 * Ziel: VE-Tool „Liststyle –“ für UL (Aufzählung) – Anzeige per CSS-Klasse aew-ul--dash
 * Phase 1: Anzeige live im VE und im View (CSS).
 * Phase 2: Persistenz – Klasse via VE-Datenmodell setzen (Transaction), damit sie im View erhalten bleibt.
 */
(function ( mw, $ ) {
  'use strict';

  function debug(msg){ try{ mw.log('[aew-liststyles] ' + msg); }catch(e){} }

  // ----------------------------------------------
  // Helper: nächste UL/OL relativ zur Cursor-Position (DOM)
  // ----------------------------------------------
  function findNearestListInSurface( surface ) {
    try {
      var sel = window.getSelection && window.getSelection();
      if ( !sel || !sel.anchorNode ) return null;
      var node = sel.anchorNode.nodeType === 3 ? sel.anchorNode.parentNode : sel.anchorNode;
      if ( node && node.closest ) {
        var list = node.closest('ul,ol');
        return list || null;
      }
    } catch (e) {}
    return null;
  }

  // ----------------------------------------------
  // Persistenz: Klasse im VE-Datenmodell setzen (List-Node)
  // ----------------------------------------------
  function applyDashClassPersistent( surface ) {
    try {
      var model = surface.getModel && surface.getModel();
      if ( !model ) return false;
      var dmDoc = model.getDocument && model.getDocument();
      var sel = model.getSelection && model.getSelection();
      if ( !dmDoc || !sel || !sel.getRange ) return false;

      // Nächsten Listenknoten (DM) finden
      var start = sel.getRange().start;
      var node = dmDoc.getBranchNodeFromOffset( start );
      var listNode = null;
      while ( node && node.getType ) {
        if ( node.getType() === 'list' ) { listNode = node; break; }
        node = node.getParent && node.getParent();
      }
      if ( !listNode ) return false;

      // Klassen via originalClasses pflegen (VE konserviert unbekannte Klassen darüber)
      var attrs = ve.copy( listNode.getAttributes && listNode.getAttributes() ) || {};
      var orig = ( attrs.originalClasses || '' ).trim();
      var set  = orig ? orig.split(/\s+/) : [];
      var idx  = set.indexOf('aew-ul--dash');
      if ( idx === -1 ) { set.push('aew-ul--dash'); } else { set.splice(idx, 1); }
      attrs.originalClasses = set.length ? set.join(' ') : null;

      var tx = ve.dm.TransactionBuilder.static.newFromAttributeChanges(
        dmDoc,
        listNode.getOuterRange().start,
        attrs
      );
      surface.change( tx );
      return true;
    } catch (e) {
      debug('persist fail: ' + e);
      return false;
    }
  }

  // ----------------------------------------------
  // Tool-Definition: „Liststyle –“
  // ----------------------------------------------
  function registerTool() {
    if ( !window.ve || !window.OO ) { return; }
    if ( ve.ui.toolFactory.lookup('aewListStyleDash') ) { return; }

    function AewListStyleDashTool() { AewListStyleDashTool.super.apply(this, arguments); }
    OO.inheritClass( AewListStyleDashTool, ve.ui.Tool );
    AewListStyleDashTool.static.name = 'aewListStyleDash';
    AewListStyleDashTool.static.group = 'structure';
    AewListStyleDashTool.static.icon = 'listBullet';
    AewListStyleDashTool.static.title = 'Liststyle –';
    AewListStyleDashTool.static.autoAddToCatchall = true;

    AewListStyleDashTool.prototype.onSelect = function () {
      var surface = ve.init.target && ve.init.target.getSurface && ve.init.target.getSurface();
      if ( !surface ) { this.setActive(false); return; }

      // 1) Persistente Änderung im VE-Modell versuchen
      var ok = applyDashClassPersistent( surface );

      // 2) DOM-Fallback (nur falls nötig, für sofortige Sichtbarkeit)
      if ( !ok ) {
        var listNode = findNearestListInSurface( surface );
        if ( !listNode ) { mw.notify('Bitte Cursor in eine Liste setzen.', { type:'warn' }); this.setActive(false); return; }
        if ( listNode.nodeName.toLowerCase() !== 'ul' ) { mw.notify('„–“ gilt für Aufzählungslisten (UL).', { type:'warn' }); this.setActive(false); return; }
        listNode.classList.toggle('aew-ul--dash');
      }

      mw.notify('Liststyle „–“ ' + ( ok ? 'persistiert.' : 'gesetzt (nur sichtbar).' ), { type: ok ? 'info' : 'warn' } );
      this.setActive(false);
    };

    AewListStyleDashTool.prototype.onUpdateState = function () {
      var surface = ve.init.target && ve.init.target.getSurface && ve.init.target.getSurface();
      var enabled = false;
      if ( surface ) {
        // Primär: VE-DM (list/listItem, style === 'bullet')
        try {
          var model = surface.getModel();
          var sel = model && model.getSelection && model.getSelection();
          if ( sel && sel.getRange ) {
            var dmDoc = model.getDocument();
            var start = sel.getRange().start;
            var n = dmDoc.getBranchNodeFromOffset( start );
            while ( n && n.getType ) {
              var t = n.getType && n.getType();
              if ( t === 'list' ) {
                var st = n.getAttribute ? n.getAttribute('style') : ( n.getAttributes && n.getAttributes().style );
                enabled = ( st === 'bullet' ); break;
              }
              if ( t === 'listItem' ) {
                var p = n.getParent && n.getParent();
                if ( p && p.getType && p.getType() === 'list' ) {
                  var st2 = p.getAttribute ? p.getAttribute('style') : ( p.getAttributes && p.getAttributes().style );
                  enabled = ( st2 === 'bullet' ); break;
                }
              }
              n = n.getParent ? n.getParent() : null;
            }
          }
        } catch (e) {}
        // Sekundär: DOM-Fallback
        if ( !enabled ) {
          try {
            var selDom = window.getSelection && window.getSelection();
            if ( selDom && selDom.anchorNode ) {
              var dn = selDom.anchorNode.nodeType === 3 ? selDom.anchorNode.parentNode : selDom.anchorNode;
              enabled = !!( dn && dn.closest && dn.closest('ul') );
            }
          } catch (e2) {}
        }
      }
      this.setDisabled( !enabled );
      this.setActive( false );
    };

    ve.ui.toolFactory.register( AewListStyleDashTool );
    debug('Tool registriert');
  }

  // ----------------------------------------------
  // Toolbar-Gruppe ggf. nachträglich hinzufügen (wenn Gadget spät lädt)
  // ----------------------------------------------
  function addToolbarGroupIfNeeded() {
    if ( !window.ve || !ve.init || !ve.init.target ) { return; }
    var toolbar = ve.init.target.getToolbar && ve.init.target.getToolbar();
    if ( !toolbar ) { return; }
    try {
      var group = new OO.ui.ListToolGroup( toolbar, { title: 'Listenstil', include: [ 'aewListStyleDash' ] } );
      toolbar.addItems( [ group ] );
      toolbar.emit( 'updateState' );
      debug('ToolGroup hinzugefügt');
    } catch (e) {}
  }

  // Feature-Flag: ::marker-Unterstützung
  function setMarkerSupportClass(){
    try{
      if ( window.CSS && CSS.supports && CSS.supports('selector(::marker)') ) {
        document.documentElement.classList.add('aew-supports-marker');
      } else {
        document.documentElement.classList.remove('aew-supports-marker');
      }
    }catch(e){}
  }

  // 1) VE-Plugin-Mechanismus: vor Toolbar-Aufbau registrieren, wenn möglich
  mw.hook('ve.loadModules').add( function ( addPlugin ) {
    addPlugin( function () { registerTool(); } );
  } );

  // 2) Lesemodus + VE-Start
  mw.hook('wikipage.content').add( setMarkerSupportClass );
  mw.hook('ve.activationComplete').add( function () {
    setMarkerSupportClass();
    registerTool();
    addToolbarGroupIfNeeded();
  } );

})( window.mediaWiki, window.jQuery );