Hinweis: Leere nach dem Veröffentlichen den Browser-Cache, um die Änderungen sehen zu können.

  • Firefox/Safari: Umschalttaste drücken und gleichzeitig Aktualisieren anklicken oder entweder Strg+F5 oder Strg+R (⌘+R auf dem Mac) drücken
  • Google Chrome: Umschalttaste+Strg+R (⌘+Umschalttaste+R auf dem Mac) drücken
  • Edge: Strg+F5 drücken oder Strg drücken und gleichzeitig Aktualisieren anklicken
/// localUserOptions.js
//  Gadget to save user options via LocalStorage
//  ResourceLoader:  compatible;
//    dependencies: mediawiki.storage
/// License: CC-by-sa/4.0
//  Documentation:  [[w:de:]]
/// <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   = 0.1,   // 2022-07-31
       Signature = "localUserOptions",
       OPT       = { entry:   null,
                     keep:    1440,
                     minutes: 1440,
                     maxmin:  500000,
                     life:    false,
                     now:     false,
                     sign:    "_sign_",
                     since:   "_minutes_",
                     stored:  "_filled_"
                   },
       HOOK      = { };



   function fair( analyze ) {
      // Check object for lifecycle, and remove undesired components
      // Precondition:
      //    analyze  -- object, non-null, to be inspected
      // Postcondition:
      //    Returns aftermath
      //            --  false, nothing to do
      //            --  null, delete this component
      //            --  object, update by this
      // Uses:
      //    >
      var r = analyze,
          left, learn, m, o, s;
      for ( s in r ) {
         if ( typeof s  ===  "string"
              &&     s.trim() !== ""   &&
              typeof r[ s ]  ===  "object" ) {
            o = r[ s ];
            if ( o ) {
               if ( typeof o[ OPT.since ]  ===  "number" ) {
                  m = o[ OPT.since ];
                  if ( m < OPT.now  ||  m > OPT.maxmin ) {
                     o = false;
                  }
               } else {
                  o = false;
               }
            }
         } else {
            o = false;
         }
         if ( o ) {
            left = true;
         } else {
            delete r[ s ];
            learn = true;
         }
      }   // for s in r
      if ( ! left ) {
         r = null;
      } else if ( ! learn ) {
         r = false;
      }
      return r;
   }   // fair()



   function fire() {
      // mediawiki.storage available
      // Uses:
      //    >  Signature
      //    >  OPT.since
      //    >  OPT.now
      //    >  OPT.maxmin
      //    >  HOOK
      //    >< OPT.maxmin
      //     < OPT.now
      //     < OPT.options
      //     < OPT.life
      //     < OPT.sub
      //     < OPT.entry
      var date    = new Date(),
          ms      = date.getTime(),
          storage = mw.storage.get( Signature ),
          learn, left, o, s;
      OPT.now     = Math.floor( ms * 0.0000166666667 );
      OPT.maxmin += OPT.now;
      if ( storage ) {
         try {
            OPT.options = JSON.parse( storage );
            if ( typeof OPT.options  ===  "object" ) {
               OPT.life = ( OPT.options ? true : false );
            } else {
               OPT.options = false;
            }
         } catch( ex ) {
            // why ever * corrupted by anyone
            OPT.options = false;
         }
      }
      OPT.sub = mw.config.get( "wgUserName" );
      OPT.sub = ( OPT.sub  ?  "@" + OPT.sub  :  "@" );
      if ( OPT.options ) {
         if ( typeof OPT.options[ OPT.since ]  !==  "number"
              ||     OPT.options[ OPT.since ]  <  OPT.now ) {
            for ( s in OPT.options ) {
               if ( typeof s  ===  "string"   &&
                    typeof OPT.options[ s ]  ===  "object"
                    &&     OPT.options[ s ] ) {
                  o = fair( OPT.options[ s ] );
               } else {
                  o = null;
               }
               if ( typeof o  ===  "object" ) {
                  if ( o ) {
                     OPT.options[ s ] = o;
                     left             = true;
                  }
                  learn = true;
               } else {
                  left = true;
               }
               if ( left ) {
                  left = false;
               } else {
                  delete OPT.options[ s ];
               }
            }   // for s in OPT.options
            OPT.options[ OPT.since ] = OPT.now + OPT.keep;
         }
         if ( typeof OPT.options[ OPT.sub ]  ===  "object" ) {
            OPT.entry = OPT.options[ OPT.sub ];
            if ( OPT.entry  &&  ! learn ) {
               o = fair( OPT.entry );
               if ( typeof o  ===  "object" ) {
                  OPT.entry = o;
                  if ( o ) {
                     OPT.options[ OPT.sub ] = o;
                  } else {
                     delete OPT.options[ OPT.sub ];
                  }
                  learn = true;
               }
            }
         }
      } else {
         OPT.options              = { };
         OPT.options[ OPT.since ] = OPT.now + OPT.keep;
         learn                    = true;
      }
      if ( learn ) {
         storage = JSON.stringify( OPT.options );
         mw.storage.set( Signature, storage );
         if ( mw.storage.get( Signature ) === storage ) {
            OPT.life = true;
         } else {
            OPT.life = false;
         }
      }
      for ( s in HOOK ) {
         mw.hook( Signature + "." + s ).add( HOOK[ s ] );
      }   // for s in HOOK
   }   // fire()



   function first() {
      // Autorun on loading
      // Uses:
      //    >  Signature
      //    >  Version
      //    (fire)
      var signature = "ext.gadget." + Signature,
          rls;
      if ( mw.loader.getState( signature )  !==  "ready" ) {
         rls = { };
         rls[ signature ] = "ready";
         mw.loader.state( rls );
         mw.loader.using( "mediawiki.storage", fire );
         mw.hook( Signature + ".ready" ).fire( { type: Signature,
                                                 vsn:  Version } );
      }
   }   // first()



   HOOK.feasible = function ( answer ) {
      // Is possible here and now?
      // Precondition:
      //    answer  -- function, for callback
      // Postcondition:
      //    Calls answer function and provides true or false
      // Uses:
      //    >  OPT.life
      if ( typeof answer  ===  "function" ) {
         answer( OPT.life );
      }
   };   // HOOK.feasible()



   HOOK.fetch = function ( about ) {
      // Retrieve particular entry or entire set
      // Precondition:
      //    about  -- object, for query and answer
      //              .sign   -- string or boolean,
      //                         entry name, or true for all
      //              .found  -- function, for callback
      // Postcondition:
      //    Calls answer function and provides requested information,
      //          or null if not found, or false if unavailable
      // Uses:
      //    >  OPT.life
      //    >  OPT.entry
      var r;
      if ( typeof about  ===  "object"
           &&     about   &&
           typeof about.found  ===  "function" ) {
         if ( OPT.life ) {
            switch ( typeof about.sign ) {
               case "boolean":
                  if ( about.sign ) {
                     r = ( OPT.entry ? OPT.entry : null );
                  } else {
                     r = false;
                  }
                  break;
               case "string":
                  r = about.sign.trim();
                  if ( typeof OPT.entry[ r ]  ===  "object" ) {
                     r = OPT.entry[ r ];
                  } else if ( r ) {
                     r = null;
                  } else {
                     r = false;
                  }
                  break;
               default:
                  r = false;
            }   // switch about.sign
         } else {
            r = false;
         }
         about.found( r );
      }
   };   // HOOK.fetch()



   HOOK.fill = function ( assign ) {
      // Store option object
      // Precondition:
      //    assign     -- object, with timestamp and payload
      //                  ._sign_     -- string, with entry name
      //                  ._minutes_  -- number, with lifetime, or not
      //                  ._filled_   -- function, for callback, or not
      // Postcondition:
      //    Option object should be stored.
      //    If provided, calls answer function and tell stored object,
      //    or false if failed.
      // Uses:
      //    >  OPT.life
      //    >  OPT.since
      //    >  OPT.sign
      //    >  OPT.stored
      //    >  OPT.maxmin
      //    >  OPT.minutes
      //    >  OPT.now
      //    >  OPT.sub
      //    >  Signature
      //    >< OPT.entry
      //    >< OPT.options
      var m, o, s, sign;
      if ( typeof assign  ===  "object"
           &&     assign ) {
         if ( OPT.life ) {
            if ( typeof assign[ OPT.sign ]  ===  "string" ) {
               sign = assign[ OPT.sign ].trim();
               if ( sign ) {
                  for ( s in assign ) {
                     if ( s === OPT.since ) {
                        m = assign[ s ];
                     } else if ( s !== OPT.sign  &&
                                 s !== OPT.stored  &&
                                 typeof assign[ s ]  !==  "function" ) {
                        o      = o  ||  { };
                        o[ s ] = assign[ s ];
                     }
                  }   // for s in assign
                  if ( o ) {
                     if ( typeof m  !==  "number"   ||
                          m < 1   ||
                          m > OPT.maxmin ) {
                        m = OPT.minutes;
                     } else {
                        m = Math.floor( m );
                     }
                     o[ OPT.since ]         = m + OPT.now;
                     OPT.entry              = OPT.entry  ||  { };
                     OPT.entry[ sign ]      = o;
                     OPT.options[ OPT.sub ] = OPT.entry;
                     s = JSON.stringify( OPT.options );
                     if ( ! mw.storage.set( Signature, s ) ) {
                        OPT.life = false;
                        o        = false;
                     }
                  } else {
                     o = null;
                  }
               } else {
                  o = false;
               }
            } else {
               o = false;
            }
         } else {
            o = false;
         }
         if ( typeof assign[ OPT.stored ]  ===  "function" ) {
            assign[ OPT.stored ]( o );
         }
      }
   };   // HOOK.fill()



   HOOK.flush = function ( access ) {
      // Remove particular entry or all of this account
      // Precondition:
      //    access  -- string or boolean, entry name, or true for all
      // Postcondition:
      // Uses:
      //    >  OPT.sub
      //    >  Signature
      //    >< OPT.life
      //    >< OPT.entry
      //    >< OPT.options
      var left, s;
      if ( OPT.life && OPT.entry ) {
         switch ( typeof access ) {
            case "boolean":
               if ( access ) {
                  if ( typeof OPT.options[ OPT.sub ]  ===  "object" ) {
                     delete OPT.options[ OPT.sub ];
                     s = JSON.stringify( OPT.options );
                     if ( ! mw.storage.set( Signature, s ) ) {
                        OPT.life = false;
                     }
                  }
                  OPT.entry = false;
               }
               break;
            case "string":
               s = access.trim();
               if ( typeof OPT.entry[ s ]  ===  "object" ) {
                  delete OPT.entry[ s ];
                  for ( s in OPT.entry ) {
                     left = true;
                     break;   // for s
                  }   // for s in OPT.entry
                  if ( left ) {
                     OPT.options[ OPT.sub ] = OPT.entry;
                  } else {
                     delete OPT.options[ OPT.sub ];
                  }
                  s = JSON.stringify( OPT.options );
                  if ( ! mw.storage.set( Signature, s ) ) {
                     OPT.life = false;
                  }
               }
               break;
         }   // switch typeof access
      }
   };   // HOOK.flush()



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



/// EOF </nowiki>   localUserOptions.js