User:PerfektesChaos/js/citoidWikitext/core/d.js

/// User:PerfektesChaos/js/citoidWikitext/core.js // Execute core functionality for citoid on wikitext source editing /// 2018-09-03 PerfektesChaos@de.wikipedia // ResourceLoader: compatible; //   dependencies: -- /// Fingerprint: #0#0# /// @license GPL [//www.mediawiki.org/w/COPYING] (+GFDL, LGPL, CC-BY-SA) /// /* global window: false, JSON: 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   = -4.3,       Signature = "citoidWikitext",       Sub       = "core",       Sites     = "|dewiki|",       APIC      = { },       BOOK      = { },       DESC      = { },       EDIT      = { codeMirror: false,                     wikEd:      false },       GUIP      = { btn:    { },                     caret:  { },                     gadget: { },                     input:  { },                     push:   { } },       HELP      = { site:    "w:en",                     support: "user:PerfektesChaos/js/" + Signature },       I18N      = { },       PREGO     = { maxage:    604812,                     signature: "preferencesGadgetOptions",                     site:      "w:en",                     store:     "User:PerfektesChaos/js/",                     sub:       "/r.js" },       REPOS     = { maxage: 86400,                     site:   "w:en", store: "User:PerfektesChaos/js/"  }, PROJ     = false, TASK     = { }, UTIL     = { }, XPORT    = { core: { sites: Sites } }, CITWT;

