User:PerfektesChaos/js/keyboardMapper/d.js

/// User:PerfektesChaos/js/keyboardMapper.js // Establish keyboard mapper for particular pages and forms /// 2018-08-24 PerfektesChaos@de.wikipedia // ResourceLoader: compatible; //   dependencies: user, jquery.textSelection /// Fingerprint: #0#0# /// @license GPL [//www.mediawiki.org/w/COPYING] (+GFDL, LGPL, CC-BY-SA) /// /* global window: false                                               */ /* jshint forin: false, bitwise:true, curly:true, eqeqeq:true, latedef:true, laxbreak:true, nocomma:true, strict:true, undef:true, unused:true          */

( function ( mw, $ ) {  "use strict";   var Version   = -1.7,       Signature = "keyboardMapper",       CNF       = { bib:       mw.libs,                     divert:    [ "meta", "alt", "ctrl", "shift" ],                     doc:       "w:en:PerfektesChaos/js/" + Signature,                     env:       null,                     list:      false,                     listen:    false,                     live:      false,                     pad:       { "+": "Add",                                  ",": "Comma",     // thousands sep                                  ".": "Decimal",   // decimal sep                                  "/": "Divide",                                  "=": "Equal",                                  "#": "Hash",                                  "*": "Multiply",                                  "-": "Subtract" },                     plains:    null,                     scope:     " edit ve ", signature: false, transform: null, user:     null, ve:       false };

function factory { // Create transformation map from user defined map // Uses: //   >  CNF.user //   >  CNF.divert //   >  CNF.pad //   >< CNF.plains //    < CNF.transform // 2017-07-12 PerfektesChaos@de.wikipedia var suitable = " number string function boolean ", i, k, o, s, second, seek, t, v;     CNF.transform = null; if ( typeof CNF.user ===  "object" ) { for ( i = 0; i < CNF.user.length;  i++ ) { v = CNF.user[ i ]; if ( typeof v ===  "object"                 &&     v   &&                 typeof v.seek  ===  "string"                 &&     v.seek ) { s = typeof v.transfer; if ( suitable.indexOf( s ) >  0                    &&   v.transfer ) { if ( s === "number" ) { if ( v.transfer < 32 ) { t = false; } else { t = String.fromCharCode( v.transfer ); }                 } else if ( v.transfer ) { t = v.transfer; }                 if ( t ) { second = "*"; seek  = v.seek; for ( k = 0; k < CNF.divert.length;  k++ ) { s = CNF.divert[ k ]; if ( typeof v[ s ] ===  "boolean"                             &&     v[ s ] ) { second = s;                          break;   // for k                        } }  // for k                     if ( typeof v.num  ===  "boolean" ) { if ( v.num ) { if ( typeof CNF.pad[ seek ] ===  "string" ) { seek = CNF.pad[ seek ]; }                          seek = "Numpad" + seek; } else if ( seek.length === 1 ) { if ( typeof CNF.pad[ seek ] ===  "string" ) { seek = CNF.pad[ seek ]; } else { k = seek.charCodeAt( 0 ); if ( k >= 48 &&  k <= 57 ) { seek = "Digit" + seek; }                          }                        }                     }                     o = { transfer: t }; if ( typeof v.leave ===  "boolean"                          &&     v.leave ) { o.leave = true; } else { o.leave = false; }                    switch ( typeof v.say ) { case "object": if ( v.say  &&                                typeof v.say.en  ===  "string" ) { o.say = v.say; }                          break; case "string": if ( v.say ) { o.say = v.say; }                          break; }  // switch typeof v.say if ( ! CNF.transform ) { CNF.transform = { }; }                    if ( ! CNF.transform[ seek ] ) { CNF.transform[ seek ] = { }; }                    CNF.transform[ seek ][ second ] = o;                  } }           }         }   // for i      } if ( CNF.transform &&  ! CNF.plains ) { CNF.plains = [ ]; CNF.plains.push( 2 * CNF.divert.length ); for ( k = CNF.divert.length; k >= 0;  k-- ) { s = CNF.divert[ k ]; CNF.plains.push( s ); CNF.plains.push( s + "Key" ); }  // for k-- }     CNF.bib.transform = CNF.transform; }  // factory

function fake( apply, assigned ) { // Insert text // Precondition: //   apply     -- string, with text //   assigned  -- object, with options // Uses: //   ve      //    >  CNF.learn //   $.textSelection // 2017-09-01 PerfektesChaos@de.wikipedia var submit = "", elt, i, k, params, veFrag, veSurface, veSModel; for ( i = 0; i < apply.length;  i++ ) { k = apply.charCodeAt( i ); if ( k === 10 ||  k >= 32 ) { submit = submit + String.fromCharCode( k ); }     }   // for i      if ( submit ) { elt = window.document.activeElement; if ( elt  &&              typeof elt.tagName  ===  "string"   &&              ( elt.tagName === "INPUT"  || elt.tagName === "TEXTAREA" ) ) { if ( assigned.leave ) { params = { peri:   "", pre:    submit, replace: false }; } else { params = { peri:   submit, replace: true }; }           if ( typeof assigned.learn  ===  "boolean" ) { params.selectPeri = assigned.learn; }           $( elt ).textSelection( "encapsulateSelection", params ); } else if ( typeof window.ve ===  "object"                     &&     window.ve   &&                     typeof window.ve.init  ===  "object"                     &&     window.ve.init   &&                     typeof window.ve.init.target  ===  "object"                     &&     window.ve.init.target                     &&     window.ve.init.target.active )  { veSurface = window.ve.init.target.getSurface; veSModel = veSurface.getModel; veFrag   = veSModel.getFragment; if ( ! veFrag.isNull ) { veFrag.insertContent( submit ); }        }      }   }   // fake

function features { // Load survey code // Uses: //   >  CNF.divert //   >  CNF.pad //   >  Signature //    < CNF.bib.divert //    < CNF.bib.reverse //   mw.loader.load // 2017-07-18 PerfektesChaos@de.wikipedia var maxage = 0, s;     CNF.bib.divert  = CNF.divert; CNF.bib.reverse = { }; for ( s in CNF.pad ) { CNF.bib.reverse[ CNF.pad[ s ] ] = s;     }   // for s in CNF.pad mw.loader.load( "https://en.wikipedia.org"                     + "/w/index.php?title="                      + "User:PerfektesChaos/js/"                      + Signature + "/config.js"                      + "&bcache=1&maxage=" + maxage                      + "&action=raw"                      + "&ctype=text/javascript" ); }  // features

function feed( event ) { // Handler for keyboard event // Precondition: //   event  -- DOM event // Uses: //   >  CNF.plains //   >  CNF.transform //   fake // 2017-07-12 PerfektesChaos@de.wikipedia var blocker, k, s, second, t;     if ( typeof CNF.transform[ event.code ]  ===  "object" ) { t = CNF.transform[ event.code ]; } else if ( typeof CNF.transform[ event.key ] ===  "object" ) { t = CNF.transform[ event.key ]; }     if ( t ) { second = "*"; for ( k = CNF.plains[ 0 ]; k > 0;  k -= 2 ) { if ( event[ CNF.plains[ k ] ] ) { second = CNF.plains[ k - 1 ]; break;  // for k-- }        }   // for k-- if ( typeof t[ second ] ===  "object" ) { blocker = [ "preventDefault", "stopImmediatePropagation", "stopPropagation" ]; for ( s in blocker ) { if ( typeof event[ s ] ===  "function" ) { event[ s ]; }           }   // for s in blocker t = t[ second ]; if ( typeof t.transfer ===  "function" ) { s = t.transfer( event ); } else { s = t.transfer; }           if ( typeof s  ===  "string"  &&  s ) { fake( s, t ); }        }      }      return; }  // feed

function feeder { // Enable or disable listener // Uses: //   >  CNF.user //   >  CNF.transform //   >< CNF.live //   >< CNF.listen //    < CNF.bib.listen //   factory //   (feed) // 2017-07-12 PerfektesChaos@de.wikipedia var listen = CNF.live; if ( CNF.live ) { if ( CNF.user &&  ! CNF.transform ) { factory; }        if ( CNF.transform ) { if ( ! CNF.listen ) { $( function {                  window.addEventListener( "keydown", feed, true );               } ); }        } else { listen = false; }     } else if ( CNF.listen ) { window.removeEventListener( "keydown", feed, true ); listen = false; }     CNF.listen     = listen; CNF.bib.listen = listen; }  // feeder

function fetch( assign ) { // Retrieve user defined mapping // Precondition: //   assign  -- Array, with mapping objects // Uses: //   >  CNF.list //    < CNF.user //    < CNF.bib.user //    < CNF.transform //    < CNF.bib.transform //   factory //   mw.hook //   feeder // 2017-07-12 PerfektesChaos@de.wikipedia var user; if ( assign  &&           typeof assign  ===  "object"   &&           typeof assign.length  ===  "number"           &&     assign.length ) { user = assign; }     if ( user ) { CNF.user = user; } else { CNF.user = null; }     CNF.bib.user = user; if ( CNF.list ) { factory; mw.hook( Signature + ".updated" ).fire( CNF.transform ); } else { CNF.transform    = null; CNF.bib.transform = null; feeder; }  }   // fetch

function fire( actions ) { // Start regular workflow in edit mode, if appropriate // Precondition: //   actions  -- string, with space separated list of actions // Uses: //   >  CNF.env //   >  CNF.list //   >< CNF.reTrim //    < CNF.scope //    < CNF.live //   mw.hook //   features //   mw.loader.using //   feeder //   (feeder) // 2017-07-19 PerfektesChaos@de.wikipedia var loved, s;     if ( typeof actions  ===  "string" ) { if ( typeof CNF.reTrim !==  "object" ) { CNF.reTrim = new RegExp( "^\\s*(\\S.*\\S|-)?\\s*$" );

}        s = actions.replace( CNF.reTrim, "$1" ); if ( s === "-" ) { CNF.scope = false; } else if ( s === "*" ) { CNF.scope = true; loved    = true; } else if ( s ) { CNF.scope = " " + s + " "; } else { CNF.scope = false; }     }      if ( CNF.scope ) { if ( typeof CNF.scope ===  "string" ) { if ( CNF.scope.indexOf( " edit " ) >=  0 ) { CNF.scope = CNF.scope + " submit "; }           loved    = ( CNF.scope.indexOf( " ve " )  >  0 ); s       = " " + CNF.env.wgAction + " "; CNF.live = ( CNF.scope.indexOf( s ) >=  0 ); }        if ( loved  &&  CNF.env.wgAction === "view" ) { mw.hook( "ve.activationComplete" ).add(              function  {                  CNF.live = true;                  feeder;               }            ); mw.hook( "ve.deactivate" ).add(              function  {                  feeder;               }            ); }     } else if ( CNF.list ) { features; }     if ( CNF.live ) { mw.loader.using( [ "jquery.textSelection" ],                         feeder ); } else { feeder; }     mw.hook( Signature + ".keymap" ).add( fetch ); }  // fire

function first { // Autorun on loading // Uses: //   >  Signature //   >  Version //    < CNF.signature //    < CNF.env //    < CNF.scope //    < CNF.list //    < CNF.bib //   mw.loader.getState //   mw.loader.state //   mw.config.get //   mw.loader.using //   mw.hook //   (fetch) //   (fire) // 2018-08-24 PerfektesChaos@de.wikipedia var rls; CNF.signature = "ext.gadget." + Signature; if ( mw.loader.getState( CNF.signature ) !==  "ready" ) { rls = { }; rls[ CNF.signature ] = "ready"; mw.loader.state( rls ); CNF.env = mw.config.get( [ "wgAction",                                     "wgCanonicalSpecialPageName" ] ); CNF.bib[ Signature ] = { doc: "" + CNF.doc + "", type: Signature, vsn: Version }; CNF.bib = CNF.bib[ Signature ]; if ( CNF.env.wgCanonicalSpecialPageName === "Blankpage" ) { CNF.env.wgTitle = mw.config.get( "wgTitle" ); if ( CNF.env.wgTitle.indexOf( "/" + Signature ) >  0 ) { CNF.scope = false; CNF.list = true; }        }         if ( ! CNF.list ) { mw.hook( Signature + ".actions" ).add( fire ); }        mw.loader.using( [ "user" ],                          fire ); mw.hook( Signature + ".ready" ).fire( CNF.bib ); }  }   // first

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

/// EOF  keyboardMapper/d.js