Benutzer:PerfektesChaos/js/localUserOptions.js
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