User:PerfektesChaos/js/remindErrorMessages/d.js

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/remindErrorMessages/d.js
//  Check rendered page whether HTML elements with class="error" occur
/// 2022-07-01 PerfektesChaos@de.wikipedia
//  ResourceLoader: compatible;
//    dependencies: NONE
/// Fingerprint:    #0#0#
/// @license: CC-by-sa/4.0 GPLv3
//  Documentation:  [[w:en:User:PerfektesChaos/js/remindErrorMessages]]
/// <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   = -2.6,
       Sign      = "remindErrorMessages",
       Shop      = "w:en:User:PerfektesChaos/js/",
       Selectors = [ ".mw-error",
                     ".mw-warning",
                     ".error",
                     ".warning",
                     ".errorbox",
                     ".warningbox",
                     ".cm-error",
                     "div[role=\"alert\"]" ],
       Submit    = ".errorbox",
       Category  = { state:  ".mw-hidden-catlinks",
                     submit: ".hiddencats",
                     track:  [ "duplicate-args-category",
                               "expensive-parserfunction-category",
                               "graph-broken-category",
                               "kartographer-broken-category",
                               "math-tracking-category-error",
                               "math-tracking-category-render-error",
                               "node-count-exceeded-category",
                               "post-expand-template-argument-category",
                               "post-expand-template-inclusion-category",
                               "restricted-displaytitle-ignored",
                               "score-error-category",
                               "syntaxhighlight-error-category",
                               "templatestyles-page-error-category" ],
                     $hidden: false },
       CodeMirr  = { live: false },
       Content   = { $contentSub: false },
       Repo      = { minutes: 1440 },
       This      = { complaints: false,
                     config:   false,
                     css:      { bark:   { "background-color": "#FFFF00",
                                           "color":            "#FF0000",
                                           "font-size":        "120%",
                                           "font-weight":      "bold" },
                                 box:    { "border-color":     "#FF0000",
                                           "border-style":     "solid",
                                           "border-width":     "3px",
                                           "font-size":        "1rem",
                                           "font-style":       "normal",
                                           "font-weight":      "normal",
                                           "line-height":      "1.3rem",
                                           "margin-top":       "0.5rem",
                                           "margin-bottom":    "0.5rem",
                                           "padding":          "5px" },
                                 preview:{ "background-color": "#FFDDDD",
                                           "border-color":     "#FF0000",
                                           "border-style":     "dashed",
                                           "border-width":     "2px",
                                           "font-size":        "0.8rem",
                                           "line-height":      "1.5rem",
                                           "margin-top":       "1rem",
                                           "margin-bottom":    "1.5rem",
                                           "padding-top":      "0.3rem",
                                           "padding-bottom":   "0.3rem",
                                           "padding-left":     "1rem",
                                           "padding-right":    "1rem" },
                                 warn:   { "background-color": "#FF0000",
                                           "color":            "#FFFF00",
                                           "font-size":        "150%",
                                           "font-weight":      "1000",
                                           "margin-left":      "0.5em",
                                           "margin-right":     "0.5em",
                                           "padding-left":     "0.5em",
                                           "padding-right":    "0.5em",
                                           "padding-top":      "4px",
                                           "padding-bottom":   "4px" }
                               },
                     options:  { categories: "object",
                                 hiddencats: "boolean",
                                 maintCats:  "number" },
                     opt:      false,
                     shrink:   "-invisible",
                     suppress: "-noContent",
                     unselect: [ "#editpage-copywarn-declaration",
                                 "#mw-anon-preview-warning" ],
                     warnDrop: [ ".mw-warning-with-logexcerpt" ]
                   };



   Category.factory = function () {
      // Create maintenance category titles object
      // Precondition:
      //    mediawiki.api is ready
      //    mediawiki.storage is ready
      // Uses:
      //    >  Category.track
      //    >< Category.Api
      //    mw.Api.loadMessagesIfMissing()
      //    Category.feed()
      //    (Category.feed)
      //    (Category.fault)
      // 2019-07-01 PerfektesChaos@de.wikipedia
      if ( typeof Category.track  ===  "object"
           &&     Category.track    &&
           typeof Category.track.length  ===  "number" ) {
         if ( typeof Category.Api  ===  "undefined" ) {
            Category.Api = new mw.Api();
         }
         Category.Api.loadMessagesIfMissing( Category.track )
                     .done( Category.feed )
                     .fail( Category.fault );
      } else {
         Category.feed();
      }
   };   // Category.factory()



   Category.fault = function ( jqXHR, textStatus, errorThrown ) {
      // API query failure
      // Precondition:
      //    Common failure call
      // Uses:
      //    >  Sign
      // 2019-07-01 PerfektesChaos@de.wikipedia
      var scream;
      if ( textStatus ) {
         switch ( typeof textStatus ) {
            case "object":
               if ( typeof textStatus.textStatus  ===  "string" ) {
                  scream = textStatus.textStatus;
               } else {
                  scream = "";
               }
               if ( typeof textStatus.exception  ===  "string"
                    &&     textStatus.exception ) {
                  scream = scream + " (" + textStatus.exception + ")";
               }
               break;
            case "string":
               scream = textStatus;
               break;
         }   // switch
      }
      if ( errorThrown ) {
         if ( scream ) {
            scream = scream + "  -- Error: ";
         }
         scream = scream + errorThrown;
      }
      if ( ! scream ) {
         scream = "???";
      }
      if ( typeof window.console  ===  "object"   &&
           typeof window.console.log  ===  "function" ) {
         window.console.log( Sign + " * " + scream );
         if ( typeof textStatus  ===  "object"
              &&     textStatus   &&
              typeof window.console.dir  ===  "function" ) {
            window.console.dir( textStatus );
         }
      }
   };   // Category.fault()



   Category.feed = function ( answer ) {
      // Build maintenance category titles object from system messages
      // Precondition:
      //    answer  -- messages, or false
      //    api.messages available
      //    mediawiki.storage is ready
      // Uses:
      //    >  Category.track
      //    >  Category.$hidden
      //    >< Category.titles
      //     < Category.tracking
      //     < Category.parsing
      //    mw.message()
      //    Category.fire()
      //    Content.follow()
      //    Repo.flush()
      // 2019-07-01 PerfektesChaos@de.wikipedia
      var i, s;
      Category.tracking = false;
      Category.parsing  = false;
      if ( answer ) {
         for ( i = 0;  i < Category.track.length;  i++ ) {
            s = Category.track[ i ];
            if ( mw.messages.exists( s ) ) {
               s = mw.message( s ).plain();
               if ( s.indexOf( "\n" ) < 0  &&
                    s.indexOf( "{{" ) < 0 ) {
                  if ( typeof Category.tracking  !==  "object" ) {
                     Category.tracking = [ ];
                  }
                  Category.tracking.push( s );
                  if ( typeof Category.titles  !==  "object" ) {
                     Category.titles = { };
                  }
                  Category.titles[ s ] = true;
               } else {
                  if ( typeof Category.parsing  !==  "object" ) {
                     Category.parsing = [ ];
                  }
                  Category.parsing.push( s );
               }
            }
         }   // for i
      }
      if ( ! Category.$hidden ) {
         Category.fire();
         Content.follow();
      }
      Repo.flush();
   };   // Category.feed()



   Category.fetch = function () {
      // Populate maintenance category information
      // Precondition:
      //    mediawiki.storage is ready
      // Uses:
      //     < Category.titles
      //     < Category.parsing
      //    Repo.first()
      //    Category.fire()
      //    Content.follow()
      //    Repo.fresh()
      //    mw.loader.using()
      //    (Category.factory)
      // 2019-07-01 PerfektesChaos@de.wikipedia
      var repo = Repo.first(),
          load;
      if ( ! repo   ||
           typeof repo.titles  ===  "undefined"   ||
           typeof repo.parsing  ===  "undefined" ) {
         load = true;
      } else {
         Category.titles  = repo.titles;
         Category.parsing = repo.parsing;
         Category.fire();
         Content.follow();
         load = ! Repo.fresh();
      }
      if ( load ) {
         mw.loader.using( [ "mediawiki.api" ],
                          Category.factory );
      }
   };   // Category.fetch()



   Category.filter = function ( $a ) {
      // Decide whether category title is whitelisted
      // Precondition:
      //    $a  -- <a> with category link
      // Postcondition:
      //    Return <a>, or nothing
      // Uses:
      //    >  Category.titles
      //    >  Category.parsing
      //    >  Category.user
      // 2019-10-24 PerfektesChaos@de.wikipedia
      var c, i, re, r,
          seek = $a.text();
      if ( typeof Category.titles  ===  "object"
           &&     Category.titles  &&
           typeof Category.titles[ seek ]  ===  "boolean" ) {
         r = true;
      } else if ( typeof Category.parsing  ===  "object"
                  &&     Category.parsing  &&
                  typeof Category.parsing.length  ===  "number" ) {
         re = new RegExp( "\\b" + seek + "\\b" );
         for ( i = 0;  i < Category.parsing.length;  i++ ) {
            if ( re.test( Category.parsing[ i ] ) ) {
               r = true;
               break;   // for i
            }
         }   // for i
      }
      if ( ! r  &&  Category.user ) {
         for ( i = 0;  i < Category.user.length;  i++ ) {
            c = Category.user[ i ];
            switch ( typeof c ) {
               case "string":
                   r = ( c === seek );
                   break;   // switch
               case "object":
               case "function":
                   r = c.test( seek );
                   break;   // switch
            }   // switch typeof c
            if ( r ) {
               break;   // for i
            }
         }   // for i
      }
      return ( r ? $a.clone() : false );
   };   // Category.filter()



   Category.fire = function () {
      // Handler when page initiialized
      // Uses:
      //    >  Category.submit
      //    >  Category.state
      //    >  Category.limit
      //     < Category.$hidden
      //    Category.filter()
      // 2019-07-01 PerfektesChaos@de.wikipedia
      var $wrap = $( Category.state ),
          i, k, less, s, $div, $e, $li, $list, $ul;
      if ( $wrap.length ) {
         $e = $wrap.find( "ul" );
         if ( $e.length ) {
            $list = $e;
            $e    = $wrap.contents();
            if ( $e.get( 0 ).nodeType === 3 ) {
               $div = $( "<div>" );
               $div.text( $e.eq( 0 ).text().trim() );
            }
         }
      } else {
         $wrap = $( Category.submit );
         if ( $wrap.length ) {
            $e = $wrap.find( "p" );
            if ( $e.length ) {
               $div = $( "<div>" );
               $div.text( $e.text().trim() );
            }
            $list = $wrap.find( "ul" );
            less  = true;
         }
      }
      if ( $div ) {
         $list = $list.children();
         for ( i = 0;  i < $list.length;  i++ ) {
            $e = $list.eq( i ).find( "a" );
            if ( $e.length ) {
               if ( Category.limit ) {
                  $e = Category.filter( $e );
               } else {
                  $e = $e.clone();
               }
               if ( $e ) {
                  $e.attr( { target: "maintCats" } );
                  if ( less ) {
                     s = $e.text().trim();
                     k = s.indexOf( ":" );
                     if( k > 0 ) {
                        s = s.substr( k + 1 );
                        $e.text( s );
                     }
                  }
                  $li = $( "<li>" );
                  $li.append( $e );
                  $ul = $ul  ||  $( "<ul>" );
                  $ul.append( $li );
               }
            }
         }   // for i
         if ( $ul ) {
            Category.$hidden = $( "<div>" );
            Category.$hidden.append( $div );
            Category.$hidden.append( $ul );
         }
      }
   };   // Category.fire()



   CodeMirr.fiat = function () {
      // Handler when CodeMirror changed
      // Uses:
      //    >  CodeMirr.cm
      //    >  CodeMirr.$wrapper
      //    >< CodeMirr.complaints
      //    >< CodeMirr.many
      // 2018-01-11 PerfektesChaos@de.wikipedia
      var i, learnt, $e, $errors, $li;
      if ( CodeMirr.cm ) {
         $errors = CodeMirr.$wrapper.find( ".cm-error" );
         if ( $errors.length ) {
            if ( ! CodeMirr.complaints ) {
               CodeMirr.complaints = [ ];
               CodeMirr.many       = 0;
            }
            for ( i = 0;  i < $errors.length;  i++ ) {
               $e = $errors.eq( i );
               if ( ! $e.attr( "id" ) ) {
                  learnt = true;
                  CodeMirr.many++;
                  $e.attr( "id", "cm-error-" + CodeMirr.many );
               }
            }   // for i
            if ( learnt  ||
                 $errors.length !== CodeMirr.complaints.length ) {
               CodeMirr.complaints = [ ];
               for ( i = 0;  i < $errors.length;  i++ ) {
                  $e  = $errors.eq( i );
                  $li = $( "<li>" );
                  $li.attr( "id",  $e.attr( "id" ) );
                  CodeMirr.complaints.push( $li );
               }   // for i
            }
         }
      }
   };   // CodeMirr.fiat()



   CodeMirr.finish = function () {
      // Handler when CodeMirror disabled
      // Uses:
      //     < CodeMirr.cm
      // 2017-09-03 PerfektesChaos@de.wikipedia
      CodeMirr.cm = null;
   };   // CodeMirr.finish()



   CodeMirr.fire = function ( application ) {
      // Handler when CodeMirror enabled
      // Precondition:
      //    application  -- object
      // Uses:
      //    >< CodeMirr.live
      //     < CodeMirr.cm
      //     < CodeMirr.complaints
      //     < CodeMirr.$wrapper
      //    mw.hook()
      //    (CodeMirr.finish)
      //    (CodeMirr.fiat)
      // 2017-09-03 PerfektesChaos@de.wikipedia
      CodeMirr.cm = application;
      if ( ! CodeMirr.live ) {
         CodeMirr.live = true;
         mw.hook( "CodeMirr.disabled" ).add( CodeMirr.finish );
         CodeMirr.complaints = false;
      }
      CodeMirr.$wrapper = $( CodeMirr.cm.getWrapperElement() );
      CodeMirr.cm.on( "change", CodeMirr.fiat );
   };   // CodeMirr.fire()



   CodeMirr.first = function () {
      // Uses:
      //    >  window.CodeMirror
      //    >< CodeMirr.cm
      //    mw.user.options.get()
      // 2018-07-06 PerfektesChaos@de.wikipedia
      var r, uo;
      if ( ! CodeMirr.cm   &&
           typeof window.CodeMirror  ===  "function"   &&
           typeof window.CodeMirr.doc  ===  "object" ) {
         CodeMirr.cm = window.CodeMirror;
      }
      if ( CodeMirr.cm ) {
         uo = mw.user.options.get( "usecodemirror" );
         if ( typeof uo  ===  "number"
              &&     uo > 0 ) {
			   r = CodeMirr.cm;
         }
      }
      return r;
   };   // CodeMirr.first()



   Content.fine = function () {
      // No HTML elements with class="error", cleanup if necessary
      // Uses:
      //    >  This.$box
      //    >  This.$barWarn
      //    >< This.lapsus
      // 2019-07-01 PerfektesChaos@de.wikipedia
      if ( This.lapsus ) {
         This.$box.hide();
         if ( typeof This.$barWarn  ===  "object" ) {
            This.$barWarn.hide();
         }
         This.lapsus = false;
      }
   };   // Content.fine()



   Content.flip = function ( as, alert ) {
      // Make HTML element visible, highlight and add content to survey
      // Precondition:
      //    as     -- sequence number
      //    alert  -- DOM element
      // Postcondition:
      //    Return true -- continue $.each()
      // Uses:
      //    this  -- DOM element
      //    >  This.suppress
      //    >  This.shrink
      //    >  This.signed
      //    >  Sign
      //    >  This.complaints
      //    >  This.css.bark
      //    >  Content.selector
      // 2019-09-20 PerfektesChaos@de.wikipedia
      var $e = $( alert ),
          show, sign, $a;
      if ( ! $e.hasClass( This.signed )  &&   // child already displayed
           ! $e.hasClass( This.suppress ) ) {
         sign = $e.attr( "id" );
         if ( ! sign ) {
            sign = Sign + "_" + as;
            $e.attr( { id: sign } );
         }
         $e.addClass( This.signed )
           .css( This.css.bark );
         show = $e.text().replace( /^(\s|\xA0|&#160;)+/, "" )
                         .replace( /(\s|\xA0|&#160;)+$/, "" );
         if ( ! show ) {
            show = "[" + as + "]";
            $e.text( "ERROR" + show );
         }
         $e.find( "a" ).css( { "text-decoration": "underline" } );
         $a = $( "<a>" ).attr( { href:  "#" + sign } )
                        .text( show );
         This.complaints.push( $( "<li>" ).append( $a ) );
         $e.parent().show();
         $e.find( Content.selector ).addClass( This.signed );
      }
      return true;
   };   // Content.flip()



   Content.flop = function ( $alerts ) {
      // HTML elements with class="error" etc. detected
      // Precondition:
      //    $alerts  -- jQuery elements of class="error"; or false
      // Uses:
      //    >  Content.$content
      //    >  This.opts
      //    >  This.action
      //    >  Selectors
      //    >  Submit
      //    >  Stale
      //    >  Category.$hidden
      //    >< This.$barWarn
      //    >< This.complaints
      //    >< This.css.bark
      //    >< This.css.box
      //    >< This.css.warn
      //     < This.$ul
      //     < This.$box
      //     < This.lapsus
      //    (Content.flip)
      // 2022-07-01 PerfektesChaos@de.wikipedia
      var sign  = Sign + "_box",
          swift = "#" + sign,
          view  = { "display":     null,
                    "visibility":  "visible" },
          $box  = $( swift ),
          i, $next;
      if ( $alerts || Category.$hidden || $box.length ) {
         if ( $box.length ) {
            This.$ul.empty();
            This.$box = $box;
            This.$box.show();
         } else {
            This.$box = $( "<div>" );
            This.$box.attr( "id", sign );
            if ( This.opts ) {
               if ( typeof This.opts.barkCSS  ===  "object" ) {
                  $.extend( This.css.bark, This.opts.barkCSS );
               }
               if ( typeof This.opts.boxCSS  ===  "object" ) {
                  $.extend( This.css.box, This.opts.boxCSS );
               }
            }
            This.$box.css( This.css.box );
            This.$ul = $( "<ul>" );
            This.$box.append( This.$ul );
            Content.$content.prepend( This.$box );
         }
      } else {
         $( Submit ).eq( 0 ).attr( { id: sign } );
      }
      if ( This.action === "submit" ) {
         if ( typeof This.$barWarn  ===  "object" ) {
            This.$barWarn.show();
         } else {
            $next = $( "#wpPreview" );
            if ( $next.length ) {
               This.$barWarn = $( "<a>" );
               This.$barWarn.attr( { href: swift,
                                     id:   Sign + "_attention" } );
               if ( This.opts
                    &&   typeof This.opts.barCSS  ===  "object" ) {
                  $.extend( This.css.warn, This.opts.barCSS );
               }
               This.$barWarn.css(  This.css.warn );
               This.$barWarn.text( "!" );
               $next.before( This.$barWarn );
            }
         }
      }
      if ( $alerts ) {
         This.complaints = [ ];
         $alerts.each( Content.flip );
         for ( i = 0;  i < Selectors.length;  i++ ) {
            view.display = "block";
            $( "div" + Selectors[ i ] ).css( view );
            view.display = "inline";
            $( "span" + Selectors[ i ] ).css( view );
         }   // for i
         $( This.shrink ).empty();
      }
      if ( Category.$hidden ) {
         This.complaints = This.complaints  ||  [ ];
         This.complaints.push( Category.$hidden );
      }
      This.lapsus = ( This.complaints.length );
      if ( This.lapsus ) {
         for ( i = 0;  i < This.complaints.length;  i++ ) {
            This.$ul.append( This.complaints[ i ] );
         }   // for i
      }
   };   // Content.flop()



   Content.follow = function () {
      // Launch main task and listeners
      // Uses:
      //    >  Sign
      //    mw.hook()
      //    (Category.fire)
      //    (Content.fresh)
      //    (CodeMirr.fire)
      // 2019-10-10 PerfektesChaos@de.wikipedia
      mw.hook( "wikipage.content" ).add( Content.fresh );
      mw.hook( "error.message" ).add( Content.fresh );
      mw.hook( Sign + ".refresh" ).add( Content.fresh );
//    mw.hook( "CodeMirr.enabled" ).add( CodeMirr.fire );
   };   // Content.follow()



   Content.fresh = function ( $area ) {
      // Handler when content area has changed
      // Precondition:
      //    $area  -- jQuery element of content area, or not
      // Uses:
      //    >  Content.selector
      //    >  Content.unselect
      //    >  This.opts.previewCSS
      //    >  This.css.preview
      //    >  Submit
      //    >  Category.$hidden
      //    >  This.warnDrop.length
      //    >< Content.$contentSub
      //     < Content.$content
      //    Content.flop()
      //    Content.fine()
      // 2020-12-13 PerfektesChaos@de.wikipedia
      var $warnings = $( Content.selector ).not( Content.unselect ),
          i, suppress, $old, $paras, $preview, $warningbox;
      if ( ! Content.$contentSub ) {
         if ( Content.$contentSub === false ) {
            Content.$contentSub = $( "#contentSub" );
            if ( Content.$contentSub.length ) {
               Content.$content = Content.$contentSub;
            } else {
               Content.$contentSub = null;
            }
         }
         if ( ! Content.$contentSub ) {
            if ( $area ) {
               Content.$content = $area;
            } else {
               Content.$content = $( "#mw-content-text" );
            }
         }
      }
      if ( $warnings.length ) {
         $warningbox = $( ".warningbox" );
         if ( $warningbox.length ) {
            $preview = $( ".previewnote .warningbox" );
            if ( $preview.length ) {
               if ( This.opts      &&
                    typeof This.opts.previewCSS  ===  "object" ) {
                  $.extend( This.css.preview, This.opts.previewCSS );
               }
               $preview.removeClass( "warningbox " + This.signed )
                       .css( This.css.preview );
               $warnings = $warnings.not( $preview.get( 0 ) );
               $paras    = $preview.find( "p" );
               if ( $paras.length > 1 ) {
                  $preview = $paras.eq( 0 );
                  $paras   = $paras.not( $preview );
                  $paras.each( function () {
                                  var $p = $( this );
                                  $warnings = $warnings.add( $p );
                                  $p.detach();
                               } );
               }
            }
            $old = $warningbox.filter( ".mw-revision" );
            if ( $old.length ) {
               $old.addClass( This.suppress );
               $warnings = $warnings.not( $old );
               $old = $area.children().eq( 0 ).filter( ".warningbox" );
               if ( $old.length ) {
                  $old.addClass( This.suppress );
                  $warnings = $warnings.not( $old );
               }
            }
            if ( This.warnDrop.length ) {
               for ( i = 0;  i < This.warnDrop.length;  i++ ) {
                  if ( i ) {
                     suppress = suppress + ",";
                  } else {
                     suppress = "";
                  }
                  suppress = suppress + This.warnDrop[ i ];
               } // for i
               $old = $warningbox.filter( suppress );
               if ( $old.length ) {
                  $old.addClass( This.suppress );
                  $warnings = $warnings.not( $old );
               }
            }
         }
      }
      if ( $warnings.length ) {
         Content.flop( $warnings );
      } else if ( $( Submit ).length  ||  Category.$hidden ) {
         Content.flop();
      } else {
         Content.fine();
      }
   };   // Content.fresh()



   Repo.first = function () {
      // Initialize local storage
      // Precondition:
      //    mediawiki.storage is ready
      // Uses:
      //    >  Sign
      //    >  JSON
      //     < Repo.repo
      //    mw.storage.get()
      // 2019-07-01 PerfektesChaos@de.wikipedia
      var stored = mw.storage.get( Sign );
      if ( stored ) {
         try {
            Repo.repo = JSON.parse( stored );
         } catch( ex ) {
            // why ever * corrupted by anyone
            Repo.repo = false;
         }
      }
      return Repo.repo;
   };   // Repo.first()



   Repo.flush = function () {
      // Memorize current options in local storage
      // Precondition:
      //    mediawiki.storage is ready
      // Uses:
      //    >  Category.titles
      //    >  Category.parsing
      //    >  Sign
      //     < Repo.repo
      //    mw.storage.set()
      //    Category.fault()
      // 2019-07-01 PerfektesChaos@de.wikipedia
      var date = new Date(),
          ms   = date.getTime(),
          luck;
      Repo.repo = { minutes:  Math.floor( ms * 0.0000166666667 ) };
      if ( typeof Category.titles  ===  "object" ) {
         Repo.repo.titles = Category.titles;
      } else {
         Repo.repo.titles = false;
      }
      if ( typeof Category.parsing  ===  "object" ) {
         Repo.repo.parsing = Category.parsing;
      } else {
         Repo.repo.parsing = false;
      }
      luck = mw.storage.set( Sign, JSON.stringify( Repo.repo ) );
      if ( ! luck ) {
         Category.fault( false, "local storage dump" );
      }
   };   // Repo.flush()



   Repo.fresh = function () {
      // Is local storage still fresh?
      // Postcondition:
      //    Return true, if local storage is still fresh
      // Uses:
      //    >  Repo.repo.minutes
      //    >  Repo.minutes
      // 2019-07-01 PerfektesChaos@de.wikipedia
      var date, m, r;
      if ( typeof Repo.repo  ===  "object"
           &&     Repo.repo    &&
           typeof Repo.repo.minutes  ===  "number"    &&
           typeof Repo.minutes  ===  "number" ) {
         date = new Date();
         m    = date.getTime() * 0.0000166666667;
         r    = ( m  <  Repo.repo.minutes + Repo.minutes );
      }
      return r;
   };   // Repo.fresh()



   function feature( all, apply, about ) {
      // Configure single option from external
      // Precondition:
      //    all     -- object with all external options
      //    apply   -- string with option name
      //    about   -- string with required option type
      // Uses:
      //     < This.opts.*
      // 2019-10-24 PerfektesChaos@de.wikipedia
      if ( typeof all[ apply ]  ===  about
           &&     ( all[ apply ]  ||  all[ apply ] === false ) ) {
         This.opts[ apply ] = all[ apply ];
      }
   }   // feature()



   function features( assign ) {
      // Configure options from external
      // Precondition:
      //    assign   -- object with external options
      // Uses:
      //    >  This.css
      //    >< This.opts
      //    >< This.options
      //    feature()
      // 2019-10-24 PerfektesChaos@de.wikipedia
      var s;
      if ( typeof assign  ===  "object"
           &&     assign ) {
         This.opts = This.opts  ||  { };
         for ( s in This.css ) {
            This.options[ s + "CSS" ] = "object";
         }
         for ( s in assign ) {
            feature( assign, s, This.options[ s ] );
         }
      }
   }   // features()



   function fiat() {
      // DOM is ready, analyze initial page
      // Uses:
      //    >  This.namespaceNumber
      //    >  This.opts.hiddencats
      //    >  This.opts.categories
      //    >< This.opts.maintCats
      //     < Category.user
      //     < Category.limit
      //    mw.loader.using()
      //    Category.fire()
      //    Content.follow()
      //    (Category.fetch)
      // 2019-10-24 PerfektesChaos@de.wikipedia
      var i, v;
      if ( This.namespaceNumber !== 14 ) {
         This.opts = This.opts  ||  { };
         if ( typeof This.opts.maintCats  !==  "number"  &&
              typeof This.opts.hiddencats  ===  "boolean" ) {
            if ( This.opts.hiddencats ) {
               This.opts.maintCats = 2;
            } else {
               This.opts.maintCats = 0;
            }
         }
         if ( typeof This.opts.categories  ===  "object"   &&
              typeof This.opts.categories.length  ===  "number"
              &&     This.opts.categories.length >= 1 ) {
            Category.user = [ ];
            for ( i = 0;  i < This.opts.categories.length;  i++ ) {
               v = This.opts.categories[ i ];
               if ( ( typeof v  ===  "string"
                      &&     v )     ||
                    ( ( typeof v  ===  "object"   &&   v    ||
                        typeof v  ===  "function" )    &&
                      typeof v.test  ===  "function" ) ) {
                  Category.user.push( v );
               }
            } // for i
            if ( ! Category.user.length ) {
               Category.user = false;
            }
         } else {
            Category.user = false;
         }
         if ( typeof This.opts.maintCats  !==  "number" ) {
            This.opts.maintCats = 1;
         }
         if ( This.opts.maintCats >= 1 ) {
            Category.limit = ( This.opts.maintCats < 2 );
         }
         if ( Category.limit ) {
            mw.loader.using( [ "mediawiki.storage" ],
                             Category.fetch );
         } else {
            if ( This.opts.maintCats >= 2 ) {
               Category.fire();
            }
            Content.follow();
         }
      } else {
         Content.follow();
      }
   }   // fiat()



   function fire() {
      // Error messages might occur in this context
      // Uses:
      //    >  Sign
      //    >  Version
      //    >  Shop
      //    >  mw.libs
      //     < This.lapsus
      //     < This.config
      //     < This.complaints
      //    features()
      //    mw.hook()
      //    (fiat)
      // 2019-10-24 PerfektesChaos@de.wikipedia
      var card = { type: Sign,
                   vsn:  Version,
                   doc:  "[[" + Shop + Sign + "]]" };
      This.lapsus = false;
      if ( typeof mw.libs[ Sign ]  ===  "object"
           &&     mw.libs[ Sign ] ) {
         This.config = mw.libs[ Sign ];
         if ( This.config ) {
            This.config.vsn = card.vsn;
            This.config.doc = card.doc;
            if ( typeof This.config.options  ===  "object"
                 &&     This.config.options ) {
               features( This.config.options );
            }
         }
      }
      This.complaints = [ ];
      $( fiat );
      mw.hook( Sign ).fire( card );
   }   // fire()



   function first() {
      // Autorun on load (once)
      // Uses:
      //    >  Sign
      //    >  Selectors
      //    >  This.unselect
      //     < This.action
      //     < This.namespaceNumber
      //     < Content.selector
      //     < Content.unselect
      //     < This.signed
      //     < This.suppress
      //    mw.loader.getState()
      //    mw.loader.state()
      //    mw.hook()
      //    mw.config.get()
      //    mw.loader.using()
      //    (features)
      //    (fire)
      // 2022-01-01 PerfektesChaos@de.wikipedia
      var signature = "ext.gadget." + Sign,
          env, i, launch, rls;
      if ( mw.loader.getState( signature ) !== "ready" ) {
         rls = { };
         rls[ signature ] = "ready";
         mw.loader.state( rls );
         mw.hook( Sign + "-options" ).add( features );
         env = mw.config.get( [ "wgAction",
                                "wgNamespaceNumber" ] );
         switch ( env.wgAction ) {
            case "view" :
               launch = ( env.wgNamespaceNumber >= 0 );
               // includes veaction=edit
               // upload?
               break;
            case "submit" :
            case "parsermigration-edit" :
               launch = true;
               break;
         }   // switch wgAction
         if ( launch ) {
            This.action          = env.wgAction;
            This.namespaceNumber = env.wgNamespaceNumber;
            for ( i = 0;  i < Selectors.length;  i++ ) {
               if ( i ) {
                  Content.selector = Content.selector + ",";
               } else {
                  Content.selector = "";
               }
               Content.selector = Content.selector + Selectors[ i ];
            }   // for i
            for ( i = 0;  i < This.unselect.length;  i++ ) {
               if ( i ) {
                  Content.unselect = Content.unselect + ",";
               } else {
                  Content.unselect = "";
               }
               Content.unselect = Content.unselect + This.unselect[ i ];
            }   // for i
            This.signed   = Sign + "_msg";
            This.shrink   = "." + Sign + This.shrink;
            This.suppress = Sign + This.suppress;
            mw.loader.using( [ "user" ],
                             fire );
         }
      }
   }   // first()



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

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