User:PerfektesChaos/js/pageTeaserHint/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/pageTeaserHint/d.js
/// 2020-12-27 PerfektesChaos@de.wikipedia
//  Enrich links to pages with short description, intro preview and image
//  Part 1: Check wiki page for page links, equip with button etc.
//  ResourceLoader:  compatible;
//    dependencies: mediawiki.api,
//                  mediawiki.storage,
//                  mediawiki.ui.button,
//                  mediawiki.util
/// Fingerprint: #0#0#
/// License: CC-by-sa/4.0
/// <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.5,
       Signature = "pageTeaserHint",
       Store     = "User:PerfektesChaos/js/" + Signature,
       PTH       = { core:      { maxage: 86400,
                                  site:   "w:en",
                                  store:  Store,
                                  sub:    "core" },
                     doc:       { site:   "w:en",
                                  store:  Store },
                     got:       false,
                     lazy:      true,
                     limited:   true,
                     paged:     { "allpages":
                                    { suite:  ".mw-allpages-nav",
                                      search: ".mw-allpages-body"
                                    },
                                  "category":
                                    { suite:  "#mw-pages",
                                      search: "#mw-pages"
                                    },
                                  "contributions":
                                    { suite:  ".mw-contributions-list",
                                      search: "#mw-content-text"
                                    },
                                  "info":
                                    { suite:  "#mw-pageinfo-"
                                                 + "header-restrictions",
                                      search: false
                                    },
                                  "prefixindex":
                                    { suite:  ".mw-prefixindex-body",
                                      search: ".mw-prefixindex-body"
                                    },
                                  "search":
                                    { suite:  ".mw-search-results",
                                      search: ".mw-search-results"
                                    },
                                  "whatlinkshere":
                                    { suite:  "#mw-whatlinkshere-list",
                                      search: "#mw-content-text"
                                    }
                                },
                     pages:     { "*":      { button: { large: true
                                                      },
                                              list:   true },
                                  "info":   { button: { large: false
                                                      },
                                              list:   true },
                                  "search": { button: { large: true
                                                      },
                                              list:   false },
                                  "user":   { button: { large: false
                                                      },
                                              list:   true }
                                },
                       re:      false,
                       result:  false,
                       rooms:   false,
                       scope:   false,
                       trigger: { src: "OOjs UI icon "
                                       + "window-invert.svg",
                                  sub: "ec"
                                },
                       $widget: false
                     },
       REPOS     = { };
   PTH.REPOS = REPOS;



   function face() {
      // Page orientation
      // Precondition:
      //    DOM ready
      // Uses:
      //    >< PTH.$body
      //     < PTH.ltr
      // 2020-12-27 PerfektesChaos@de.wikipedia
      if ( ! PTH.$body ) {
         PTH.$body = $( "body" );
         PTH.ltr   = ( $( "html" ).attr( "dir" )  !==  "rtl" );
      }
   }   // face()



   function factory ( area, at, $a ) {
      // Check for matching link and register if appropriate
      // Precondition:
      //    area  -- number, of namespace
      //    at    -- string, with decoded link title
      //    $a    -- object of link to page, or not
      // Postcondition:
      //    Returns pretty link title, or not
      // Uses:
      //    >  PTH.limited
      //    >  PTH.re.usc
      //    >< PTH.got
      // 2020-12-27 PerfektesChaos@de.wikipedia
      var r = at;
      if ( area   &&
           ( area < 0    // How comes?
             ||  PTH.limited
             ||  area % 2 ) ) {
         r = false;
      }
      if ( r   &&   ( area ===  2  ||
                      area ===  6  ||
                      area ===  8  ||
                      area === 14 ) ) {
         r = false;
      }
      if ( r  &&  area  &&  PTH.limited ) {
         r = false;
      }
      if ( r ) {
         r = r.replace( PTH.re.usc, " " );
         PTH.got = PTH.got  ||  { };
         if ( typeof PTH.got[ r ]  !==  "object" ) {
            PTH.got[ r ] = { ns:      area,
                             show:    r,
                             ul:      [ ]
                           };
         }
         if ( $a ) {
            PTH.got[ r ].ul.push( $a );
         }
      }
      return r;
   }   // factory()



   function feed () {
      // All preconditions met, run core script
      // Uses:
      //    >  Signature
      //    >  PTH
      //    mw.hook()
      // 2020-12-27 PerfektesChaos@de.wikipedia
      mw.hook( Signature + ".init" ).fire( PTH );
   }   // feeder()



   function feeder () {
      // Retrieve core script
      // Uses:
      //    >< PTH.core
      //    REPOS.fire()
      //    mw.loader.using()
      //    (feed)
      // 2020-12-27 PerfektesChaos@de.wikipedia
      if ( PTH.core ) {
         PTH.core.suite = ( Version > 1  ?  "r"  :  "d" );
         if ( PTH.core.suite !== "r" ) {
            PTH.core.maxage = 100;
         }
         REPOS.fire( PTH.core.site,
                     PTH.core.store,
                     "/" + PTH.core.sub
                     + "/" + PTH.core.suite + ".js",
                     { maxage: PTH.core.maxage } );
         PTH.core = false;
         mw.loader.using( [ "mediawiki.api",
                            "mediawiki.storage",
                            "mediawiki.util" ],
                          feed );
      }
   }   // feeder()



   function fetch () {
      // Button has been pressed
      // Uses:
      //    >  PTH.selector
      //    >  PTH.$widget
      //    >  PTH.got
      //    >  PTH.page
      //    feeder()
      //    mw.hook()
      // 2020-12-27 PerfektesChaos@de.wikipedia
      var $ajax = $( "<div>" );
      PTH.$widget.empty();
      $ajax.addClass( "mw-ajax-loader",
                      PTH.selector + "ajax" )
           .css( { "margin-bottom": "0.2em",
                   "margin-left":   "1em",
                   "margin-right":  "1em",
                   "margin-top":    "0.2em" } )
           .text( String.fromCharCode( 160 ) );
      PTH.$widget.append( $ajax );
      feeder();
      mw.hook( Signature + ".result" ).fire( PTH.got, PTH.page );
   }   // fetch()



   function fiat ( at, assigned ) {
      // Matching link
      // Precondition:
      //    at        -- number of link to page, ignored
      //    assigned  -- DOM object of link to page
      // Uses:
      //    >  PTH.re.abs
      //    >  PTH.re.sns
      //    >  PTH.rooms
      //     < PTH.page.learnt
      //     < PTH.lazy
      //    factory()
      // 2020-12-27 PerfektesChaos@de.wikipedia
      var $a = $( assigned ),
          s  = $a.attr( "href" ),
          got, i, ns, space;
      if ( s.substr( 0, 6 ) === "/wiki/" ) {
         s = s.substr( 6 );
      } else {
         got = PTH.re.abs.exec( s );
         if ( got ) {
            s = got[ 1 ];
         } else {
            s = false;
         }
      }
      if ( s ) {
         i = s.indexOf( "#" );
         if ( i > 0 ) {
            s = s.substr( 0, i );
         }
         try {
            s = decodeURIComponent( s );
         } catch ( e ) {
         }
         got = PTH.re.sns.exec( s );
         if ( got ) {
            space = got[ 1 ].toLowerCase();
            if ( typeof PTH.rooms[ space ]  ===  "number" ) {
               ns = PTH.rooms[ space ];
            }
         }
         if ( s ) {
            ns = ns || 0;
            if ( factory( ns, s, $a ) ) {
               PTH.page.learnt = true;
               if ( ! ns ) {
                  PTH.lazy = false;
               }
            }
         }
      }
   }   // fiat()



   function finesse () {
      // Process info page
      // Uses:
      //    >  PTH.nsn
      //    >  PTH.page.button
      //     < PTH.page.learnt
      //     < PTH.lazy
      //    mw.config.get()
      // 2020-12-27 PerfektesChaos@de.wikipedia
      var cnf = mw.config.get( [ "wgPageContentModel",
                                 "wgTitle" ] );
      if ( cnf.wgPageContentModel === "wikitext"  &&
           factory( PTH.nsn, cnf.wgTitle ) ) {
         if ( ! PTH.nsn ) {
            PTH.lazy = false;
         }
         PTH.page.learnt = true;
      }
   }   // finesse()



   function fire () {
      // Document ready
      // Uses:
      //    >  PTH.scope
      //    >  PTH.pages
      //    >  Signature
      //    >  Version
      //    >  PTH.got
      //    >< PTH.page
      //     < PTH.$container
      //     < PTH.result
      //    mw.loader.load()
      //    PTH.furnish()
      //    feeder()
      //    (fetch)
      //    (fiat)
      // 2020-12-27 PerfektesChaos@de.wikipedia
      var button, seek, $got;
      switch ( PTH.scope ) {
         case "allpages":
         case "contributions":
         case "prefixindex":
         case "whatlinkshere":
         case "category":
            PTH.page = PTH.pages[ "*" ];
            break;
         default:
            PTH.page = PTH.pages[ PTH.scope ];
      }   // switch PTH.scope
      PTH.page.learnt = false;
      button          = PTH.page.button;
      button.fiat     = fetch;
      button.sel      = PTH.paged[ PTH.scope ].suite;
      button.support  = Signature + " " + Version;
      PTH.page.search = PTH.paged[ PTH.scope ].search;
      if ( PTH.page.search ) {
         PTH.page.$container = $( PTH.page.search );
         seek = "a[href*=\"/wiki/\"]:not(a[href*=\"#\"])";
         $got = PTH.page.$container.find( seek );
         if ( PTH.scope !== "user" ) {
            $got.not( ".mw-parser-output a" );
         }
         $got.each( fiat );
      } else {
         finesse();
      }
      if ( PTH.page.learnt ) {
         PTH.furnish( PTH.page.button );
      }
      delete PTH.page.learnt;
   }   // fire()



   function firing ( apply ) {
      // Check request conditions
      // Precondition:
      //    apply  -- config object, or not
      // Uses:
      //    >  Signature
      //    >< PTH.scope
      //     < PTH.limited
      //     < PTH.rooms
      //     < PTH.nsn
      //     < PTH.selector
      //     < PTH.paged.user
      //     < PTH.re
      //    mw.hook()
      //    mw.config.get()
      //    (fire)
      // 2020-12-27 PerfektesChaos@de.wikipedia
      var cnf, listen, s;
      mw.hook( Signature + ".config" ).remove( firing );
      if ( PTH.scope === false ) {
         PTH.scope = null;
         cnf       = mw.config.get( [ "wgAction",
                                      "wgPageContentModel",
                                      "wgNamespaceIds",
                                      "wgNamespaceNumber" ] );
         PTH.rooms    = cnf.wgNamespaceIds;
         PTH.nsn      = cnf.wgNamespaceNumber;
         PTH.selector = Signature.toLowerCase() + "-";
         if ( typeof apply  ===  "object"   &&
              apply ) {
            if ( typeof apply.limited  ===  "boolean" ) {
               PTH.limited = apply.limited;
            }
            if ( typeof apply.listen  ===  "boolean" ) {
               listen = apply.listen;
               PTH.paged.user = { suite:  "." + PTH.selector + "private",
                                  search: "." + PTH.selector + "private"
                                };
            }
         }
         switch ( cnf.wgAction ) {
            case "view":
               if ( PTH.nsn === -1 ) {
                  s = mw.config.get( "wgCanonicalSpecialPageName" );
                  switch ( s ) {
                     case "Allpages":
                     case "Contributions":
                     case "Prefixindex":
                     case "Search":
                     case "Whatlinkshere":
                        PTH.scope = s.toLowerCase();
                        break;
                  }   // switch wgCanonicalSpecialPageName
               } else if ( cnf.wgPageContentModel === "wikitext"
                           && PTH.nsn ) {
                  if ( PTH.nsn === 14 ) {
                     PTH.scope = "category";
                  } else if ( listen ) {
                     PTH.scope = "user";
                  }
               }
               break;
            case "edit":
            case "submit":
               if ( listen   &&
                    cnf.wgPageContentModel === "wikitext"   &&
                    PTH.nsn ) {
                  PTH.scope = "user";
               }
               break;
            case "info":
               if ( ! ( PTH.nsn && apply.limited )   &&
                    PTH.nsn !== 14 ) {
                  PTH.scope = "info";
               }
               break;
         }   // switch wgAction
         if ( PTH.scope ) {
            PTH.re  = { abs: new RegExp( "^(?:[htps]*:)?//[^/]+/wiki/"
                                         + "(.+)$" ),
                        sns: new RegExp( "^([^:]+):" ),
                        spc: new RegExp( " ", "g" ),
                        usc: new RegExp( "_", "g" ),
                        wsp: new RegExp( "^\\s*$" )
                      };
            $( fire );
         }
      }
   }   // firing()



   function first () {
      // Autorun on loading
      // Uses:
      //    >  Signature
      //    >  PTH.doc
      //    >  Version
      //     < PTH.signature
      //     < PTH.pub
      //    mw.loader.getState()
      //    mw.loader.state()
      //    mw.config.get()
      //    mw.hook()
      //    (firing)
      // 2020-12-27 PerfektesChaos@de.wikipedia
      var rls, s;
      PTH.signature = "ext.gadget." + Signature;
      if ( mw.loader.getState( PTH.signature )  !==  "ready" ) {
         rls = { };
         rls[ PTH.signature ] = "ready";
         mw.loader.state( rls );
         s = "[[" + PTH.doc.site + "/" + PTH.doc.store + "]]";
         PTH.pub = { doc:       s,
                     signature: PTH.signature,
                     type:      Signature,
                     vsn:       Version };
         mw.hook( Signature + ".ready" ).fire( PTH.pub );
         mw.hook( Signature + ".config" ).add( firing );
         mw.hook( Signature + ".config" ).fire();
      }
   }   // first()



   PTH.$file = function ( access, appear ) {
      // Create image
      // Precondition:
      //    access  -- media ID
      //               .ltr   -- version LTR
      //               .rtl   -- version RTL
      //               .src   -- page title
      //               .sub   -- 2-char-code of subdir
      //               .site  -- default: commons
      //    appear  -- number, of pixels
      // Postcondition:
      //    Returns jQuery <img>
      // Uses:
      //    >  PTH.ltr
      //    >  PTH.re.spc
      //    >  Signature
      // 2020-12-27 PerfektesChaos@de.wikipedia
      var $r  = $( "<img>" ),
          obj, src;
      if ( typeof access  ===  "object"
           &&     access  &&
           typeof appear  ===  "number"
           &&     appear > 0 ) {
         if ( typeof access.ltr  ===  "object"
              &&     access.ltr   &&
              typeof access.rtl  ===  "object"
              &&     access.rtl ) {
            obj = access[ ( this.ltr ? "ltr" : "rtl" ) ];
         } else {
            obj = access;
         }
         if ( typeof obj.src  ===  "string"
              &&     obj.src   &&
              typeof obj.sub  ===  "string"
              &&     obj.sub.length === 2 ) {
            src = obj.src.replace( PTH.re.spc, "_" );   // + encode()
            $r.attr( { "src": "https://upload."
                              + "wikimedia.org/wikipedia/commons"
                              + "/thumb/"
                              + obj.sub.substr( 0, 1 ) + "/"
                              + obj.sub + "/"
                              + src + "/"
                              + appear + "px-" + src + ".png"
                     } )
              .css( { "display": "inline" } );
         } else {
            window.console.log( Signature + ".$file() s",  access );
         }
      } else {
         window.console.log( Signature + ".$file() *",
                             access,
                             appear );
      }
      return $r;
   };   // PTH.$file()



   PTH.furnish = function ( apply ) {
      // Insert button
      // Precondition:
      //    apply  -- descriptive object
      //              .fiat     -- action
      //              .large    -- large or line-size?
      //              .sel      -- selector ahead of which to insert
      //              .support  -- query tooltip
      // Uses:
      //    >  PTH.ltr
      //    >  PTH.selector
      //    >< PTH.$widget
      //    mw.loader.load()
      //    face()
      //    PTH.$file()
      // 2020-12-27 PerfektesChaos@de.wikipedia
      var css   = { "background-color": "#3366CC",
                    "border":           "1px solid #3366CC",
                    "border-radius":    "2px",
                    "color":            "#FFFFFF",
                    "cursor":           "pointer",
                    "display":          "table",
                    "padding":          "0.546875em 1em",
                    "text-align":       "center",
                    "vertical-align":   "middle"
                  },
          $btn = $( "<div>" ),
          img, trigger, $img, $rel;
      if ( ! this.$widget ) {
         mw.loader.load( "mediawiki.ui.button" );
         // w:de:Template:MediaWiki-Button/styles.css
         this.$widget = $( "<div>" );
         this.$widget.addClass( this.selector + "widget" );
         face();
         this.$widget.css( { "float":
                                     ( this.ltr ? "right" : "left" ) } );
         $rel = $( apply.sel );
         $rel.eq( 0 ).before( this.$widget );
      }
      trigger = this.trigger;
      if ( typeof trigger.ltr  ===  "object" ) {
         trigger = trigger[ ( this.ltr ? "ltr" : "rtl" ) ];
      }
      img  = ( apply.large ? 30 : 18 );
      $img = this.$file( trigger, img );
      $btn.addClass( [ "mw-ui-button",
                       "mw-ui-progressive",
                       this.selector + "-button" ] )
          .append( $img )
          .attr( { "role":  "button",
                   "title": apply.support } )
          .click( apply.fiat )
          .css( css );
      this.$widget.append( $btn );
   };   // PTH.furnish()



   REPOS.fire = function ( at, access, append, alter ) {
      // Load from external URL
      // Precondition:
      //    at      -- Wikimedia Foundation site code, or not
      //    access  -- string with basic page name
      //    append  -- string with subpage, or not
      //    alter   -- parameter object, or MIME string, or not
      // Uses:
      //    >< REPOS.requests
      //    REPOS.foundation()
      //    mw.loader.load()
      // 2018-03-21 PerfektesChaos@de.wikipedia
      var source, syntax;
      if ( typeof REPOS.requests  !==  "object" ) {
         REPOS.requests = { };
      }
      if ( typeof REPOS.requests[ access ]  !==  "boolean" ) {
         REPOS.requests[ access ] = true;
         if ( append ) {
            source = access + append;
         } else {
            source = access;
         }
         if ( at ) {
            source = REPOS.foundation( at, source, alter );
            if ( typeof alter  ===  "object"
                 &&     alter   &&
                 typeof alter.ctype  ===  "string" ) {
               syntax = alter.ctype;
            }
         } else {
            syntax = alter;
         }
         mw.loader.load( source, syntax );
      }
   };   // REPOS.fire()



   REPOS.foundation = function ( at, access, alter ) {
      // Create URL within Wikimedia Foundation
      // Precondition:
      //    at      -- site code, or not
      //    access  -- string with page name
      //    alter   -- parameter object, or not
      // Postcondition:
      //    Returns full URL
      // 2018-03-21 PerfektesChaos@de.wikipedia
      var s = access,
          r = encodeURI( s );
      if ( typeof alter  ===  "object"
           &&     alter ) {
         r = "/w/index.php?title=" + r;
         if ( access.substr( -3 ) === ".js" ) {
            alter.ctype = "text/javascript";
         } else if ( access.substr( -4 ) === ".css" ) {
            alter.ctype = "text/css";
         }
         alter.action = "raw";
         for ( s in alter ) {
            r = r + "&" + s + "=" + encodeURI( alter[ s ] );
         }   // for s in alter
      } else {
         r = "/wiki/" + r;
      }
      if ( typeof at  ===  "string"
           &&     at ) {
         switch ( at ) {
            case "meta":
               r = "meta.wikimedia.org" + r;
               break;
            case "mw":
               r = "www.mediawiki.org" + r;
               break;
            case "w:en":
               r = "en.wikipedia.org" + r;
               break;
            default:
               r = window.location.host + r;
         }   // switch at
         r = "https://" + r;
      }
      return r;
   };   // REPOS.foundation()



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



// Emacs
// Local Variables:
// coding: utf-8-dos
// fill-column: 80
// End:

/// EOF </nowiki>   pageTeaserHint/d.js