Jump to content

User:PerfektesChaos/js/keyboardMapper/d.js

From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
/// 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)
/// <nowiki>
/* 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 </nowiki>   keyboardMapper/d.js