function facilitated { // Mark sub-module as ready // Uses: //   >  Signature //   >  Sub //   >  Version //   >  XPORT //    < CITWT //    < .signature //    < .vsn //    < .type //   mw.loader.getState //   mw.loader.state //   mw.hook // 2018-08-24 PerfektesChaos@de.wikipedia var sign     = "ext.gadget." + Signature, sub      = "/" + Sub, signature = sign + sub, s        = mw.loader.getState( signature ), e, o, rls; if ( s !== "loaded" &&  s !== "ready" ) { rls = { }; rls[ signature ] = "loaded"; mw.loader.state( rls ); if ( typeof mw.libs[ Signature ] !==  "object"   ||              !      mw.libs[ Signature ] ) { mw.libs[ Signature ] = { }; }        CITWT = mw.libs[ Signature ]; CITWT.signature = sign; if ( typeof CITWT.vsn ===  "string" ) { CITWT.vsn = CITWT.vsn + " "; } else { CITWT.vsn = ""; }        CITWT.vsn   = CITWT.vsn + Sub.substr( 0, 1 ) + ":" + Version; CITWT.type = Signature; CITWT.suite = ( Version > 1 ?  "r"  :  "d" ); if ( typeof CITWT[ Sub ] !==  "object"   ||              !      CITWT[ Sub ] ) { CITWT[ Sub ] =  { }; }        e = XPORT[ Sub ]; o = CITWT[ Sub ]; for ( s in e ) { o[ s ] = e[ s ]; }  // for s in e         for ( s in XPORT ) { if ( typeof XPORT[ s ] ===  "function" ) { CITWT[ s ] = XPORT[ s ]; }        }   // for s in XPORT rls[ signature ] = "ready"; mw.loader.state( rls ); mw.hook( CITWT.type + sub + ".ready" ).fire; }  }   // facilitated

//---

APIC.site     = "https://citoid.wikimedia.org/api"; APIC.stateless = "/api/rest_v1/data/citation/mediawiki/";

APIC.fault = function ( jqXHR, textStatus, errorThrown ) { // API failure // Precondition: //   Common failure call // Uses: //   >  .type //    < APIC.scream //   GUIP.flat //   console.log //   console.dir // Remark: Used as event handler -- 'this' is not APIC // 2015-05-01 PerfektesChaos@de.wikipedia GUIP.flat( "unanswered" ); APIC.scream = textStatus + " -- Error: " + errorThrown; if ( typeof window.console ===  "object"   &&           typeof window.console.log  ===  "function" ) { window.console.log( CITWT.type + " * " + APIC.scream ); if ( textStatus  &&              typeof textStatus  ===  "object"   &&              typeof window.console.dir  ===  "function" ) { window.console.dir( textStatus ); }     }   };   // APIC.fault

APIC.finish = function { // All queries have been answered // Uses: //   >  APIC.results //   >< APIC.queries //   TASK.follow // 2017-06-10 PerfektesChaos@de.wikipedia var n = APIC.queries.length, i, j, q, r, ufo; for ( i = 0; i < APIC.results.length;  i++ ) { r = APIC.results[ i ]; if ( r ) { for ( j = 0; j < n;  j++ ) { q = APIC.queries[ j ]; if ( q === r.url ) { r.lucky          = true; APIC.queries[ j ] = r;                 r                 = false; break;  // for j               } }  // for j            if ( r ) { if ( ! ufo ) { ufo = [ ]; }              r.idResult = i;               ufo.push( r ); }        }      }   // for i      if ( ufo ) { i = 0; if ( ufo.length === 1 ) { ufo[ 0 ].idResult = false; }        for ( j = 0;  j < n;  j++ ) { q = APIC.queries[ j ]; if ( typeof q ===  "string" ) { ufo[ i ].queryURL = q;              APIC.queries[ j ] = ufo[ i ]; i++; }        }   // for j      } TASK.follow; };  // APIC.finish

APIC.fire = function { // Run queries at WMF via API // Precondition: //   mediawiki.api has been loaded // Uses: //   >  .server //   >  APIC.site //   >  APIC.stateless //   >  APIC.queries //   >< APIC.data //   >< APIC.jq      //    >< APIC.legacy //    < APIC.results //    < APIC.missing //   (APIC.found) //   (APIC.fault) // Remark: Used as event handler -- 'this' is not APIC // 2017-06-11 PerfektesChaos@de.wikipedia var f, i, query, service; if ( typeof APIC.jq !==  "object" ) { f = function ( jqXHR ) { jqXHR.setRequestHeader( "Content-Type",                                                   "application/json" ); };        if ( typeof CITWT.server  ===  "string" ) { service = CITWT.server; } else { service = APIC.site; }        APIC.data   = { format: "mediawiki" };   // mediawiki zotero APIC.jq    = { beforeSend: f,                         dataType:   "json",   // No "Intelligent Guess" url:       service }; APIC.legacy = ( service.indexOf( "/url" ) >  0 ); if ( APIC.legacy ) { APIC.jq.type = "POST"; } else if ( APIC.stateless ) { APIC.site = window.location.protocol + "//" + window.location.hostname + APIC.stateless; } else { APIC.jq.data = APIC.data; }     }      APIC.results = [ ]; APIC.missing = APIC.queries.length; for ( i = 0; i < APIC.missing;  i++ ) { /* citoid.wmflabs appears to handle an Array of URL and will return an Array of result objects, but there is nothing promised nor documented nor a stable implementation in spring 2015. */        query = APIC.queries[ i ]; switch ( typeof query ) { case "string": if ( APIC.legacy ) { APIC.data.url = query; APIC.jq.data = JSON.stringify( APIC.data ); } else if ( APIC.stateless ) { APIC.jq.url = APIC.site + encodeURIComponent( query ); } else { APIC.jq.data.search = query; }              $.ajax( APIC.jq ).done( APIC.found ) .fail( APIC.fault ); break; case "object": if ( typeof query.beforeSend ===  "string"                    &&     query.beforeSend  ===  "json" ) { query.jq.beforeSend = f;              } query.jq.beforeSend = f;              $.ajax( query.jq ).done( query.found ) .fail( query.fault ); break; }  // switch typeof query }  // for i   };   // APIC.fire

APIC.found = function ( arrived ) { // Answer arrived // Precondition: //   arrived  -- object, full result //               string, favorite result //               boolean, no favorite result // Uses: //   >< APIC.missing //   >< APIC.results //   GUIP.flat //   TASK.follow //   APIC.finish // Remark: Used as event handler -- 'this' is not APIC // 2018-07-14 PerfektesChaos@de.wikipedia var got; switch ( typeof arrived ) { case "boolean": APIC.missing--; break; case "string": APIC.missing = -1; GUIP.flat; TASK.follow; break; case "object": if ( arrived  &&   typeof arrived.length  ===  "number" ) { got = arrived[ 0 ]; if ( got  &&   typeof got  ===  "object" ) { if ( typeof got.url ===  "string"   &&   got.url ) { APIC.results.push( got ); APIC.missing--; } else if ( typeof got.Error ===  "string" ) { // Never reached //      HTTP-OPTIONS call APIC.fault only // Plan: //  * Record on console //    shared with APIC.fault //  * Enrich flat("unanswered") by details GUIP.flat( "unanswered" ); // GUIP.flat( "unanswered", $span ); }              }            }            break; }  // switch typeof arrived if ( ! APIC.missing ) { APIC.finish; }  };   // APIC.found

//---

BOOK.fire = function { // Initialize ISBN support // Uses: //   mw.hook //   (BOOK.first) // 2016-03-21 PerfektesChaos@de.wikipedia mw.hook( "isbnLib.ready" ).add( BOOK.first ); };  // BOOK.fire

BOOK.first = function ( application ) { // Uses: // Precondition: //   application   -- isbnLib // Uses: //    < .isbnLib //   .isbnLib.furnish //   GUIP.fire // 2016-03-25 PerfektesChaos@de.wikipedia CITWT.isbnLib =  application; switch ( typeof CITWT.isbn ) { case "string": case "object": CITWT.isbnLib.furnish( CITWT.isbn ); }  // switch typeof CITWT.isbn GUIP.fire; };  // BOOK.first

//---

DESC.re = { };

DESC.fire = function ( attempt ) { // Analyse request description string // Precondition: //   attempt  -- string or false // Postcondition: //   Returns object, or false // Uses: //   >  GUIP.caret.story //   DESC.fold //   DESC.* // 2015-07-01 PerfektesChaos@de.wikipedia var got, i, mode, r, s, start; if ( attempt ) { s = attempt.replace( /^\s+/, "" ); i = s.indexOf( " " ); if ( i >= 0 ) { s = s.substr( 0, i ); }        if ( s ) { switch ( s.substr( 0, 1 ) ) { case "[": if ( s.substr( 1, 1 ) ===  "[" ) { i = s.indexOf( "]]", 2 ); if ( i > 0 ) { s = s.substr( 0, i ); i = s.indexOf( "|", 1 ); if ( i > 0 ) { s = s.substr( 0, i ); }                       if ( s.indexOf( ":", 2 )  >  0 ) { mode = 2; } else { s = false; }                    } else { s = false; }                 } else if ( s.indexOf( "//" )  >  0 ) { mode = 1; }                 if ( mode ) { s = s.substr( mode ); }                 break; case "{": if ( s.substr( 1, 1 ) ===  "{" ) { s = DESC.fold( s ); if ( s ) { mode = 3; }                 }                  break; default: mode = 0; i = s.indexOf( "\n", 5 ); if ( i > 0 ) { s = s.substr( 0, i ); }                 i = s.indexOf( "]]", 2 ); if ( i > 0 ) { s = s.substr( 0, i ); }                 break; }  // switch s.substr( 0, 1 ) if ( s ) { if ( mode ) { s = s.replace( /^\s+/, "" ) .replace( /\s+$/, "" ); if ( mode === 1  &&   s.substr( 0, 2 )  ===  "//" ) { s = window.location.protocol + s;                 } }              got = /^([a-zA-Z]+)\b/.exec( s ); if ( got ) { start = got[ 1 ].toLowerCase; if ( typeof DESC[ start ] ===  "function"                       &&   start !== "fire" ) { r = DESC[ start ]( s, mode ); }              }            }         }      }      return r;   };   // DESC.fire

DESC.fold = function ( attempt ) { // Analyse presumable template transclusion // Precondition: //   attempt   -- string with query, beginning with "{{" // Postcondition: //   Returns string with URL or keyword/data, or false // Uses: //   >  PROJ //   mw.config.get // 2017-05-17 PerfektesChaos@de.wikipedia var r = false, env, got, i, ns, sign, space, suffix; got = /^({{\s*([^|}]+)\s*)[|}]/.exec( attempt ); if ( got ) { suffix = attempt.substr( got[ 1 ].length ) .replace( /\n/g, " " ); sign  = got[ 2 ].replace( /\n/g, " " ); i     = sign.indexOf( ":" ); if ( i >= 0 ) { env = mw.config.get( [ "wgNamespaceIds",                                  "wgFormattedNamespaces" ] ); if ( i ) { space = sign.substr( 0, i ) .toLowerCase .replace( /\s+/g, "_" ) .replace( /__+/g, "_" ); ns   = env.wgNamespaceIds[ space ]; if ( ! ns ) { ns = -9; }           } else { ns = 0; }           if ( ns >= 0 ) { sign = sign.substr( i + 1 ).replace( /^\s+/, "" ); sign = env.wgFormattedNamespaces[ "" + ns ] +  ":" + sign.substr( 0, 1 ) + sign.substr( 1 ); }        }         sign = sign.replace( /\s+/g, "_" ) .replace( /__+/g, "_" ) .replace( /_$/, "" ); switch ( sign.toUpperCase ) { case "ARXIV": case "DNB": case "DOI": case "ISBN": case "LCCN": case "OCLC": case "PMC": case "PMID": case "RFC": got = /^\|\s*([^|}]+)\s*[|}]/.exec( suffix ); if ( got ) { r = sign.toUpperCase + " " + got[ 1 ]; }              break; default: if ( typeof PROJ.templates ===  "object" &&                    typeof PROJ.templates[ sign ]  ===  "function" ) { r = PROJ.templates[ sign ]( suffix ); }        }   // switch sign }     return r;   };   // DESC.fold

DESC.arxiv = function ( attempt ) { // Analyse request string, presumably arXiv // Precondition: //   attempt  -- string with query // Postcondition: //   Returns object, or not // 2015-05-10 PerfektesChaos@de.wikipedia var got = /^arxiv\s*[:=|]?\s*(\S+)\s*/i.exec( attempt ), r, s;     if ( got ) { s = got[ 1 ]; r = { scheme: "arxiv", arxiv: s,               url:    "http://arxiv.org/abs/" + s,               say:    "arXiv " + s }; }     return r;   };   // DESC.arxiv

DESC.dnb = function ( attempt ) { // Analyse request string, presumably Deutsche Nationalbibliothek // Precondition: //   attempt  -- string with query // Postcondition: //   Returns object, or not // 2015-05-10 PerfektesChaos@de.wikipedia var got = /^dnb\s*[:=|]?\s*([1-9][0-9]+X?)\b/i.exec( attempt ), r, s;     if ( got ) { s = got[ 1 ]; r = { scheme: "dnb", dnb:   s,               url:    "http://d-nb.info/" + s,               say:    "DNB " + s }; }     return r;   };   // DESC.dnb

DESC.doi = function ( attempt, achieved ) { // Analyse request string, presumably DOI // Precondition: //   attempt   -- string with query //   achieved  -- number of mode // Postcondition: //   Returns object, or not // 2015-06-30 PerfektesChaos@de.wikipedia var got, i, r, s;     switch ( achieved ) { case 0: got = /^doi\s*[:=]?\s*(\S+)(?:\s.+)?$/i.exec( attempt ); break; case 2: got = /^doi:\s*(\S+)$/i.exec( attempt ); break; case 3: got = /^doi\s*\|([^|]+)(?:\|.+)?$/i.exec( attempt ); break; }  // switch achieved if ( got ) { s = got[ 1 ].replace( /^\s+/, "" ) .replace( /\s+$/, "" ); i = s.indexOf( "}}" ); if ( i >  0   &&   s.indexOf( "{", i )  < 0 ) { s = s.substr( 0, i ); }        r = { scheme: "doi", doi:   s,               say:    "doi:" + s }; if ( /^10\.[1-9]\d\d\d+\/\S+$/.test( s ) ) { r.url = "http://dx.doi.org/" + s;        } }     return r;   };   // DESC.doi

DESC.ftp = function ( attempt ) { // Analyse request string, presumably URL // Precondition: //   attempt  -- string with query // Postcondition: //   Returns object, or not // Uses: //   this //   DESC.http // 2015-05-01 PerfektesChaos@de.wikipedia return this.http( attempt ); };  // DESC.ftp

DESC.http = function ( attempt ) { // Analyse request string, presumably URL // Precondition: //   attempt  -- string with query // Postcondition: //   Returns object, or not // Uses: //   >  GUIP.caret.starter //   >< DESC.re.url // 2015-09-07 PerfektesChaos@de.wikipedia var got = /(\S+)\s?/.exec( attempt ), i, r, re, s, site, suffix; if ( got ) { if ( typeof DESC.re.url !==  "object" ) { s = "^((?:f|ht)tps?://"               + "(?:[^./]+\\.)+\\w+"                + "(?::[0-9]+)?)" + "(/.*)$";           DESC.re.url = new RegExp( s, "i" ); }        s   = got[ 1 ]; r  = { scheme: "url" }; got = DESC.re.url.exec( s ); if ( got ) { site  = got[ 1 ].toLowerCase; suffix = got[ 2 ]; i     = suffix.indexOf( "]" ); if ( i > 0 ) { suffix = suffix.substr( 0, i ); }           i = suffix.indexOf( "|" ); if ( i > 0  &&                 typeof GUIP.caret.starter  ===  "string" ) { if ( /[|=]\s*$/.test( GUIP.caret.starter ) ) { // template parameter suffix = suffix.substr( 0, i ); }           }            re  = /^([^#<]+)([#<])(.*)$/; got = re.exec( suffix ); if ( got ) { suffix = got[ 1 ]; if ( got[ 2 ] === "#" ) { r.subtle = got[ 3 ]; }           }            r.url    = site + suffix; // TODO ///////// redirect URL r.source = r.url; got     = /[.\/]?([^.\/]+\.\w+)(:[0-9]+)?$/.exec( site ); if ( got ) { r.say = got[ 1 ]; }        }      }      return r;   };   // DESC.http

DESC.https = function ( attempt ) { // Analyse request string, presumably URL // Precondition: //   attempt  -- string with query // Postcondition: //   Returns object, or not // Uses: //   this //   DESC.http // 2015-05-01 PerfektesChaos@de.wikipedia return this.http( attempt ); };  // DESC.https

DESC.isbn = function ( attempt, achieved ) { // Analyse request string, presumably ISBN // Precondition: //   attempt   -- string with query //   achieved  -- number of mode // Postcondition: //   Returns object, or not // Uses: //   .isbnLib.focus //   .isbnLib.finder // 2016-03-29 PerfektesChaos@de.wikipedia var got, i, isbnLib, r;     switch ( achieved ) { case 0: case 2: got = /^isbn\s*[:=]?\s*([-0-9]+x?.*)$/i.exec( attempt ); break; }  // switch achieved if ( got ) { r  = { scheme: "isbn", isbn:  got[ 1 ], lang:  false }; got = /^([-0-9]+x?)(?:[^-0-9x].*)?$/i.exec( r.isbn ); if ( got ) { isbnLib = CITWT.isbnLib; r.isbn = got[ 1 ].replace( /-/g, "" ); switch ( r.isbn.length ) { case 10: r.isbn = r.isbn.toUpperCase; if ( /^[0-9]+X?$/.test( r.isbn ) ) { r.lang = isbnLib.focus( r.isbn ); r.url = true; }                 break; case 13: got = /^97([89])[0-9]+$/.exec( r.isbn ); if ( got ) { if ( got[ 1 ] === "8" ) { r.lang = isbnLib.focus( r.isbn.substr( 3 ) ); } else { r.lang = isbnLib.focus( r.isbn ); }                    r.url = true; }                 break; }  // switch n            if ( r.url ) { r.url = isbnLib.finder( r.lang ); r.say = r.isbn; r.url.push( "/wiki/Special:Booksources/#" ); for ( i = 0; i < r.url.length;  i++ ) { r.url[ i ] = r.url[ i ].replace( /#/, r.isbn ); }  // for i               i = r.url.length - 1; r.url[ i ] = [ r.url[ i ], "ISBN" ]; }        } else { r.isbn = r.isbn.substr( 0, 30 ); }     }      return r;   };   // DESC.isbn

DESC.lccn = function ( attempt ) { // Analyse request string, like Library of Congress Control Number // Precondition: //   attempt  -- string with query // Postcondition: //   Returns object, or not // 2015-05-10 PerfektesChaos@de.wikipedia var got = /^lccn\s*[:=|]?\s*([-a-z/0-9]+)\b/i.exec( attempt ), r, s;     if ( got ) { s = got[ 1 ]; r = { scheme: "lccn", lccn:  s,               url:    "http://lccn.loc.gov/" + s,               say:    "LCCN " + s }; }     return r;   };   // DESC.lccn

DESC.oclc = function ( attempt ) { // Analyse request string, presumably OCLC // Precondition: //   attempt  -- string with query // Postcondition: //   Returns object, or not // 2015-05-10 PerfektesChaos@de.wikipedia var got = /^oclc\s*[:=|]?\s*([1-9][0-9]+)\b/i.exec( attempt ), r, s;     if ( got ) { s = got[ 1 ]; r = { scheme: "oclc", oclc:  s,               url:    "http://worldcat.org/oclc/" + s,               say:    "OCLC " + s }; }     return r;   };   // DESC.oclc

DESC.pmc = function ( attempt ) { // Analyse request string, presumably PMC // Precondition: //   attempt  -- string with query // Postcondition: //   Returns object, or not // 2015-05-01 PerfektesChaos@de.wikipedia var got = /^pmc\s*[:=|]?\s*([1-9][0-9]+)\b/i.exec( attempt ), r, s;     if ( got ) { s = got[ 1 ]; r = { scheme: "pmc", pmc:   s,               url:    "http://www.ncbi.nlm.nih.gov/pmc/articles/PMC" + s,              say:    "PMC " + s }; }     return r;   };   // DESC.pmc

DESC.pmid = function ( attempt, achieved ) { // Analyse request string, presumably PMID // Precondition: //   attempt   -- string with query //   achieved  -- number of mode // Postcondition: //   Returns object, or not // 2015-05-01 PerfektesChaos@de.wikipedia var got, r, s;     switch ( achieved ) { case 0: case 2: got = /^pmid\s*[:=]?\s*([1-9][0-9]+)\b/i.exec( attempt ); break; }  // switch achieved if ( got ) { s = got[ 1 ]; r = { scheme: "pmid", pmid:  s,               url:    "https://www.ncbi.nlm.nih.gov/pubmed/" + s,               say:    "PMID " + s }; }     return r;   };   // DESC.pmid

//---

GUIP.gallery = { buttonTool: "00/Button_easy_cite_%281%29.png", throbber:  "de/Ajax-loader.gif", wikiEditor: "67/WikiEditor_Cite.svg", MISSING:   "45/%D0%95%D0%B3%D0%B3%D0%BE%D0%B3.svg" };  // 2015-05-01 PerfektesChaos@de.wikipedia GUIP.$panel = false;

GUIP.factory = function { // Equip page GUI with panel // Uses: //   >  .type //   >  GUIP.btn.show //   >  .vsn //   >  GUIP.$textarea //    < GUIP.live //    < GUIP.oneof //    < GUIP.$panel //    < GUIP.$button //    < GUIP.input.$text //    < GUIP.push.$bar //   GUIP.gadget.factory{)      //    GUIP.fiat      //    (TASK.fiat)      // 2015-06-16 PerfektesChaos@de.wikipedia      var collection = [ "empty",                         "invalid",                         "throbber",                         "translated",                         "unanswered",                         "yippie" ],          i, $editarea;      GUIP.live   = false;      GUIP.oneof  = { };      GUIP.$panel = $( " " );      GUIP.$panel.attr( { "id":  CITWT.type } );      GUIP.$panel.css( { "border":        "#808080 2px solid", "margin-top":   "0.5em", "margin-bottom": "0.5em", "overflow":     "auto", "padding":      "5px" } );      GUIP.$panel.hide;      GUIP.$button = $( " " );      GUIP.$button.attr( { "id":    CITWT.type + "-button", "title": CITWT.vsn } );     GUIP.$button.click( TASK.fiat );      GUIP.$button.css( { "float":        "left", "margin-right": "2em" } );     GUIP.$button.text( GUIP.btn.show );      GUIP.$panel.append( GUIP.$button );      GUIP.gadget.factory;      for ( i = 0;  i < collection.length;  i++ ) {         GUIP.fiat( collection[ i ] );      }   // for i      GUIP.input.$text = false;      GUIP.push.$bar   = false;      $editarea        = $( "#edithelper-panel");   // user:Schnark      if ( ! $editarea.length ) {        if ( $( "#syntaxhighlight").length ) {            // hack Schnark/js/syntaxhighlight.js            $editarea = GUIP.$textarea.parent;         }         if ( ! $editarea.length ) {           $editarea = GUIP.$textarea;         }      }      $editarea.before( GUIP.$panel );   };   // GUIP.factory

GUIP.fiat = function ( achieve ) { // Create element // Precondition: //   achieve  -- keyword //               * empty //               * invalid //               * throbber //               * translated //               * unanswered //               * yippie // Uses: //   >  .type //   >  GUIP.oneof //   >  GUIP.$panel //   GUIP.file //   I18N.fair // 2015-05-25 PerfektesChaos@de.wikipedia var $elem  = $( " " ), colours = { empty:     "808080", invalid:   "FF0000", translated: "208020", unanswered: "FF0000", yippie:    "40C040" }, $img, $span; $elem.attr( { id: CITWT.type + "_" + achieve } ); $elem.css( { "vertical-align": "top" } ); if ( achieve === "throbber" ) { $img = $( " " ); $img.attr( { src:   GUIP.file( "throbber" ),                      id:     CITWT.type + "_throbber_ajax",                      height: "32",                      alt:    "Ajax" } ); $elem.append( $img ); } else { $span = $( " " ); $span.css( { "color":        "#" + colours[ achieve ],                      "font-size":     "200%",                      "font-weight":   "bold",                      "margin-right":  "1em" } ); $span.text( I18N.fair( "msg" + achieve.substr( 0, 1 ).toUpperCase + achieve.substr( 1 ), true ) ); $elem.append( $span ); }     if ( "|invalid|throbber|translated|".indexOf( achieve )  >  0 ) { $span = $( " " ); $span.attr( { id: CITWT.type + "_" + achieve + "_text" } ); $span.css( { "margin-left": "1em" } ); if ( achieve === "invalid" ) { $span.css( { "color":      "#FF0000",                         "font-weight": "bold" } ); }        $elem.append( $span ); } else if ( achieve === "unanswered" ) { $elem.css( { "letter-spacing": "0.13em" } ); }     $elem.hide; GUIP.oneof[ "$" + achieve ] = $elem; GUIP.$panel.append( $elem ); };  // GUIP.fiat

GUIP.file = function ( access ) { // Retrieve image URL // Precondition: //   access  -- keyword // Postcondition: //   Returns any image access string // Uses: //   >  GUIP.gallery // 2015-05-01 PerfektesChaos@de.wikipedia var r = GUIP.gallery[ access ]; if ( ! r ) { r = GUIP.gallery.MISSING; }     return "//upload.wikimedia.org/wikipedia/commons/" + r.substr(0, 1)  +  "/"  +  r;   };   // GUIP.file

GUIP.fire = function { // Start page GUI equipping // Uses: //   $      //    (GUIP.first) // Remark: Used as event handler -- 'this' is not GUIP // 2015-05-12 PerfektesChaos@de.wikipedia $( GUIP.first ); };  // GUIP.fire

GUIP.first = function { // Equip page GUI with DOM elements // Precondition: //   DOM ready //   mediawiki modules and user options/config have been loaded // Uses: //   >  GUIP.$panel //   >  .bibRecord //   >  .leading   (user defined) //    < GUIP.$textarea //    < GUIP.submit //    < GUIP.btn.show //   I18N.fair //   GUIP.factory //   GUIP.btn.fire //   mw.loader.using //   GUIP.flat //   mw.loader.load //   (.fire); // Remark: Used as event handler -- 'this' is not GUIP // 2017-02-20 PerfektesChaos@de.wikipedia var require; GUIP.$textarea = $( "#wpTextbox1" ); if ( GUIP.$textarea.length &&  ! GUIP.$panel ) { GUIP.submit  = false; GUIP.btn.show = I18N.fair( "Citoid", true ); GUIP.factory; GUIP.btn.fire; require = [ "jquery.textSelection", "mediawiki.api" ]; if ( CITWT.bibRecord && CITWT.bibRecord.launch ) { mw.loader.using( require, CITWT.fire ); } else { if ( typeof CITWT.leading ===  "boolean"                 &&     CITWT.leading ) { GUIP.flat( false ); }           mw.loader.load( require ); }     }   };   // GUIP.first

GUIP.flat = function ( access, $add ) { // Disable main button, rise cleared panel; show message // Precondition: //   access  -- keyword, if any //              -- false: do not discard text field //   $add    -- additional jQuery object (second call only) // Uses: //   >  GUIP.$button //   >  GUIP.oneof //   >  .vsn //   >  GUIP.$panel //    < GUIP.live //   GUIP.input.free //   GUIP.input.fire // 2015-06-16 PerfektesChaos@de.wikipedia var leave, s, $child, $elem; if ( access ) { if ( access !== true ) { $elem = GUIP.oneof[ "$" + access ]; $child = $elem.children.eq( 1 ); if ( $child.length ) { $child.empty; }           s = "|empty|invalid|unanswered|"; if ( s.indexOf( access ) >  0 ) { GUIP.input.free; }        }      } else if ( access !== false ) { GUIP.input.fire( true ); }     if ( $add ) { if ( $child ) { $child.append( $add ); }     } else { leave = ( access === "throbber" ); GUIP.$button.attr( { "disabled": leave,                             "title":    CITWT.vsn } ); for ( s in GUIP.oneof ) { GUIP.oneof[ s ].hide; }  // for $elem in .oneof GUIP.push.flip( 0 ); GUIP.$panel.show; GUIP.live = true; if ( $elem ) { $elem.show; }     }   };   // GUIP.flat

GUIP.$flip = function ( $assembly, add, assign ) { // Create sequence of external links // Precondition: //   $assembly  -- or nothing //   add        -- add Array[2] //                     -- [0]  URL string //                     -- [1]  title string //   assign     -- serial number // Postcondition: //   Returns extended $assembly // Uses: //    < GUIP.$info // 2015-05-01 PerfektesChaos@de.wikipedia var $a = $( "" ), $r; if ( $assembly ) { $r = $assembly; } else { $r        = $( " " ); GUIP.$info = false; }     $a.attr( { href:    add[ 0 ],                 target:  "CITWT" + assign } ); $a.css( { "margin-right": "0.75em" } ); $a.text( add[ 1 ] ); $r.append( $a ); return $r; };  // GUIP.$flip

GUIP.$flipper = function ( $assembly, add ) { // Add identifier element to query info // Precondition: //   $assembly  -- //   add        -- displayed string // Uses: //    < GUIP.$info // 2015-05-01 PerfektesChaos@de.wikipedia GUIP.$info = $( " " ); GUIP.$info.css( { "margin-right": "0.75em" } ); GUIP.$info.text( add ); $assembly.append( GUIP.$info ); };  // GUIP.$flipper

GUIP.flop = function ( about ) { // Show error message on invalid data format // Precondition: //   about  -- object with details //             -- about.scheme          data type //             -- about[about.scheme]   data content // Uses: //   I18N.fair //   GUIP.flat // 2015-05-01 PerfektesChaos@de.wikipedia var story = I18N.fair( "invalid" ), $msg = $( " " ), $span = $( " " ), $code; GUIP.flat( "invalid" ); if ( typeof about.scheme ===  "string" ) { story = about.scheme.toUpperCase + " &#8211; " + story; if ( typeof about[ about.scheme ] ===  "string" ) { $code = $( " " ); $code.css( { "margin-left": "1.5em" } ); $code.text( about[ about.scheme ] ); }     }      $span.html( story ); $msg.append( $span ); if ( $code ) { $msg.append( $code ); }     GUIP.flat( "invalid", $msg ); };  // GUIP.flop

GUIP.btn.fire = function { // Equip page GUI with general button // Uses: //   this //   >  GUIP.opts //   >< GUIP.submit //   mw.loader.using //   GUIP.btn.wikEd //   GUIP.btn.toolbar //   GUIP.btn.portlet //   (GUIP.btn.wikiEditor) // 2018-08-24 PerfektesChaos@de.wikipedia if ( ! this.wikEd ) { if ( GUIP.opts.usebetatoolbar ) { GUIP.submit = "wikiEditor ... (loading)"; mw.loader.using( [ "ext.wikiEditor" ],                            this.wikiEditor ); } else if ( GUIP.opts.showtoolbar ) { this.toolbar; }     }      if ( ! GUIP.submit ) { this.portlet; }  };   // GUIP.btn.fire

GUIP.btn.portlet = function { // Equip wikiEditor toolbar with button // Uses: //   >  .type //   >  GUIP.btn.show //    < GUIP.submit //   mw.util.addPortletLink //   (.fire) // 2015-05-12 PerfektesChaos@de.wikipedia var portlet =  mw.util.addPortletLink( "p-tb",                                              "#",                                              GUIP.btn.show,                                              "t-" + CITWT.type ); $( portlet ).click( CITWT.fire ); GUIP.submit = "portlet-tb"; };  // GUIP.btn.portlet

GUIP.btn.toolbar = function { // Equip classic toolbar with button // Uses: //   >  .type //   >  GUIP.btn.show //    < GUIP.submit //   GUIP.file //   (.fire) // 2015-05-12 PerfektesChaos@de.wikipedia var $toolbar = $( "#toolbar" ), $img; if ( $toolbar.length ) { $img = $( " " ); $img.attr( { "src":   GUIP.file( "buttonTool" ),                      "id":     CITWT.type + "-toolbar",                      "height": "22",                      "width":  "23",                      "alt":    GUIP.btn.show,                      "title":  GUIP.btn.show } ); $img.click( CITWT.fire ); $toolbar.prepend( $img ); GUIP.submit = "toolbar"; }  };   // GUIP.btn.toolbar

GUIP.btn.wikEd = function { // Equip wikEd GUI with button // Postcondition: //   Returns something, if equipped for wikEd // Uses: //   >  wikEd //   >  .type //   >  GUIP.btn.show //    < GUIP.submit //    < EDIT.wikEd //   mw.user.options.get //   GUIP.file // 2018-07-21 PerfektesChaos@de.wikipedia var id = 746, cnf; if ( mw.user.options.get( "gadget-wikEd" )          ||  ( typeof window.wikEd  ===  "object" &&    window.wikEd ) ) { if ( typeof window.wikEd !==  "object" ) { window.wikEd = { config: { }  }; }        EDIT.wikEd = window.wikEd; if ( typeof EDIT.wikEd.config !==  "object" ) { EDIT.wikEd.config = { button:   { }, buttonBar: { } }; }        cnf = EDIT.wikEd.config; if ( typeof cnf.button !==  "object" ) { cnf.button = { }; }        cnf.button[ id ] = [ "wikEdCitoid", "wikEdButton", GUIP.btn.show, GUIP.file( "buttonTool" ), "16", "16",                             "DIV", "window.mediaWiki.libs." + CITWT.type + ".fire;" ]; if ( typeof cnf.buttonBar !==  "object" ) { cnf.buttonBar = { }; }        if ( typeof cnf.buttonBar.custom1  !==  "object" ) { cnf.buttonBar.custom1 = [ "wikEdButtonBarCustom1", "wikEdButtonBarCustom1", "wikEdButtonsCustom1", "wikEdButtonsCustom1", 44,                                     GUIP.btn.show, [ ] ];        }         cnf.buttonBar.custom1[ 6 ].push( id ); if ( typeof EDIT.wikEd.disabled        ===  "boolean"    &&              typeof EDIT.wikEd.highlightSyntax  ===  "boolean"    &&              typeof EDIT.wikEd.turnedOn         ===  "boolean"    &&              typeof EDIT.wikEd.useWikEd         ===  "boolean"              &&     EDIT.wikEd.useWikEd ) { GUIP.submit = "wikEd"; }     }      return GUIP.submit; };  // GUIP.btn.wikEd

GUIP.btn.wikiEditor = function { // Equip wikiEditor toolbar with button // Precondition: //   ext.wikiEditor.toolbar has been loaded // Uses: //   >  GUIP.$textarea //   >  .type //   >  GUIP.btn.show //    < GUIP.submit //   GUIP.file //   (.fire) // 2015-05-12 PerfektesChaos@de.wikipedia GUIP.$textarea.wikiEditor( "addToToolbar",                   { "section": "main",                      "group":   "format",                      "tools":   { citoid:                                     { type:   "button",                                       label:  GUIP.btn.show,                                       icon:   GUIP.file( "wikiEditor" ),                                       action: { type:    "callback",                                                 execute: CITWT.fire                                               }                                     }                                 }                    } ); GUIP.submit = "wikiEditor"; };  // GUIP.btn.wikiEditor

GUIP.caret.fetch = function ( after ) { // Get selection // Precondition: //   after  -- callback function // Postcondition: //   selection assigned // Uses: //   this //    < GUIP.caret.min //    < GUIP.caret.max //    < GUIP.caret.selection //    < GUIP.caret.starter //    < GUIP.caret.further //   GUIP.caret.wikEd //   mw.loader.using //   (GUIP.caret.find) // 2015-05-19 PerfektesChaos@de.wikipedia this.min      = -2; this.max      = -3; this.selection = false; this.starter  = false; if ( this.wikEd ) { after( "wikEd" ); } else { this.further = after; mw.loader.using( [ "jquery.textSelection" ],                         this.find ); }  };   // GUIP.caret.fetch

GUIP.caret.fill = function ( apply ) { // Insert/replace string at selection // Precondition: //   apply  -- string to be added // Postcondition: //   edited text modified // Uses: //   this //    < GUIP.caret.shift //   GUIP.caret.fetch //   (GUIP.caret.filler) // 2015-05-01 PerfektesChaos@de.wikipedia this.shift = apply; this.fetch( this.filler ); };  // GUIP.caret.fill

GUIP.caret.filler = function ( alien ) { // Insert/replace string at selection // Precondition: //   alien  -- string with name of editor, or false // Postcondition: //   edited text modified // Uses: //   >  GUIP.caret.shift //   >  GUIP.caret.story //   >  GUIP.caret.min //   >  GUIP.caret.max //   >  GUIP.$textarea //   >  EDIT.codeMirror //   >  EDIT.wikEd // Remark: Used as event handler -- 'this' is not GUIP.caret // 2018-07-21 PerfektesChaos@de.wikipedia var shift, start, story; if ( GUIP.caret.max >= 0 ) { shift = GUIP.caret.shift; story = GUIP.caret.story; start = story.substr( 0, GUIP.caret.min ); story = story.substr( GUIP.caret.max ); if ( shift.substr( 0, 4 ) === "<ref" ) { start = start.replace( /\s+$/, "" ); } else if ( shift.substr( 0, 1 ) === "\n"  &&                     /\n$/.test( start ) ) { shift = shift.substr( 1 ); }        if ( story.substr( 0, 1 ) === "\n"   &&              /\n$/.test( shift ) ) { story = story.substr( 1 ); }        story = start + shift + story; GUIP.$textarea.val( story ); if ( EDIT.codeMirror && EDIT.codeMirror.liveCITWT ) { EDIT.codeMirror.doc.setValue( story ); } else if ( alien === "wikEd" ) { EDIT.wikEd.UpdateFrame; }     }   };   // GUIP.caret.filler

GUIP.caret.find = function { // Get selection in regular textarea, but perhaps CodeMirror // Precondition: //   jquery.textSelection has been loaded // Postcondition: //   selection assigned // Uses: //   >  CodeMirror //   >  GUIP.$textarea //   >  GUIP.caret.further //   >< EDIT.codeMirror //    < GUIP.caret.story //    < GUIP.caret.min //    < GUIP.caret.max //    < GUIP.caret.selection //    < GUIP.caret.starter // Remark: Used as event handler -- 'this' is not GUIP.caret // 2018-07-21 PerfektesChaos@de.wikipedia var rg, uo; if ( ! EDIT.codeMirror  &&           typeof window.CodeMirror  ===  "function"   &&           typeof window.CodeMirror.doc  ===  "object"           &&     window.CodeMirror.doc ) { EDIT.codeMirror = window.CodeMirror; }     if ( EDIT.codeMirror ) { uo = mw.user.options.get( "usecodemirror" ); EDIT.codeMirror.liveCITWT = ( typeof uo ===  "number"                                       &&     uo > 0 ); if ( EDIT.codeMirror.liveCITWT ) { GUIP.$textarea.val( EDIT.codeMirror.doc.getValue ); }     }      rg = GUIP.$textarea.textSelection( "getCaretPosition",                                         { "startAndEnd": true } ); GUIP.caret.story = GUIP.$textarea.val; if ( rg[0] <= rg[1] ) { GUIP.caret.min      = rg[0]; GUIP.caret.max      = rg[1]; GUIP.caret.selection = GUIP.caret.story.substr( rg[0] ); GUIP.caret.starter  = GUIP.caret.story.substr( 0, rg[0] ); }     GUIP.caret.further; };  // GUIP.caret.find

GUIP.caret.wikEd = function { // Get wikEd selection // Precondition: //   assign  -- object // Postcondition: //   Returns true, if selection assigned // Uses: //   this //   >  EDIT.wikEd //   >  GUIP.$textarea //    < GUIP.caret.start //    < GUIP.caret.stop //    < GUIP.caret.min //    < GUIP.caret.max //    < GUIP.caret.story //    < GUIP.caret.selection //    < GUIP.caret.starter //   (GUIP.caret.wikEdEnclose) // 2018-01-21 PerfektesChaos@de.wikipedia var r;     if ( EDIT.wikEd &&           ! EDIT.wikEd.disabled  &&           EDIT.wikEd.useWikEd    &&           EDIT.wikEd.turnedOn    &&           EDIT.wikEd.highlightSyntax ) { this.start = "##\f#citoid_marker_begin##\f#"; this.stop = "##\f#citoid_marker_end##\f#"; EDIT.wikEd.EditButton( null,                               null,                                null,                                this.wikEdEnclose ); EDIT.wikEd.UpdateTextarea; r        = GUIP.$textarea.val; this.min = r.search( this.start ); r        = r.replace( this.start, "" ); this.max = r.search( this.stop ) - 1; r        = r.replace( this.stop, "" ); GUIP.$textarea.val( r ); this.story    = r;         this.selection = this.story.substr( this.min ); this.starter  = this.story.substr( 0, this.min ); EDIT.wikEd.UpdateFrame; r = true; }     return r;   };   // GUIP.caret.wikEd

GUIP.caret.wikEdEnclose = function ( assign ) { // Mark wikEd selection region // Precondition: //   assign  -- object // Postcondition: //   assign got further properties // Uses: //   >  EDIT.wikEd //   >  GUIP.caret.start //   >  GUIP.caret.stop // Remark: Used as event handler -- 'this' is not GUIP.caret // 2018-07-21 PerfektesChaos@de.wikipedia EDIT.wikEd.GetText( assign, "selection, cursor" ); if ( assign.selection.plain === "" ) { assign.sel = EDIT.wikEd.GetSelection; if ( assign.sel.anchorNode.previousSibling ) { assign.changed = assign.cursor; } else { EDIT.wikEd.GetText( assign, "whole" ); assign.changed = assign.whole; }     } else { assign.changed = assign.selection; }     assign.changed.plain = GUIP.caret.start + assign.changed.plain + GUIP.caret.stop; };  // GUIP.caret.wikEdEnclose

GUIP.gadget.factory = function { // Create gadget bar // Uses: //   this //   >  GUIP.$panel //    < GUIP.gadget.$bar // 2015-05-01 PerfektesChaos@de.wikipedia var buttons = [ "hide", "help", "hear", "home" ], i;     this.$bar = $( " " ); this.$bar.attr( { "id": CITWT.type + "-bar" } ); this.$bar.css( { "float": "right" } ); for ( i = 0; i < 4;  i++ ) { this.$fiat( buttons[ i ] ); }  // for i      GUIP.$panel.append( this.$bar ); };  // GUIP.gadget.factory

GUIP.gadget.$fiat = function ( assign ) { // Create a single gadget button and add to bar // Precondition: //   assign  -- string as identifier // Uses: //   this //   >  GUIP.gadget.$bar // 2015-05-12 PerfektesChaos@de.wikipedia var colours = { hear: "000000", help: "208020", hide: "FF0000", home: "0000FF" }, suffix = assign.substr( 0, 1 ).toUpperCase + assign.substr( 1 ), $btn   = $( " " ), $span  = $( " " ); $btn.attr( { "id":   CITWT.type + "-button-" + assign,                   "title": I18N.fair( "tip" + suffix,  true )  } ); $btn.click( this[ assign ] ); $btn.css( { "float":      "right",                  "margin-left": "2px" } ); $span.css( { "color":      "#" + colours[ assign ],                   "font-weight": "bold" } ); $span.html( I18N.fair( "gadget" + suffix, true ) ); $btn.append( $span ); this.$bar.append( $btn ); };  // GUIP.gadget.$fiat

GUIP.gadget.hear = function ( event ) { // Gadget button for input field has been clicked // Precondition: //   event  -- jQuery event object // Uses: //   UTIL.fullstop //   GUIP.input.fire // Remark: Used as event handler -- 'this' is not GUIP.gadget // 2015-05-12 PerfektesChaos@de.wikipedia UTIL.fullstop( event ); GUIP.input.fire( false ); GUIP.input.$text.show; };  // GUIP.gadget.hear

GUIP.gadget.help = function ( event ) { // Gadget button for help page has been clicked // Precondition: //   event  -- jQuery event object // Uses: //   >  HELP.support //   UTIL.fullstop //   I18N.fair //   mw.util.getUrl // Remark: Used as event handler -- 'this' is not GUIP.gadget // 2018-07-20 PerfektesChaos@de.wikipedia var support = "https://" +  I18N.fair( "helpSite", true ) + ".wikipedia.org" + mw.util.getUrl( HELP.support ); UTIL.fullstop( event ); window.open( support, "citWThelp" ); };  // GUIP.gadget.help

GUIP.gadget.hide = function ( event ) { // Gadget button has been clicked // Precondition: //   event  -- jQuery event object // Uses: //   >  GUIP.$panel //    < GUIP.live //   GUIP.gadget.home // Remark: Used as event handler -- 'this' is not GUIP.gadget // 2015-06-16 PerfektesChaos@de.wikipedia GUIP.gadget.home( event ); GUIP.$panel.hide; GUIP.live = false; };  // GUIP.gadget.hide

GUIP.gadget.home = function ( event ) { // Gadget button has been clicked // Precondition: //   event  -- jQuery event object // Uses: //   UTIL.fullstop //   GUIP.flat // Remark: Used as event handler -- 'this' is not GUIP.gadget // 2015-05-12 PerfektesChaos@de.wikipedia UTIL.fullstop( event ); GUIP.flat; };  // GUIP.gadget.home

GUIP.input.filler = function ( assign ) { // Retrieve text input content, disable field with content, or hide // Precondition: //   assign  -- string to be assigned to the invisible field // Postcondition: //   Returns non-empty input text, or false //   Hide empty field, disable field with content // Uses: //   this //   >  GUIP.input.$text //   >  GUIP.input.live //   GUIP.input.fire // 2015-05-01 PerfektesChaos@de.wikipedia var r;     if ( GUIP.input.$text ) { r = this.$text.val .replace( /^\s+/, "" ) .replace( /\s+$/, "" ) .replace( /\s+ /, " " ); this.$text.val( r ); if ( ! this.live ) { if ( assign ) { this.$text.val( assign ); }           r = false; } else if ( r ) { this.$text.attr( { "disabled": true } ); } else { this.fire( true ); r = false; }     }      return r;   };   // GUIP.input.filler

GUIP.input.fed = function ( event ) { // Keypress event on input field // Precondition: //   event  -- jQuery event object // Uses: //   >  GUIP.input.live //   >  GUIP.input.$text //   CITWT.fire // Remark: Used as event handler -- 'this' is not GUIP.input // 2015-06-16 PerfektesChaos@de.wikipedia if ( ( event.which === 10 ||  event.which === 13 )           &&   GUIP.input.live           &&   GUIP.input.$text.is( ":focus" ) ) { CITWT.fire( event ); }  };   // GUIP.input.fed

GUIP.input.fire = function ( abort ) { // Set or toggle input field visibility // Precondition: //   abort  -- true: unconditionally vanishing // Uses: //   >  .type //   >  GUIP.$panel //   >< GUIP.input.$text //   >< GUIP.input.live //   GUIP.flat //   GUIP.input.free //   GUIP.input.filler //   (GUIP.input.fed) // Remark: Used as event handler -- 'this' is not GUIP.input // 2015-05-25 PerfektesChaos@de.wikipedia if ( abort ) { GUIP.input.live = false; } else { GUIP.input.live = ( ! GUIP.input.live ); }     if ( GUIP.input.live ) { if ( ! GUIP.input.$text ) { GUIP.input.$text = $( " " ); GUIP.input.$text.addClass( "mw-ui-input NOIME" ); GUIP.input.$text.attr( { id:  CITWT.type + "_text_input",                                     size: 40,                                     type: "text" } ); GUIP.$panel.append( GUIP.input.$text ); }        GUIP.flat( false ); GUIP.input.free; GUIP.input.$text.show; GUIP.input.$text.focus; GUIP.input.$text.keypress( GUIP.input.fed ); } else if ( GUIP.input.$text ) { if ( abort === true ) { GUIP.input.$text.hide; }        if ( abort !== true ) { GUIP.input.filler; }     }   };   // GUIP.input.fire

GUIP.input.free = function { // Enable text input // Uses: //   this //   >  GUIP.input.live //   >  GUIP.input.$text // 2015-05-25 PerfektesChaos@de.wikipedia if ( this.live && this.$text ) { this.$text.attr( { "disabled": false } ); }  };   // GUIP.input.free

GUIP.push.$fiat = function ( assign ) { // Create a single result push button and add to bar // Precondition: //   assign  -- string as identifier // Uses: //   this //   >  GUIP.push.$bar // 2015-05-01 PerfektesChaos@de.wikipedia var s    = "$" + assign, $span = $( " " ), $btn; this[ s ] = $( " " ); $btn     = this[ s ]; $btn.attr( { "id": CITWT.type + "-push-" + assign } ); $btn.click( this[ assign ] ); $btn.css( { "float":      "right",                  "margin-left": "1em" } ); $span.css( { "white-space": "nowrap" } ); $span.html( I18N.fair( assign, true ) ); $btn.append( $span ); if ( assign === "bibSection" ) { $btn.hide; }     this.$bar.append( $btn ); };  // GUIP.push.$fiat

GUIP.push.fired = function ( event, action ) { // Insertion button has been clicked // Precondition: //   event   -- jQuery event object //   action  -- string as insertion format identifier // Uses: //   UTIL.fullstop //   GUIP.push.flip //   TASK.fruit // 2015-05-12 PerfektesChaos@de.wikipedia UTIL.fullstop( event ); this.flip( 0 ); TASK.fruit( action ); };  // GUIP.push.fired

GUIP.push.flip = function ( action ) { // Create or hide result insertion push bar // Precondition: //   action  -- number: 0, 3, 4 // Uses: //   this //   >  GUIP.$panel //   >  GUIP.push.$bibSection //   >< GUIP.push.$bar //   GUIP.input.fire //   GUIP.push.$fiat // 2015-05-01 PerfektesChaos@de.wikipedia var btns, i;     if ( action ) { GUIP.input.fire( true ); if ( ! this.$bar ) { btns = [ "references", "bibSection", "refref", "compact" ]; this.$bar = $( " " ); this.$bar.css( { "white-space": "nowrap" } ); this.$bar.attr( { "id": CITWT.type + "-push" } ); for ( i = 0; i < 4;  i++ ) { this.$fiat( btns[ i ] ); }  // for i            this.$references.css( { "margin-right": "3em" } ); GUIP.$panel.append( this.$bar ); }        if ( action === 3 ) { this.$bibSection.hide; } else { this.$bibSection.show; }        this.$bar.show; } else if ( this.$bar ) { this.$bar.hide; }  };   // GUIP.push.flip

GUIP.push.bibSection = function ( event ) { // Button for insertion at bibSection has been clicked // Precondition: //   event  -- jQuery event object // Uses: //   GUIP.push.fired // Remark: Used as event handler -- 'this' is not GUIP.push // 2015-05-01 PerfektesChaos@de.wikipedia GUIP.push.fired( event, "bibSection" ); };  // GUIP.push.bibSection

GUIP.push.compact = function ( event ) { // Button for insertion at compact has been clicked // Precondition: //   event  -- jQuery event object // Uses: //   GUIP.push.fired // Remark: Used as event handler -- 'this' is not GUIP.push // 2015-05-01 PerfektesChaos@de.wikipedia GUIP.push.fired( event, "compact" ); };  // GUIP.push.compact

GUIP.push.references = function ( event ) { // Button for insertion at has been clicked // Precondition: //   event  -- jQuery event object // Uses: //   GUIP.push.fired // Remark: Used as event handler -- 'this' is not GUIP.push // 2015-05-01 PerfektesChaos@de.wikipedia GUIP.push.fired( event, "references" ); };  // GUIP.push.references

GUIP.push.refref = function ( event ) { // Button for insertion at has been clicked // Precondition: //   event  -- jQuery event object // Uses: //   GUIP.push.fired // Remark: Used as event handler -- 'this' is not GUIP.push // 2015-05-01 PerfektesChaos@de.wikipedia GUIP.push.fired( event, "refref" ); };  // GUIP.push.refref

//---

I18N.texts = { bibSection:   { de: "== Literatur ==" }, Citoid:       { en: "Citoid" }, compact:      { en: "compact", de: "kompakt" }, gadgetHear:   { en: "_" }, gadgetHelp:   { en: "?" },     gadgetHide:    { en: "X" }, gadgetHome:   { en: "0" }, helpSite:     { en: "en", de: "de" }, invalid:      { en: "Invalid data:", de: "Datenformat nicht erkannt" }, msgEmpty:     { en: "???" },     msgInvalid:    { en: "!?!?!" },     msgTranslated: { en: "*" }, msgUnanswered: { en: ":-(" },     msgYippie:     { en: ":-)" }, myButtons:    { en: "My buttons", de: "Meine Buttons" }, references:   { en: "&lt;references>" }, refref:       { en: "&lt;ref>&lt;/ref>" }, tipHear:      { en: "input field", de: "Eingabefeld" }, tipHelp:      { en: "help page", de: "Hilfeseite" }, tipHide:      { en: "hide box", de: "Citoid-Box ausblenden" }, tipHome:      { en: "abort requests, clear box", de: "Anfragen abbrechen, Citoid-Box leeren" } };  // 2015-05-01 PerfektesChaos@de.wikipedia

I18N.translate = { // fallback languages "als" :      "de", "bar" :      "de", "dsb" :      "de", "frr" :      "de", "gsw" :      "de", "hsb" :      "de", "ksh" :      "de", "lb" :       "de", "nds" :      "de", "pdc" :      "de", "pdt" :      "de", "pfl" :      "de", "sli" :      "de", "stq" :      "de", "vmf" :      "de" };

I18N.facility = function ( available ) { // Localize in user language, GUI only // Precondition: //   available  -- translation object // Postcondition: //   Returns string, or undefined // Uses: //   >  I18N.userLang //   >  I18N.translate // 2015-05-01 PerfektesChaos@de.wikipedia var slang = I18N.userLang, i, r;     if ( typeof available[ slang ]  ===  "string" ) { r = available[ slang ]; } else { i = slang.indexOf( "-", 2 ); if ( i > 0 ) { slang = slang.substr( 0, i ); if ( typeof available[ slang ] ===  "string" ) { r = available[ slang ]; }        }      }      if ( ! r ) { if ( typeof I18N.translate[ slang ] ===  "string" ) { slang = I18N.translate[ slang ]; if ( typeof available[ slang ] ===  "string" ) { r = available[ slang ]; }        }         if ( ! r ) { r = available.en; }     }      return r;   };   // I18N.facility

I18N.fair = function ( access, adapt, alter ) { // Localization // Precondition: //   access  -- configuration keyword //   adapt   -- false, if project (language) dependant //              else user language dependant //   alter   -- default string (en) // Postcondition: //   Returns value, or keyword 'access' // Uses: //   >  I18N.texts //   >  .core.site //   >  I18N.contentLang //   I18N.facility // 2015-05-01 PerfektesChaos@de.wikipedia var el = I18N.texts[ access ], r = ( alter ? alter : access ), say; if ( el ) { if ( adapt ) { say = I18N.facility( el ); if ( say ) { r = say; } else if ( typeof alter !==  "string" ) { r = "???" + access + "???"; }        } else { if ( typeof el[ CITWT.core.site ] ===  "string" ) { r = el[ CITWT.core.site ]; } else { if ( typeof el[ I18N.contentLang ] ===  "string" ) { r = el[ I18N.contentLang ]; }           }         }      } else if ( adapt ) { r = "???" + access + "???"; }     return r;   };   // I18N.fair

I18N.fire = function { // Initialize internationalization // Uses: //   >  .l10n //   >< I18N.texts //    < I18N.contentLang //    < I18N.wgUserLanguage //   mw.config.get // 2015-05-31 PerfektesChaos@de.wikipedia var env = mw.config.get( [ "wgContentLanguage",                                "wgUserLanguage" ] ); I18N.contentLang = env.wgContentLanguage; I18N.userLang   = env.wgUserLanguage.toLowerCase; if ( typeof CITWT.l10n ===  "object"  &&  CITWT.l10n ) { $.extend( true, I18N.texts, CITWT.l10n ); }  };   // I18N.fire

//---

PREGO.feed = function { // Provide PREGO // Uses: //   >  PREGO.signature //   >  PREGO.site //   >  PREGO.store //   >  PREGO.sub //   >  PREGO.maxage //   mw.loader.getState //   mw.loader.state //   REPOS.fire // 2018-09-03 PerfektesChaos@de.wikipedia var sign = "ext.gadget." + PREGO.signature, rls; if ( ! mw.loader.getState( sign ) ) { rls = { }; rls[ sign ] = "loading"; mw.loader.state( rls ); REPOS.fire( PREGO.site,                    PREGO.store + PREGO.signature + PREGO.sub,                     false,                     { action: "raw",                       ctype:  "text/javascript",                       bcache: 1,                       maxage: PREGO.maxage } ); }  };   // PREGO.feed

//---

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

//---

TASK.fiat = function ( event ) { // Panel launch button has been clicked // Precondition: //   event  -- jQuery event object // Uses: //    < TASK.template //   GUIP.input.filler //   UTIL.fullstop //   GUIP.input.fire //   TASK.found //   GUIP.caret.fetch //   GUIP.flat //   (TASK.found) // Remark: Used as event handler -- 'this' is not TASK // 2015-06-16 PerfektesChaos@de.wikipedia var listen = true, suggest; if ( event ) { listen = GUIP.live &&  GUIP.$button.is( ":focus" ); if ( listen ) { UTIL.fullstop( event ); }     }      if ( listen ) { suggest = GUIP.input.filler; TASK.template = false; if ( suggest ) { TASK.found( suggest ); } else { GUIP.flat( true ); GUIP.caret.fetch( TASK.found ); }     }   };   // TASK.fiat

TASK.filter = function { // Process completed result of queries // Uses: //   >  TASK.query //   >  APIC.queries //   >  PROJ //   >  .bibRecord //    < TASK.template //   .opus.fire //   .(project).fire //   GUIP.caret.fill //   GUIP.flat //   GUIP.push.flip // Remark: Used as event handler -- 'this' is not TASK // 2017-06-04 PerfektesChaos@de.wikipedia var mode, result; if ( ! APIC.missing ) { result = CITWT.opus.fire( TASK.query, APIC.queries ); }     TASK.template = PROJ.fire( result ); switch ( typeof TASK.template ) { case "object": mode = ( TASK.template[ 0 ][ 2 ] ? 4 : 3 ); break; case "string": if ( CITWT.bibRecord &&  CITWT.bibRecord.launch ) { GUIP.caret.fill( TASK.template ); TASK.template = false; GUIP.flat( "translated", TASK.query.$links ); } else { mode = 3; }           break; default: TASK.template = false; }  // switch typeof array if ( mode ) { GUIP.push.flip( mode ); }  };   // TASK.filter

TASK.fire = function { // Initialize page // Precondition: //   mediawiki modules and user options/config have been loaded // Uses: //   >  .core.site //   >  mw.user.options //    < PROJ //    < GUIP.opts //   I18N.fire //   mw.user.options.get //   mw.loader.using //   BOOK.fire //   (BOOK.fire) // 2016-03-21 PerfektesChaos@de.wikipedia if ( typeof CITWT[ CITWT.core.site ] ===  "object" ) { PROJ = CITWT[ CITWT.core.site ]; if ( PROJ ) { I18N.fire; GUIP.opts = mw.user.options.get( [ "showtoolbar",                                              "usebetatoolbar" ] ); if ( GUIP.opts.usebetatoolbar ) { // race condition mw.loader.using( [ "ext.wikiEditor" ],                               BOOK.fire ); } else { BOOK.fire; }        }      }   };   // TASK.fire

TASK.follow = function { // Proceed after completion of query results // Uses: //   >  .signature //   >  TASK.query.$links //   GUIP.flat //   mw.loader.using //   (TASK.filter) // 2016-02-21 PerfektesChaos@de.wikipedia GUIP.flat( "translated" ); mw.loader.using( [ CITWT.signature + "/opus",                        "user:PerfektesChaos/WikiSyntaxTextMod/U" ],                       TASK.filter ); GUIP.flat( "translated", TASK.query.$links ); };  // TASK.follow

TASK.found = function ( ask ) { // Source text selection is ready or input is known // Precondition: //   ask  -- search string, if known // Uses: //   >  GUIP.caret.selection //   >  .bibRecord //   >  APIC.stateless //   >  APIC.found //    < TASK.query //    < APIC.queries //   DESC.fire //   GUIP.flat //   APIC.worldCat.fire //   .(project).favorite //   GUIP.$flip //   GUIP.$flipper //   mw.loader.using //   GUIP.flop //   GUIP.input.filler //   (APIC.fire) // 2017-06-11 PerfektesChaos@de.wikipedia var search   = ( ask ? ask : GUIP.caret.selection ), stateless = "|isbn|",   // |oclc i, k, m, project, q, suggest, url; if ( ! search  &&   CITWT.bibRecord ) { search = CITWT.bibRecord.sign + " " + CITWT.bibRecord.subject; }     if ( search ) { TASK.query = DESC.fire( search ); if ( TASK.query ) { q = TASK.query; switch ( typeof q.url ) { case "string": q.url = [ q.url ]; break; case "object": break; default: q.url = false; }  // switch typeof q.url if ( q.url ) { GUIP.flat( "throbber" ); APIC.queries = [ ]; q.$links    = false; for ( i = 0; i < q.url.length;  i++ ) { url = q.url[ i ]; for ( m = 0; m < i;  m++ ) { if ( url === q.url[ m ] ) { url = false; break; }                 }   // for m                  if ( typeof url  ===  "string" ) { k = i + 1; APIC.queries.push( url ); url       = [ url,  "[" + k + "]" ]; q.url[ i ] = url; }                 if ( url ) { q.$links = GUIP.$flip( q.$links, url, k ); }              }   // for i               if ( typeof q.say  ===  "string" ) { GUIP.$flipper( q.$links, q.say ); suggest = q.say; }              GUIP.flat( "throbber", q.$links ); if ( typeof APIC.stateless ===  "string"   &&                    typeof q.scheme  ===  "string"   &&                    stateless.indexOf( "|" + q.scheme + "|" )  >=  0 ) { stateless = q[ q.scheme ]; if ( typeof stateless ===  "string" ) { stateless = q.scheme.toUpperCase + " " + stateless; APIC.queries.push( stateless ); }              }               if ( typeof PROJ.favorite  ===  "function" ) { project = PROJ.favorite( q, APIC.found ); if ( project ) { project.local = true; APIC.queries.push( project ); }              }               mw.loader.using( [ "mediawiki.api" ],                                APIC.fire ); if ( typeof q.source ===  "string" ) { suggest = q.source; }              GUIP.input.filler( suggest ); } else { GUIP.flop( q ); }        } else { GUIP.flat( "empty" ); }     } else { TASK.query = false; }  };   // TASK.found

TASK.fruit = function ( action ) { // Insert template // Precondition: //   action  -- string as insertion format identifier // Uses: //   >< TASK.template //   .opus.fruit //   GUIP.caret.fill // 2015-05-25 PerfektesChaos@de.wikipedia var indent, seed, start, suffix; switch ( action ) { case "compact": indent = -1; break; case "refref": indent = -1; start = " "; break; case "bibSection": indent = 3; start = "\n* "; suffix = "\n"; break; case "references": indent = 1; start = "\n \n"; break; }  // switch action seed = CITWT.opus.fruit( TASK.template, indent ); TASK.template = false; if ( seed ) { seed = ( start ? start : "" ) + seed + ( suffix ? suffix : "" ); GUIP.caret.fill( seed ); }  };   // TASK.fruit

//---

UTIL.feed = function ( assigned, access, address ) { // Load and run script // Precondition: //   assigned  -- signature //   access    -- script //   address   -- URL to be used, else created from access // Uses: //   >  .suite //   >  REPOS.maxage //   mw.loader.getState //   mw.loader.state //   mw.loader.load //   REPOS.fire // 2018-09-03 PerfektesChaos@de.wikipedia var p, rls; if ( ! mw.loader.getState( assigned ) ) { rls = { }; rls[ assigned ] = "loading"; mw.loader.state( rls ); if ( address ) { mw.loader.load( address ); } else { p = { bcache: 1 }; p.maxage = ( CITWT.suite === "r" ?  REPOS.maxage  :  100 ); REPOS.fire( REPOS.site,                       REPOS.store + access + ".js",                        false,                        p ); }     }   };   // UTIL.feed

UTIL.fetch = function ( access ) { // Run subscripts // Precondition: //   access  -- subscript // Uses: //   >  .signature //   >  .type //   >  .suite //   UTIL.feed // 2018-07-28 PerfektesChaos@de.wikipedia var sub = "/" + access; UTIL.feed( CITWT.signature + sub,                CITWT.type + sub + "/" + CITWT.suite ); };  // UTIL.fetch

UTIL.friend = function { // Load current project plug-in, if appropriate // Postcondition: //   Returns something, if plug-in should become available // Uses: //   >  .signature //   >  .core.site //   >  .core.sites //   UTIL.feed //   mw.loader.getState //   UTIL.fetch //   console.log // 2018-07-14 PerfektesChaos@de.wikipedia var signature = CITWT.signature + "/" + CITWT.core.site, r, s;     switch ( typeof CITWT[ CITWT.core.site ] ) { case "string": // load from URL r = CITWT[ CITWT.core.site ]; if ( r ) { UTIL.feed( signature, false, r ); }           break; case "object": // already provided if ( mw.loader.getState( signature ) ) { r = CITWT[ CITWT.core.site ]; }           break; default: // load from code base, if registered s = "|" + CITWT.core.site + "|"; if ( CITWT.core.sites.indexOf( s ) >=  0 ) { UTIL.fetch( CITWT.core.site ); r = true; }     }   // switch typeof CITWT[ CITWT.core.site ] if ( ! r  &&           typeof window.console  ===  "object"   &&           typeof window.console.log  ===  "function" ) { window.console.log( CITWT.type + " * Local project unknown: "                            + CITWT.core.site ); }     return r;   };   // UTIL.friend

UTIL.fullstop = function ( activity ) { // Stop immediately event propagation // Precondition: //   activity  -- event // 2015-05-12 PerfektesChaos@de.wikipedia if ( typeof activity ===  "object"   &&   activity ) { if ( typeof activity.preventDefault ===  "function" ) { activity.preventDefault; }        if ( typeof activity.stopPropagation  ===  "function" ) { activity.stopPropagation; }     }  };   // UTIL.fullstop

//---

XPORT.core.fold = function ( analyse ) { // Derive simple template parameters; not nested // Precondition: //   analyse  -- string, with parameter list // Postcondition: //   Returns object, with components identified by strings // 2015-05-12 PerfektesChaos@de.wikipedia var i = 0, m = 0, r = { }, s = analyse, t = [ ], j, k, sign; while ( s ) { j = s.indexOf( "|", i ); k = s.indexOf( "}}", i ); if ( j >= 0 &&  j < k ) { if ( i ) { t.push( s.substring( i, j ) ); }           i = j + 1; } else if ( k >= 0 ) { if ( k ) { t.push( s.substring( i, k ) ); }           s = false; } else { s = false; }     }   // while s      for ( i = 0;  i < t.length;  i++ ) { s = t[ i ].replace( /^\s+/, "" ) .replace( /\s+$/, "" ); j = s.indexOf( "=", i ); if ( j > 0 ) { sign = s.substr( 0, j ) .replace( /\s+$/, "" ); s   = s.substr( j + 1 ) .replace( /^\s+/, "" ); } else { m++; sign = "" + m;        } r[ sign ] = s;     }   // for i      return r;   };   // XPORT.core.fold

//---

XPORT.fire = function ( event ) { // Tool button has been clicked // Precondition: //   event  -- jQuery event object // Uses: //   >  GUIP.$panel //   UTIL.fullstop //   GUIP.flat //   GUIP.factory //   TASK.fiat // Remark: Used as event handler -- 'this' is not XPORT // 2015-05-23 PerfektesChaos@de.wikipedia UTIL.fullstop( event ); if ( GUIP.$panel ) { GUIP.flat( false ); } else { GUIP.factory; }     TASK.fiat; };  // XPORT.fire

//---

function fire { // Start regular workflow in edit mode, if appropriate // Uses: //   >  CITWT //   >  HELP.site //   >  HELP.support //   >  Version //   >  .signature //   >< .bibRecord //    < .support //    < .core.site //   facilitated //   mw.config.get //   PREGO.feed //   UTIL.fetch //   UTIL.feed //   UTIL.friend //   mw.loader.using //   (TASK.fire) // 2018-07-28 PerfektesChaos@de.wikipedia var env, sub, suitable; facilitated; if ( CITWT ) { env = mw.config.get( [ "wgAction",                                 "wgDBname",                                 "wgIsProbablyEditable",                                 "wgPageContentModel" ] ); CITWT.support  = "" + HELP.site + ":" + HELP.support + ""; CITWT.core.site = env.wgDBname; suitable       = "|edit|submit|"; if ( suitable.indexOf( env.wgAction ) >  0   &&              env.wgIsProbablyEditable   &&              env.wgPageContentModel === "wikitext"   &&              UTIL.friend ) { PREGO.feed; UTIL.fetch( "opus" ); sub = ( Version > 1 ?  "r"  :  "d" ); UTIL.feed( "user:PerfektesChaos/WikiSyntaxTextMod/S",                      "WikiSyntaxTextMod/" + sub + "S" ); UTIL.feed( "user:PerfektesChaos/WikiSyntaxTextMod/U",                      "WikiSyntaxTextMod/" + sub + "U" ); UTIL.feed( "ext.gadget.isbnLib",                      "isbnLib/" + sub ); if ( typeof CITWT.bibRecord !==  "object" ) { CITWT.bibRecord = false; }           mw.loader.using( [ "mediawiki.user",                               "mediawiki.util",                               "user",                               "user.options",                               CITWT.signature + "/" + env.wgDBname ],                             TASK.fire ); }     }   }   // fire

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

/// EOF  citoidWikitext/core/d.js