User:PerfektesChaos/js/idResolver/core/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/idResolver/core/d.js
// Implement ID resolving alternatives on HTML page
/// 2018-10-02 PerfektesChaos@de.wikipedia
// ResourceLoader:  compatible;
//                  "oojs", "oojs-ui-core", "oojs-ui-widgets"
/// 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.92,
       IDA     = "idResolver",
       IDEA    = { illusive:  0.85,
                   signature: "ext.gadget." + IDA,
                   sub:       "/core",
                   type:      IDA,
                   seen:      "#00008B" },
       CHANCE  = { },
       TYPES, OO;



   TYPES = { pdf:     { ext:     "PDF",
                        start:   "[./=]",
                        commons: "2/23/Icons-mini-file_acrobat.gif"
                      },
             msexcel: { ext:     "XLS",
                        commons: "b/ba/Page_white_excel.png"
                      },
             msword:  { ext:     "DOC",
                        commons: "a/a1/Page_white_word.png"
                      }
           };



   // -------------------------------------------------------------------



   function fair( adjust ) {
      // HTML-escape URL string
      // Precondition:
      //    adjust  -- string
      // Postcondition:
      //    Returns string with HTML-escaped code
      // 2016-05-01 PerfektesChaos@de.wikipedia
     return adjust.replace( /'/g, "&#39;" )
                  .replace( /</g, "&lt;" )
                  .replace( />/g, "&gt;" );
   }   // fair()



   function fiat( application, adaption ) {
      // Callback from external interface, start subsystem
      // Precondition:
      //    application  -- application object
      //    adaption     -- user configuration object
      // Uses:
      //    >  Version
      //    >< IDA.vsn
      //    >< IDA.launched
      //     < IDEA.cfg
      //     < IDEA.seen
      //    mw.loader.using()
      //    (IDEA.first)
      // 2016-10-20 PerfektesChaos@de.wikipedia
      IDA     = application;
      IDA.vsn = IDA.vsn + " /" + Version;
      if ( typeof IDA.launched  !==  "boolean" ) {
         IDA.launched = true;
         IDEA.cfg     = adaption;
         if ( typeof IDEA.cfg.seen  ===  "string"
              &&     /[0-9A-Fa-f]{6}/.test( IDEA.cfg.seen ) ) {
            IDEA.seen = "#" + IDEA.cfg.seen;
         }
         mw.loader.using( [ "oojs",
                            "oojs-ui-core",
                            "oojs-ui-widgets" ],
                          IDEA.first );
      }
   }   // fiat()



   function find( append, already ) {
      // Extend selector to find URL in document
      // Precondition:
      //    append   -- string, with URL segment
      //    already  -- string, with prepending selector, or not
      // Postcondition:
      //    Returns selector string
      // 2017-01-25 PerfektesChaos@de.wikipedia
      return ( already  ?  already + ","  :  "" )
             +  "[href*='" + append + "']";
   }   // find()



   function fire() {
      // Intialize core subsystem
      // Uses:
      //    >  IDEA.signature
      //    >  IDEA.sub
      //    >  IDEA.type
      //    mw.loader.getState()
      //    mw.loader.state()
      //    mw.hook()
      //    (fiat)
      // 2018-08-24 PerfektesChaos@de.wikipedia
      var signature = IDEA.signature + IDEA.sub,
          rls;
      if ( mw.loader.getState( signature ) !== "ready" ) {
         rls = { };
         rls[ signature ] = "ready";
         mw.loader.state( rls );
         mw.hook( IDEA.type + IDEA.sub + ".ready" ).fire( fiat );
      }
   }   // fire()



   // -------------------------------------------------------------------



   CHANCE.dnb = { live: true,
                  re:   new RegExp( "/(?:gnd/)?"
                                    + "([0-9][0-9.]+-?[0-9xX])$" )
                };   // 2017-01-24


   CHANCE.dnb.resolver = [
      "https://d-nb.info/#",
      // d:P227
      "https://www.deutsche-digitale-bibliothek.de/entity/#",
      "http://swb.bsz-bw.de/DB=2.104/SET=1/TTL=1//CMD?retrace=0"
      + "&trm_old=&ACT=SRCHA&IKT=2999&SRT=RLV&MATCFILTER=N&MATCSET=N"
      + "&NOABS=Y&SHRTST=50&TRM=#",
      "https://beacon.findbuch.de/seealso/pnd-aks?format=sources&id=#"
      ];   // 2018-10-02 PerfektesChaos@de.wikipedia
      // findbuch.de   under construction


   CHANCE.dnb.find = function () {
      // Find all matching links in content and apply basic data
      // Uses:
      //    >  IDEA.$external
      //    find()
      //    (CHANCE.dnb.found)
      //    (CHANCE.dnb.found2)
      // 2017-01-25 PerfektesChaos@de.wikipedia
      var s = find( "//d-nb.info/" );
      s = find( "//www.deutsche-digitale-bibliothek.de/entity/", s );
      IDEA.$external.filter( s ).each( CHANCE.dnb.found );
      s = find( "//portal.dnb.de/opac.htm?method=" );
      IDEA.$external.filter( s )
                    .filter( find( "&query=idn%3D" ) )
                    .each( CHANCE.dnb.found2 );
   };   // CHANCE.dnb.find()


   CHANCE.dnb.found = function ( ignore, element ) {
      // Process one matching link
      // Precondition:
      //    ignore   -- number of match
      //    element  -- DOM element
      // Uses:
      //    >  CHANCE.dnb.re
      //    IDEA.fiat()
      // 2016-05-01 PerfektesChaos@de.wikipedia
      var $a   = $( element ),
          sign = $a.attr( "href" ),
          got  = CHANCE.dnb.re.exec( sign );
      if ( got ) {
         IDEA.fiat( $a, "dnb", got[ 1 ] );
      }
   };   // CHANCE.dnb.found()


   CHANCE.dnb.found2 = function ( ignore, element ) {
      // Process one matching link
      // Precondition:
      //    ignore   -- number of match
      //    element  -- DOM element
      // Uses:
      //    >< CHANCE.dnb.re2
      //    IDEA.fiat()
      // 2016-05-01 PerfektesChaos@de.wikipedia
      var $a   = $( element ),
          sign = $a.attr( "href" ),
          got;
      if ( typeof CHANCE.dnb.re2  !==  "object" ) {
         CHANCE.dnb.re2 = new RegExp( "&query=idn%3D([0-9]+)\\b" );
      }
      got = CHANCE.dnb.re2.exec( sign );
      if ( got ) {
         IDEA.fiat( $a, "dnb", got[ 1 ] );
      }
   };   // CHANCE.dnb.found2()




   CHANCE.doi = { live: true,
                  re:   new RegExp( "[/=](10\\.[0-9]+(?:/|%2F)[^?&#]+)"
                                    + "(?:[?&#].*)?$" ) };
   CHANCE.doi.resolver = [
      "https://doi.org/#",
      "https://dx.doi.org/#",
      "http://dx.doi.org/#",
      "http://doai.io/#",
      "https://openaccessbutton.org/#",
      "https://sci-hub.io/#",
      "https://scholar.google.de/scholar?q=#"
      ];   // 2018-01-11 PerfektesChaos@de.wikipedia
/*
<a href="//dx.doi.org/10.1159/000354617" class="extiw">  Syntaxcheck
https://openaccessbutton.org/
https://sci-hub.io/
https://scholar.google.de/scholar?q=#
http://doai.io/10.1159/000354617
https://openaccessbutton.org/10.1159/000354617
https://sci-hub.io/10.1159/000354617
https://scholar.google.de/scholar?q=10.1159/000354617
http://www.springerlink.com/Index/10.1007/s10267-002-0068-x
http://www.springerlink.com/index/10.1007/s10267-002-0068-x
http://onlinelibrary.wiley.com/doi/#
*/


   CHANCE.doi.find = function () {
      // Find all matching links in content and apply basic data
      // Uses:
      //    >  IDEA.$extiw
      //    >  IDEA.$external
      //    find()
      //    (CHANCE.doi.found)
      // 2017-01-25 PerfektesChaos@de.wikipedia
      var seek = find( "//dx.doi.org/10." );
      IDEA.$extiw.filter( seek ).each( CHANCE.doi.found );
      seek = find( "//doai.io/10.", seek );
      seek = find( "//openaccessbutton.org/10.", seek );
      IDEA.$external.filter( seek ).each( CHANCE.doi.found );
      seek = find( "//onlinelibrary.wiley.com/" );
      IDEA.$external.filter( seek ).filter( find( "doi/10." ) )
                    .each( CHANCE.doi.found );
      seek = find( "//www.springerlink.com/" );
      IDEA.$external.filter( seek ).filter( find( "ndex/10." ) )
                    .each( CHANCE.doi.found );
      seek = find( "google.com/scholar?q=" );
      seek = find( "google.de/scholar?q=", seek );
      IDEA.$external.filter( seek ).filter( find( "/scholar?q=10." ) )
                    .each( CHANCE.doi.found );
   };   // CHANCE.doi.find()


   CHANCE.doi.found = function ( ignore, element ) {
      // Process one matching link
      // Precondition:
      //    ignore   -- number of match
      //    element  -- DOM element
      // Uses:
      //    >  CHANCE.doi.re
      //    IDEA.fiat()
      // 2016-05-01 PerfektesChaos@de.wikipedia
      var $a   = $( element ),
          sign = $a.attr( "href" ),
          got  = CHANCE.doi.re.exec( sign );
      if ( got ) {
         sign = got[ 1 ];
         try {
            sign = decodeURIComponent( sign );
         } catch (e) {
         }
         IDEA.fiat( $a, "doi", sign );
      }
   };   // CHANCE.doi.found()




   CHANCE.isbn = { live:     true,
                   resolver: null };



/*
http://www.ubka.uni-karlsruhe.de/kvk.html?SB=# KVK
http://gso.gbv.de/DB=2.1/CMD?ACT=SRCHA&IKT=1007&TRM=#
http://193.30.112.134/F/?func=find-a&find_code=IBN&request=#
http://swb.bsz-bw.de/DB=2.1/CMD?ACT=SRCHA&IKT=1007&TRM=#
http://gateway-bayern.bib-bvb.de/aleph-cgi/bvb_suche?sid=WIKIPEDIA&find_code_1=ISBN&find_request_1=#
http://digibib.kobv.de/cgi-bin/deeplink-from-wikipedia?ISBN=#
http://cbsopac.rz.uni-frankfurt.de/DB=2.1/CMD?ACT=SRCHA&IKT=8520&TRM=#
http://aleph20-prod-acc.obvsg.at/F?func=find-b&find_code=IBN&request=#
http://ml.metabib.ch/V/?func=meta-1-check&mode=advanced&portal=IDS&institute=IDS&new_lng=ger&find_code_2=ISBN&find_request_2=#&find_op_1=AND&find_code_3=WAU&find_request_3=&ckbox=IDS00431&ckbox=IDS00600&ckbox=IDS00432&ckbox=IDS00433&ckbox=IDS06097
http://www.swissbib.ch/TouchPoint/start.do?Language=de&Query=540=%22#%22
http://opac.nebis.ch/F/?func=scan&scan_code=020&scan_start=#
*/



   CHANCE.isbn.factory = function ( alien ) {
      // Populate and retrieve patterns
      // Precondition:
      //    alien  -- string with language code, or false
      // Postcondition:
      //    Returns pattern
      // Uses:
      //    >< IDEA.patterns
      //    CHANCE.isbn.lib.finder()
      //    IDEA.factory()
      // 2016-05-01 PerfektesChaos@de.wikipedia
      var r, suite;
      if ( alien ) {
         suite = "isbn/" + alien;
      } else {
         suite = "isbn";
      }
      if ( typeof IDEA.patterns[ suite ]  ===  "object" ) {
         r = IDEA.patterns[ suite ];
      } else {
         r = IDEA.factory( suite,  CHANCE.isbn.lib.finder( alien ) );
      }
      return r;
   };   // CHANCE.isbn.factory()


   CHANCE.isbn.fed = function ( application ) {
      // Got isbnLib
      // Precondition:
      //    application  -- isbnLib
      // Uses:
      //    >  CHANCE.isbn.cfg
      //    >  CHANCE.isbn.cfg.list
      //    >  CHANCE.isbn.cfg.catalogs
      //    >  CHANCE.isbn.fire
      //     < CHANCE.isbn.lib
      //     < CHANCE.isbn.list
      //     < CHANCE.isbn.re
      //    CHANCE.isbn.lib.furnish()
      //    (CHANCE.isbn.fire)
      // 2016-05-01 PerfektesChaos@de.wikipedia
      CHANCE.isbn.lib  = application;
      CHANCE.isbn.list = false;
      if ( typeof CHANCE.isbn.cfg  ===  "object" ) {
         if ( typeof CHANCE.isbn.cfg.list  ===  "boolean" ) {
            CHANCE.isbn.list = CHANCE.isbn.cfg.list;
         }
         if ( typeof CHANCE.isbn.cfg.catalogs  ===  "object" ) {
            CHANCE.isbn.lib.furnish( CHANCE.isbn.cfg.catalogs );
         }
      }
      CHANCE.isbn.re = new RegExp( "/([0-9]+[xX]?)$" );
      CHANCE.isbn.fire();
   };   // CHANCE.isbn.fed()


   CHANCE.isbn.feeder = function ( after ) {
      // Retrieve isbnLib
      // Precondition:
      //    after  -- callback when ready
      // Uses:
      //    >  Version
      //     < CHANCE.isbn.fire
      //    mw.loader.state()
      //    mw.loader.load()
      //    mw.hook()
      //    (CHANCE.isbn.fed)
      // 2018-08-30 PerfektesChaos@de.wikipedia
      var rls;
      CHANCE.isbn.fire = after;
      if ( ! mw.loader.getState( "ext.gadget.isbnLib" ) ) {
         rls = { };
         rls[ "ext.gadget.isbnLib" ] = "loading";
         mw.loader.state( rls );
         mw.loader.load( "https://en.wikipedia.org/w/index.php?"
                         + "title=User:PerfektesChaos/js/"
                         + "isbnLib/"
                         + ( Version > 0  ?  "r"  :  "d" )
                         + ".js&bcache=1&maxage="
                         + "604810"
                         + "&action=raw&ctype=text/javascript" );
      }
      mw.hook( "isbnLib.ready" ).add( CHANCE.isbn.fed );
   };   // CHANCE.isbn.feeder()


   CHANCE.isbn.$fetch = function ( ask ) {
      // Retrieve jQuery element for menu
      // Precondition:
      //    ask  -- string with identifier
      // Postcondition:
      //    Returns jQuery <span> object
      // Uses:
      //    >  CHANCE.isbn.list
      //    CHANCE.isbn.lib.focus()
      //    CHANCE.isbn.factory()
      //    IDEA.fork()
      //    IDEA.fill()
      //    CHANCE.isbn.lib.flip()
      //    CHANCE.isbn.lib.format()
      // 2016-09-01 PerfektesChaos@de.wikipedia
      var slang   = CHANCE.isbn.lib.focus( ask ),
          pattern = CHANCE.isbn.factory( slang ),
          $a      = $( "<a>" ),
          $r      = $( "<span>" ),
          s, $span;
      $a.attr( { "href":   "/wiki/Special:Booksources/" + ask,
                 "target": IDEA.fork( "www", "URL" ),
                 "title":  s } )
         .css( { "font-weight": "bold" } )
         .text( "Wiki" );
      $r.append( $a )
        .append( $( "<br />" ) );
      IDEA.fill( "isbn", pattern, ask, $r );
      if ( CHANCE.isbn.list ) {
         s = CHANCE.isbn.lib.flip( ask );
         if ( s ) {
            $span = $( "<span>" ).css( { "color": "#404040" } )
                                 .text( s );
            $r.append( $( "<br />" ) )
              .append( $span );
         }
      }
      return $r;
   };   // CHANCE.isbn.$fetch()


   CHANCE.isbn.find = function ( $area ) {
      // Find all matching links in content and apply basic data
      // Precondition:
      //    $area  -- jQuery with focussed page content
      // Uses:
      //    (CHANCE.isbn.found)
      // 2016-05-01 PerfektesChaos@de.wikipedia
      $area.find( ".mw-magiclink-isbn" ).each( CHANCE.isbn.found );
   };   // CHANCE.isbn.find()


   CHANCE.isbn.found = function ( ignore, element ) {
      // Process one matching link
      // Precondition:
      //    ignore   -- number of match
      //    element  -- DOM element
      // Uses:
      //    >  CHANCE.isbn.re
      //    CHANCE.isbn.lib.format()
      //    IDEA.fiat()
      // 2016-09-01 PerfektesChaos@de.wikipedia
      var $a     = $( element ),
          source = $a.attr( "href" ),
          got    = CHANCE.isbn.re.exec( source ),
          show, sign;
      if ( got ) {
         sign = got[ 1 ].toUpperCase();
         show = CHANCE.isbn.lib.format( sign );
         if ( show ) {
            $a.text( "ISBN " + show );
            IDEA.fiat( $a, "isbn", sign );
         }
      }
   };   // CHANCE.isbn.found()




   CHANCE.issn = { live: true,
                   re:   new RegExp( "[/=:]" +
                                     "([0-9]{4}-?[0-9]{3}[0-9xX])" +
                                     "(?:&.+)?$" )
                 };   // 2017-01-24


   CHANCE.issn.resolver = [
      "http://www.worldcat.org/issn/#",
      "http://dispatch.opac.dnb.de/DB=1.1/CMD?ACT=SRCHA&IKT=8&TRM=#",
      "http://services.dnb.de/fize-service/gvr/html-service.htm?issn=#",
      "http://www.jstor.org/journals/#",
      "http://www.sudoc.abes.fr//DB=2.1/SET=1/TTL=1/CLK?IKT=8&TRM=#"
      ];   // 2017-10-04 PerfektesChaos@de.wikipedia
   // http://www.worldcat.org/issn/08993718
   // http://www.worldcat.org/issn/1234-5678
   // http://www.jstor.org/journals/08993718
   // http://dispatch.opac.dnb.de/DB=1.1/CMD?ACT=SRCHA&IKT=8&TRM=08993718
   // http://www.sudoc.abes.fr//DB=2.1/SET=1/TTL=1/CLK?IKT=8&TRM=08993718


   CHANCE.issn.find = function () {
      // Find all matching links in content and apply basic data
      // Uses:
      //    >  IDEA.$external
      //    find()
      //    (CHANCE.issn.found)
      // 2017-10-04 PerfektesChaos@de.wikipedia
      var s = find( "//www.worldcat.org/issn/" );
      s = find( "//www.worldcat.org/search?fq=x0:jrnl&q=n2:", s );
      s = find( "//zdb-katalog.de/list.xhtml?key=iss&t=", s );
      s = find( "//services.dnb.de/fize-service/gvr/html-service.htm?issn=",
                s );
      s = find( "//dispatch.opac.d-nb.de/DB=1.1/CMD?ACT=SRCHA&IKT=8&TRM=",
                s );
      IDEA.$external.filter( s ).each( CHANCE.issn.found );
   };   // CHANCE.issn.find()


   CHANCE.issn.found = function ( ignore, element ) {
      // Process one matching link
      // Precondition:
      //    ignore   -- number of match
      //    element  -- DOM element
      // Uses:
      //    >  CHANCE.dnb.re
      //    IDEA.fiat()
      // 2016-09-01 PerfektesChaos@de.wikipedia
      var $a   = $( element ),
          sign = $a.attr( "href" ),
          got  = CHANCE.issn.re.exec( sign ),
          s;
      if ( got ) {
         s = got[ 1 ].replace( /-/, "" );
         IDEA.fiat( $a, "issn", s );
      }
   };   // CHANCE.issn.found()


   CHANCE.www = { live: true };
   CHANCE.www.resolver = [
   // "http://wayback.archive.org/web/*/#",
      "https://web.archive.org/web/*/#",
      "http://www.webcitation.org/query?url=#",
      "https://archive.is/#"
      ];   // 2016-05-01 PerfektesChaos@de.wikipedia


   CHANCE.www.$fetch = function ( ask ) {
      // Retrieve jQuery element for menu
      // Precondition:
      //    ask  -- string with identifier
      // Postcondition:
      //    Returns jQuery <span> object
      // Uses:
      //    IDEA.factory()
      //    fair()
      //    IDEA.fork()
      //    IDEA.fill()
      // 2016-09-01 PerfektesChaos@de.wikipedia
      var pattern = IDEA.factory( "www", CHANCE.www.resolver ),
          s       = fair( ask ),
          $a      = $( "<a>" ),
          $r      = $( "<span>" );
      $a.attr( { "href":   s,
                 "target": IDEA.fork( "www", "URL" ),
                 "title":  s } )
         .css( { "font-weight": "bold" } )
         .text( "URL" );
      $r.append( $a )
        .append( $( "<br />" ) );
      IDEA.fill( "www", pattern, s, $r );
      return $r;
   };   // CHANCE.www.$fetch()


   CHANCE.www.find = function () {
      // Find all matching links in content and apply basic data
      // Uses:
      //    >  IDEA.$external
      //    find()
      //    (CHANCE.www.found)
      // 2017-01-25 PerfektesChaos@de.wikipedia
      IDEA.$external.filter( find( "//" ) ).each( CHANCE.www.found );
   };   // CHANCE.www.find()


   CHANCE.www.found = function ( ignore, element ) {
      // Process one matching link
      // Precondition:
      //    ignore   -- number of match
      //    element  -- DOM element
      // Uses:
      //    IDEA.fiat()
      //    IDEA.format()
      // 2016-09-01 PerfektesChaos@de.wikipedia
      var $a   = $( element ),
          sign = $a.attr( "href" ),
          s;
      if ( sign.indexOf( ".org/w" ) > 0 ) {
         if ( typeof CHANCE.www.reWiki  !==  "object" ) {
            s = "(?:ipedia"
                + "|ibooks"
                + "|idata"
                + "|imedia"
                + "|imediafoundation"
                + "|inews"
                + "|iquote"
                + "|isource"
                + "|iversity"
                + "|ivoyage"
                + "|tionary)";
            s = "\\/\\/[^/#?]*\\.?wik" + s + "\\.org/w";
            s = "^(?:[hft]+tps?:)?" + s;
            CHANCE.www.reWiki = new RegExp( s );
         }
         if ( CHANCE.www.reWiki.test( sign ) ) {
            sign = false;
          }
      }
      if ( sign ) {
         IDEA.fiat( $a, "www", sign );
         IDEA.format( $a, sign );
      }
   };   // CHANCE.www.found()




   CHANCE.arxiv  = { live: false };
   CHANCE.handle = { live: false };
   CHANCE.lccn   = { live: false };
   CHANCE.pmid   = { live: false };



   // -------------------------------------------------------------------



   IDEA.factory = function ( assign, apply ) {
      // Populate and retrieve patterns
      // Precondition:
      //    assign  -- string with pattern identifier
      //    apply   -- Array with URL patterns
      // Postcondition:
      //    Returns pattern
      // Uses:
      //    >< IDEA.patterns
      //    IDEA.flat()
      // 2016-05-01 PerfektesChaos@de.wikipedia
      var i, r, show, src;
      if ( typeof IDEA.patterns[ assign ]  ===  "object" ) {
         r = IDEA.patterns[ assign ];
      } else {
         r = [ ];
         for ( i = 0;  i < apply.length;  i++ ) {
            src  = apply[ i ];
            show = IDEA.flat( src );
            if ( show ) {
               r.push( [ src, show ] );
            }
         }   // for i
         IDEA.patterns[ assign ] = r;
      }
      return r;
   };   // IDEA.factory()



   IDEA.features = function ( adapt ) {
      // Consider user options
      // Precondition:
      //    adapt  -- object with CHANCE component
      // 2016-05-01 PerfektesChaos@de.wikipedia
      var i, src, urls;
      if ( typeof adapt.cfg.resolver  ===  "object" ) {
         urls = adapt.cfg.resolver;
         if ( typeof urls.length  ===  "number" ) {
            for ( i = 0;  i < urls.length;  i++ ) {
               src = urls[ i ];
               if ( $.inArray( src, adapt.resolver )  <  0 ) {
                  adapt.resolver.push( src );
               }
            }   // for i
         }
      }
   };   // IDEA.features()



   IDEA.$fetch = function ( assigned, ask, already ) {
      // Retrieve HTML code for menu
      // Precondition:
      //    assigned  -- string with CHANCE component name
      //    ask       -- string with identifier
      //    already   -- string with initial URL at href=
      // Postcondition:
      //    Returns jQuery <span> object
      // Uses:
      //    >  CHANCE.*.resolver
      //    IDEA.factory()
      //    IDEA.fill()
      // 2016-09-01 PerfektesChaos@de.wikipedia
      var pattern = IDEA.factory( assigned,
                                  CHANCE[ assigned ].resolver ),
          $r      = $( "<span>" );
      IDEA.fill( assigned, pattern, ask, $r, already );
      return $r;
   };   // IDEA.$fetch()



   IDEA.fiat = function ( $a, assigned, access ) {
      // Equip link initially
      // Precondition:
      //    $a        -- jQuery with <a>
      //    assigned  -- string with CHANCE component name
      //    access    -- string with resource identifier
      // Uses:
      //    >  CHANCE.*.shift
      //    >  IDEA.re
      //    >  IDEA.store
      //    IDEA.flash()
      //    IDEA.followed()
      //    (IDEA.flash)
      //    (IDEA.flip)
      // 2017-02-06 PerfektesChaos@de.wikipedia
      var shift = CHANCE[ assigned ].shift,
          props;
      if ( shift ) {
         $a.attr( "href",  shift.replace( IDEA.re, access ) )
           .addClass( "external " +
                      IDEA.type + "-shifted" );
      } else {
         props = { //   "href": "#",
                   "data-href": $a.attr( "href" ) };
         props[ IDEA.store + "scope" ] = assigned;
         props[ IDEA.store + "sign" ]  = access;
         if ( assigned === "www" ) {
            props.title = access;
            // pdf
         } else {
            props.title = assigned + ":" + access;
            $a.css( { "white-space": "nowrap" } );
         }
         $a.attr( props )
           .addClass( IDEA.type + " " +
                      IDEA.type + "-" + assigned )
           .dblclick( IDEA.flash )
           .click( IDEA.flip );
         IDEA.followed( $a,  assigned + access );
      }
   };   // IDEA.fiat()



   IDEA.fill = function ( adjacent, album, ask, $all, already ) {
      // Retrieve jQuery element for menu
      // Precondition:
      //    adjacent  -- string with scope
      //    album     -- Array with URL patterns
      //    ask       -- string with identifier
      //    $all      -- jQuery parent container object
      //    already   -- string with initial URL at href=, or false
      // Postcondition:
      //    $all has been extended.
      // Uses:
      //    >  IDEA.re
      //    fair()
      //    IDEA.$forward()
      //    IDEA.flat()
      // 2018-10-01 PerfektesChaos@de.wikipedia
      var s     = fair( ask ),
          sites = " ",
          i, pattern, site;
      for ( i = 0;  i < album.length;  i++ ) {
         if ( i ) {
            $all.append( $( "<br />" ) );
         }
         pattern = album[ i ];
         site    = pattern[ 0 ].replace( IDEA.re, s );
         if ( site !== already ) {
            $all.append( IDEA.$forward( adjacent,
                                        site,
                                        pattern[ 1 ] ) );
            if ( already ) {
               sites = sites + site + " ";
            }
         }
      }   // for i
      if ( already   &&
           sites.indexOf( " " + already )  <  0 ) {
         $all.append( $( "<br />" ) )
             .append( IDEA.$forward( adjacent,
                                    already,
                                    IDEA.flat( already ) ) );
      }
   };   // IDEA.fill()



   IDEA.fire = function () {
      // Start analysis and equipment
      // Precondition:
      //    all components ready
      // Uses:
      //    >  IDEA.codes
      //    >  CHANCE.*
      //    mw.hook()
      //    (IDEA.furnish)
      // 2016-10-20 PerfektesChaos@de.wikipedia
      var handler, i, scope;
      for ( i = 0;  i < IDEA.codes.length;  i++ ) {
         scope   = IDEA.codes[ i ];
         handler = CHANCE[ scope ];
         if ( typeof handler.cfg  ===  "object" ) {
            if ( typeof handler.features  ===  "function" ) {
               handler.features( handler );
            } else {
               IDEA.features( handler );
            }
         }
      }   // for i
      mw.hook( "wikipage.content" ).add( IDEA.furnish );
   };   // IDEA.fire()



   IDEA.first = function () {
      // Establish scope of analysis
      // Uses:
      //    >  CHANCE
      //    >  IDEA.cfg
      //     < OO
      //     < IDEA.codes
      //     < IDEA.make
      //     < IDEA.store
      //     < IDEA.story
      //     < IDEA.patterns
      //     < IDEA.re
      //     < IDEA.types
      //    CHANCE.isbn.feeder()
      //    IDEA.fire()
      //    (IDEA.fire)
      // 2016-05-01 PerfektesChaos@de.wikipedia
      var handler, s;
      OO = window.OO;
      IDEA.codes = [ ];
      for ( s in CHANCE ) {
         handler = CHANCE[ s ];
         if ( handler.live ) {
            switch ( typeof IDEA.cfg[ s ] ) {
               case "boolean":
                  if ( ! IDEA.cfg[ s ] ) {
                     handler.live = false;
                  }
                  break;
               case "object":
                  if ( IDEA.cfg[ s ] ) {
                     handler.cfg = IDEA.cfg[ s ];
                  }
                  break;
            }   // switch  typeof IDEA.cfg[ s ]
            if ( handler.live   &&
                 ( typeof handler.find      !==  "function"   ||
                   typeof handler.resolver  !==  "object" ) ) {
               handler.live = false;
            }
            if ( handler.live ) {
               if ( s === "www" ) {
                  if ( IDEA.cfg.linking ) {
                     handler.shift = false;
                  } else {
                     handler.live = false;
                  }
               } else if ( typeof handler.cfg  ===  "object"   &&
                           typeof handler.cfg.shift  ===  "string"   &&
                           handler.cfg.shift.indexOf( "#" )  >  0 ) {
                  handler.shift = handler.cfg.shift;
               } else {
                  handler.shift = false;
               }
               if ( handler.live ) {
                  IDEA.codes.push( s );
               }
            }
         }
      }   // for s in CHANCE
      if ( typeof IDEA.cfg.make  ===  "number" ) {
         IDEA.make = IDEA.cfg.make;
      } else {
         IDEA.make = 0;
      }
      IDEA.store    = "data-" + IDEA.type.toLowerCase() + "-";
      IDEA.story    = false;
      IDEA.patterns = { };
      IDEA.re       = new RegExp( "#" );
      IDEA.types    = false;
      if ( CHANCE.isbn.live ) {
         CHANCE.isbn.feeder( IDEA.fire );
      } else {
         IDEA.fire();
      }
   };   // IDEA.first()



   IDEA.flash = function () {
      // Handler for double-click
      // Postcondition:
      //    Returns always false, stop the bubbling
      // Uses:
      //    this  -- clicked element
      //    >  IDEA.store
      //    IDEA.fork()
      // 2016-09-01 PerfektesChaos@de.wikipedia
      var msec  = 1000,
          that  = this,
          $that = $( that ),
          scope = $that.attr( IDEA.store + "scope" ),
          state    = IDEA.store + "state";
      window.open( $that.attr( "data-href" ),
                   IDEA.fork( scope, "URL" ) );
      window.setTimeout( function () {
                            if ( $that.attr( state ) === "show" ) {
                               IDEA.flip.call( that );
                            }
                         },
                         msec );
   };   // IDEA.flash()



   IDEA.flat = function ( address ) {
      // Extract host
      // Precondition:
      //    address  -- string with URL pattern
      // Postcondition:
      //    Returns string with host, or false
      // Uses:
      //    >< IDEA.reAuth
      // 2016-05-01 PerfektesChaos@de.wikipedia
      var got, n, parts, r, s, sub;
      if ( typeof IDEA.reAuth  !==  "object" ) {
         IDEA.reAuth = new RegExp( "^[^/]*//([^/:]+)(?::[0-9]+)?/" );
      }
      got = IDEA.reAuth.exec( address + "/" );
      if ( got ) {
         parts = got[ 1 ].toLowerCase().split( "." );
         n     = parts.length - 1;
         if ( n ) {
            s = parts[ n - 1 ]  +  ".";
            r = s + parts[ n ];
            if ( n > 1  &&  s.length <= 4 ) {
               s = "." + s;
               if ( n > 1  &&  s.length <= 4 ) {
                  sub = ".ac.com.co.edu.gov.gv.";
                  if ( sub.indexOf( s )  >=  0 ) {
                     r = parts[ n - 2 ]  +  "."  +  r;
                  }
               }
            }
         }
      }
      return r;
   };   // IDEA.flat()



   IDEA.flip = function () {
      // Toggle click on hyperlink
      // Postcondition:
      //    Returns always false, stop the bubbling
      // Uses:
      //    this  -- clicked element
      //    >  IDEA.store
      //    >  IDEA.cfg.layer
      //    >  IDEA.illusive
      //    >  IDEA.type
      //    >  IDEA.$body
      //    >< IDEA.popups
      //    >< IDEA.cfg.illusive
      //    CHANCE.*.fetch()
      //    IDEA.$fetch()
      //    IDEA.followed()
      //    OO.ui.PopupWidget()
      // 2017-03-31 PerfektesChaos@de.wikipedia
      var $that    = $( this ),
          margin   = 10,
          start    = $that.attr( "data-href" ),
          state    = IDEA.store + "state",
          swap     = IDEA.store + "popup",
          index    = $that.attr( swap ),
          slip     = $that.attr( state ),
          live, options, popup, scope, sign, signature, $e;
      if ( index ) {
         index = parseInt( index, 10 );
         popup = IDEA.popups[ index ];
         live  = ( slip === "show" );
      }
      if ( live ) {
         slip = "hide";
      } else {
         if ( ! popup ) {
            if ( typeof IDEA.cfg.illusive  !==  "number" ) {
               if ( IDEA.cfg.layer ) {
                  IDEA.cfg.illusive = 1;
               } else {
                  IDEA.cfg.illusive = IDEA.illusive;
               }
            }
            index = IDEA.popups.length;
            scope = $that.attr( IDEA.store + "scope" );
            sign  = $that.attr( IDEA.store + "sign" );
            IDEA.followed( $that,  scope + sign,  true );
            options  = { align:               "backwards",
                         anchor:              true,
                         horizontalPosition:  "end",
                         padded:              false,
                         verticalPosition:    "below",
                         $floatableContainer: $that };
            if ( typeof CHANCE[ scope ].$fetch  ===  "function" ) {
               $e = CHANCE[ scope ].$fetch( sign, start );
            } else {
               $e = IDEA.$fetch( scope, sign, start );
            }
            signature = IDEA.type + "_choice_" + index;
            $e.addClass( IDEA.type + " " +
                         IDEA.type + "-" + scope )
              .attr( { "id": signature } )
              .css( { "font-family":  "sans-serif",
                      "font-size":    "medium",
                      "font-style":   "normal",
                      "font-variant": "normal",
                      "text-align":   "left" } );
            IDEA.$body.append( $e );
            $e             = $( "#" + signature );
            options.height = $e.outerHeight() + margin + margin;
            options.width  = $e.outerWidth()  + margin;
            $e.detach()
              .css( { "visibility": "visible" } );
            options.$content = $( "<div>" ).append( $e )
                                           .css( { "padding": "3px" } );
            popup = new OO.ui.PopupWidget( options );
            IDEA.popups.push( popup );
            $that.attr( swap, index );
            $e = popup.$element;
            $e.attr( { "id":   IDEA.type + "_popup_" + index,
                       "role": "tooltip"  } )
              .css( { "opacity": IDEA.cfg.illusive } );
            IDEA.$body.append( popup.$floatable );
            if ( $that.hasClass( IDEA.type + "-www" ) ) {
               sign = start;
            }
            $that.attr( "title", sign );
            popup.$floatable.attr( { "role": "tooltip" } )
                            .css( { "opacity":    IDEA.cfg.illusive,
                                    "padding":    "2px",
                                    "text-align": "center" } );
         }
         slip = "show";
      }
      $that.attr( state, slip );
      if ( popup ) {
         popup.toggle( slip === "show" );
      }
      return false;
   };   // IDEA.flip()



   IDEA.followed = function ( $a, assigned, apply ) {
      // Mark hyperlink as visited
      // Precondition:
      //    $a        -- jQuery with <a>
      //    assigned  -- string with full identifier
      //    apply     -- true if unconditionally
      // Uses:
      //    >  IDEA.type
      //    >  IDEA.cfg.light
      //    >  IDEA.seen
      //    >< IDEA.story
      // 2017-01-25 PerfektesChaos@de.wikipedia
      var learnt = apply,
          sign, webSs, $children, $span;
      if ( ! apply  &&  IDEA.story ) {
         learnt = ( IDEA.story.indexOf( " " + assigned + " " )  >=  0 );
      } else if ( typeof window.sessionStorage  ===  "object" ) {
         webSs = window.sessionStorage;
         if ( webSs   &&   typeof webSs.getItem  ===  "function" ) {
            sign = IDEA.type + ".visited";
            try {
               IDEA.story = webSs.getItem( sign );
               if ( IDEA.story ) {
                  IDEA.story = " " + IDEA.story + " ";
               } else {
                  IDEA.story = " ";
               }
               if ( IDEA.story.indexOf( " " + assigned + " " )  >=  0 ) {
                  learnt = true;
               } else if ( apply ) {
                  IDEA.story = IDEA.story + assigned;
                  if ( typeof webSs.setItem  ===  "function" ) {
                     webSs.setItem( sign, IDEA.story.substr( 1 ) );
                  }
                  IDEA.story = IDEA.story + " ";
               }
            } catch (e) {
            }
         }
      }
      if ( learnt ) {
         $a.addClass( IDEA.type + "-visited" );
         if ( ! IDEA.cfg.light ) {
            $children = $a.children();
            if ( $children.length ) {
               $children.css( { "color": IDEA.seen } );
            } else {
               $span = $( "<span>" );
               $span.css( { "color": IDEA.seen } );
               $span.text( $a.text() );
               $a.text( "" );
               $a.append( $span );
            }
         }
      }
   };   // IDEA.followed()



   IDEA.fork = function ( adjacent, at ) {
      // Create target window/tab specifier
      // Precondition:
      //    adjacent  -- string with scope
      //    at        -- string with URL host
      // Postcondition:
      //    Returns string with target name
      // Uses:
      //    >  IDEA.make
      //    >  IDEA.type
      // 2016-09-01 PerfektesChaos@de.wikipedia
      var r;
      switch ( IDEA.make ) {
         case 0:
            r = IDEA.type;
            break;
         case 1:
            r = adjacent;
            break;
         case 2:
            r = at;
            break;
         default:
            r = "_blank";
      }   // switch  IDEA.make
      return r;
   };   // IDEA.fork()



   IDEA.format = function ( $a, access ) {
      // Decorate external link
      // Precondition:
      //    $a      -- jQuery with <a>
      //    access  -- string with URL
      // Uses:
      //    >  TYPES
      //    >< IDEA.types
      // 2016-09-01 PerfektesChaos@de.wikipedia
      var cfg, css, s, sign, type;
      if ( ! IDEA.types ) {
         IDEA.types = TYPES;
         if ( typeof IDEA.cfg.types  ===  "object" ) {
            for ( sign in IDEA.cfg.types ) {
               cfg = IDEA.cfg.types[ sign ];
               if ( ! cfg ) {
                  IDEA.types[ sign ] = false;
               } else if ( typeof cfg  ===  "object"   &&
                           typeof cfg.commons  ===  "string"
                           &&     cfg.commons ) {
                  type         = IDEA.types[ sign ];
                  type.commons = cfg.commons;
                  if ( typeof cfg.ext  ===  "string"
                       &&     cfg.ext ) {
                     type.ext = cfg.ext;
                  }
               }
            }   // for sign in IDEA.types
         }
         for ( sign in IDEA.types ) {
            type = IDEA.types[ sign ];
            if ( type   &&
                 typeof type.ext  ===  "string"   &&   type.ext ) {
               s       = "^(?:https?:)?//[^/]+/.+"  +
                         ( typeof type.start  ===  "string"
                              ?   type.start
                              :   "\\." )  +
                         "("  +  type.ext.toUpperCase()  +
                         "|"  +  type.ext.toLowerCase()  +  ")"  +
                         "(?:[/?&=#].*)?$";
               type.re = new RegExp( s );
            } else {
               type.re = false;
            }
         }   // for sign in IDEA.types
      }
      for ( sign in IDEA.types ) {
         type = IDEA.types[ sign ];
         if ( type  &&  type.re  &&  type.re.test( access ) ) {
            $a.addClass( "url-type-" + sign );
            if ( typeof type.commons  ===  "string" ) {
               s   = "url(\"//upload.wikimedia.org/wikipedia/commons/"  +
                                               type.commons  +  "\") "  +
                     "center right no-repeat";
               css = { "background":    s,
                       "padding-right": "16px" };
               $a.css( css );
            }
            break;   // for sign
         }
      }   // for sign in IDEA.types
   };   // IDEA.format()



   IDEA.$forward = function ( adjacent, address, as ) {
      // Retrieve jQuery element for external link
      // Precondition:
      //    adjacent  -- string with scope
      //    address   -- string with URL
      //    as        -- string with title to show
      // Postcondition:
      //    Returns jQuery <a> object
      // Uses:
      //    IDEA.fork()
      // 2016-09-01 PerfektesChaos@de.wikipedia
      return $( "<a>" ).attr( { "href":   address,
                                "target": IDEA.fork( adjacent, as ),
                                "title":  address } )
                       .text( as );
   };   // IDEA.$forward()



   IDEA.furnish = function ( $area ) {
      // Equip links in page region with basic data
      // Precondition:
      //    $area  -- jQuery with focussed page content
      // Uses:
      //    >  IDEA.codes
      //    >  IDEA.type
      //    >< IDEA.popups
      //     < IDEA.$body
      //     < IDEA.$extiw
      //     < IDEA.$external
      //    CHANCE.*.find()
      //    mw.hook()
      // 2017-02-06 PerfektesChaos@de.wikipedia
      var i;
      if ( typeof IDEA.popups  !==  "object" ) {
         IDEA.popups = [ ];
      }
      IDEA.$body     = $( "body" );
      IDEA.$extiw    = $area.find( ".extiw" );
      IDEA.$external = $area.find( ".external" );
      for ( i = 0;  i < IDEA.codes.length;  i++ ) {
         CHANCE[ IDEA.codes[ i ] ].find( $area );
      }   // for i
      mw.hook( IDEA.type + ".changed" ).fire( $area );
   };   // IDEA.furnish()



   //--------------------------------------------------------------------



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

/// EOF </nowiki>   idResolver/core/d.js