User:PerfektesChaos/js/autoBackup/d.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
This user script seems to have a documentation page at User:PerfektesChaos/js/autoBackup/d. |
/// User:PerfektesChaos/js/autoBackup/d.js
/// 2021-05-21 PerfektesChaos@de.wikipedia
// Backup Wiki TEXTAREA in regular intervals
// ResourceLoader: compatible;
// dependencies: user,
// mediawiki.api, mediawiki.user, mediawiki.util
/// Fingerprint: #0#0#
/// @license: CC-by-sa/4.0
/// <nowiki>
/* jshint forin:false */
/* global window:false, JSON:false */
/* jshint 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.4,
BAK = "autoBackup";
if ( typeof mw.libs[ BAK ] !== "object"
|| ! mw.libs[ BAK ] ) {
mw.libs[ BAK ] = { };
}
mw.libs[ BAK ].type = BAK;
BAK = mw.libs[ BAK ];
BAK.doc = "[[w:en:User:PerfektesChaos/js/" + BAK + "]]";
BAK.vsn = VERSION;
BAK.cnf = { maxAge: 72,
maxHist: 5,
maxPages: 10,
maxRev: 3,
mid: 5,
msec: 300000 };
BAK.disk = { self: "AutoBackupPerfectChaos",
stick: "newest|subject" };
BAK.gui = { };
BAK.util = { };
if ( ! typeof BAK.opt || typeof BAK.opt !== "object" ) {
BAK.opt = { };
}
// User options:
// .maxAge number of full hours to remember
// .maxHist number of history entries per revision to keep
// .maxPages number of pages to handle simultaneously
// .maxRev number of revisions to keep
// .mid number of minutes for scheduled snapshots
// .portlet add portlet link
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program;
* if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*/
// Requires: JavaScript 1.3 (String.charCodeAt String.replace)
// ECMA 262-3 § 11.8.5 (string comparison operators)
// MediaWiki 1.18 (mw.libs, jQuery core)
/*
.pages
wgArticleId { }
newest: timestamp
subject: last known page name
wgCurRevisionId { }
newest: timestamp
history: [
[ timestamp-new, snapshot ],
[ timestamp-old, snapshot ],
[ timestamp-older, snapshot ],
]
*/
BAK.cnf.text = {
// 2014-09-23 PerfektesChaos@de.wikipedia
"BAKself": {"en": "AutoBackup",
"de": "AutoBackup"},
"IntJSONparse": {"en": "Internal ERROR -- JSON.parse",
"de": "Interner FEHLER -- JSON.parse"},
"NoLSavail": {"en": "No localStorage available",
"de": "Kein localStorage zugreifbar"},
"otherPages": {"en": "Other Pages",
"de": "Andere Seiten"},
"pending": {"en": "Recover from pending abort?",
"de": "Wiederherstellung nach Abbruch?"},
"setItemExcept": {"en": "ERROR setting localStorage",
"de": "FEHLER beim Setzen im localStorage"},
"thisPage": {"en": "this page", //oldid
"de": "diese Seite"},
"VanishedLS": {"en": "ERROR: localStorage vanished",
"de": "FEHLER: localStorage verschwunden"},
"WriteCrash": {"en": "Crash on localStorage write attempt",
"de": "Schreibversuch auf localStorage versagt"}
}; // .cnf.text
BAK.cnf.translang = {
// 2012-11-30 PerfektesChaos@de.wikipedia
"de" : "de",
"de-at" : "de",
"de-ch" : "de",
"de-formal" : "de",
"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"
}; // .cnf.translang
BAK.cnf.favorite = function () {
// Guess user language
// Uses:
// this
// > .translang
// >< .slang
// mw.config.get()
// 2012-11-21 PerfektesChaos@de.wikipedia
var s;
if ( ! this.slang ) {
s = mw.config.get( "wgUserLanguage" ).toLowerCase();
s = this.translang[ s ];
if ( s ) {
this.slang = s;
} else {
this.slang = "en";
}
}
}; // .cnf.favorite()
BAK.cnf.feature = function ( apply ) {
// Wrap message text access for user language
// Precondition:
// apply -- text keyword
// Postcondition:
// Return text closest to user language
// Uses:
// this
// > .cnf.text
// .cnf.favorite()
// Remark: To be replaced
// if one day ResourceLoader3 gives access to
// gadget@translatewiki
// 2012-11-04 PerfektesChaos@de.wikipedia
var e, r;
if ( ! this.slang ) {
this.favorite();
}
e = this.text[ apply ];
if ( e ) {
r = e[ this.slang ];
if ( ! r ) {
r = e.en;
if ( ! r ) {
r = "???" + apply + "???";
}
}
} else {
r = "***" + apply + "***";
}
return r;
}; // .cnf.feature()
BAK.cnf.fetch = function () {
// Consider user options
// Uses:
// this
// > .opt
// > .learn
// >< .cnf.load
// < .cnf.maxAge
// < .cnf.maxHist
// < .cnf.maxPages
// < .cnf.maxRev
// < .cnf.mid
// < .cnf.msec
// .gui.facility()
// 2012-11-30 PerfektesChaos@de.wikipedia
if ( ! this.load ) {
if ( typeof BAK.opt === "object" ) {
if ( typeof BAK.opt.maxAge === "number" ) {
if ( BAK.opt.maxAge >= 0 ) {
this.maxAge = Math.floor( BAK.opt.maxAge );
}
}
if ( typeof BAK.opt.maxHist === "number" ) {
if ( BAK.opt.maxHist >= 1 ) {
this.maxHist = Math.ceil( BAK.opt.maxHist );
}
}
if ( typeof BAK.opt.maxPages === "number" ) {
if ( BAK.opt.maxPages >= 1 ) {
this.maxPages = Math.ceil( BAK.opt.maxPages );
}
}
if ( typeof BAK.opt.maxRev === "number" ) {
if ( BAK.opt.maxRev >= 1 ) {
this.maxRev = Math.ceil( BAK.opt.maxRev );
}
}
if ( BAK.learn ) {
if ( typeof BAK.opt.mid === "number" ) {
if ( BAK.opt.mid > 0 ) {
this.mid = BAK.opt.mid;
} else {
this.mid = false;
}
}
if ( this.mid ) {
this.msec = this.mid * 60000;
} else {
this.msec = false;
}
if ( BAK.opt.portlet ) {
BAK.gui.facility();
}
}
}
this.load = true;
}
}; // .cnf.fetch()
BAK.disk.fetch = function () {
// Retrieve pages object from localStorage data
// Postcondition:
// .pages is set to collection object, or false
// Uses:
// this
// > .disk.storage
// >< window.localStorage
// < .pages
// < .disk.lock
// .family()
// JSON.parse()
// .gui.flag()
// 2014-09-23 PerfektesChaos@de.wikipedia
var s;
BAK.pages = false;
if ( typeof window.localStorage === "object" ) {
BAK.family();
s = window.localStorage.getItem( this.storage );
if ( s ) {
try {
BAK.pages = JSON.parse( s );
} catch ( e ) {
BAK.gui.flag( "IntJSONparse", false );
window.localStorage.setItem( this.storage, "" );
}
}
} else {
BAK.gui.flag( "NoLSavail", false );
this.lock = true;
}
}; // .disk.fetch()
BAK.disk.flush = function () {
// Put .pages object into localStorage
// Postcondition:
// Clear empty .pages object
// Uses:
// this
// > .disk.storage
// >< window.localStorage
// >< .pages
// jQuery.toJSON()
// .gui.flag()
// 2014-09-23 PerfektesChaos@de.wikipedia
var store = false,
s;
if ( typeof BAK.pages === "object" ) {
for ( s in BAK.pages ) {
store = true;
break; // for s
} // for s
}
if ( ! store ) {
this.pages = false;
}
if ( typeof window.localStorage === "object" ) {
if ( BAK.pages ) {
store = JSON.stringify( BAK.pages );
if ( store === "{}") {
store = "";
}
} else {
store = "";
}
try {
window.localStorage.setItem( this.storage, store );
s = window.localStorage.getItem( this.storage );
if ( s !== store ) {
BAK.gui.flag( "WriteCrash", false );
}
} catch ( e ) {
BAK.gui.flag( "setItemExcept", false );
}
window.localStorage.setItem( this.storage, store );
} else {
BAK.gui.flag( "VanishedLS", false );
}
}; // .disk.flush()
BAK.gui.face = function ( apply ) {
// Prepare GUI message area for content
// Precondition:
// apply -- HTML message box content
// Uses:
// this
// > .$page
// >< .gui.$top
// >< .gui.$div
// >< .gui.$msg
// mw.util.addCSS()
// jQuery()
// jQuery().prepend()
// jQuery().before()
// jQuery().empty()
// jQuery().attr()
// jQuery().append()
// 2021-05-21 PerfektesChaos@de.wikipedia
var s;
if ( ! this.$div ) {
mw.util.addCSS( ".cn-fundraiser-banner,"
+ "#mw-js-message,"
+ "#siteNotice,"
+ "#fundraising\n"
+ "{display: none ! important;}" );
this.$div = $( "<div class='AutoBackupDiv' />" );
if ( ! this.$top ) {
this.$top = $( "#mw-content-text" );
if ( this.$top.length ) {
this.$top.prepend( this.$div );
} else {
this.$top = $( ".mw-body-content" ).eq( 0 );
if ( ! this.$top.length ) {
this.$top = $( "#article" );
if ( ! this.$top.length ) {
this.$top = $( "#content" );
if ( ! this.$top.length ) {
this.$top = BAK.$page;
}
}
}
this.$top.before( this.$div );
}
}
}
if ( apply ) {
if ( this.$msg ) {
this.$msg.empty();
} else {
this.$msg = $( "<div class='AutoBackupMsg' />" );
this.$div.prepend( this.$msg );
}
if ( this.$msg ) {
s = "display: block;"
+ "font-size: 120%;";
this.$msg.attr( "style", s );
this.$msg.append( apply );
}
} else {
if ( this.$msg ) {
this.$msg.attr( "style", "display: none;" );
}
}
}; // .gui.face()
BAK.gui.facility = function () {
// Equip portlet with link to trigger
// Precondition:
// document.ready
// Uses:
// >< .cnf.self
// > .type
// > .vsn
// .cnf.feature()
// mw.util.addPortletLink()
// (.fresh)
// 2017-01-04 PerfektesChaos@de.wikipedia
var portlet, $portlet;
if ( ! BAK.cnf.self ) {
BAK.cnf.self = BAK.cnf.feature( "BAKself" );
}
portlet = mw.util.addPortletLink( "p-cactions",
"#",
BAK.cnf.self,
"ca-" + BAK.type );
$portlet = $( portlet );
$portlet.click( BAK.fresh );
$portlet.attr( { title: BAK.type + " " + BAK.vsn } );
}; // .gui.facility()
BAK.gui.feed = function () {
// Retrieve content of text area; wpTextbox2 if edit conflict
// Precondition:
// document.ready
// Postcondition:
// Return textarea string; or false
// Uses:
// this
// > .$page
// > .gui.$textarea
// > wikEd
// >< .gui.leading
// < .gui.$editform
// < .gui.$textarea
// jQuery.find()
// wikEd.UpdateTextarea()
// 2019-07-01 PerfektesChaos@de.wikipedia
var r = false,
$form,
$ta;
if ( this.leading ) { // opening
this.leading = false;
this.$editform = false;
this.$textarea = false;
$form = BAK.$page.find( "#editform" );
if ( $form ) {
$ta = BAK.$page.find( "#wpTextbox2" );
if ( $ta.length ) { // edit conflict
r = $ta.val();
}
$ta = $form.find( "#wpTextbox1" );
if ( $ta.length ) { // textarea
if ( ! $ta.attr( "readonly" ) ) { // modifiable
this.$editform = $form;
this.$textarea = $ta;
}
} // textarea
}
}
if ( this.$textarea && ! r ) { // editing
if ( window.wikEd
&& typeof window.wikEd === "object"
&& ! window.wikEd.disabled
&& window.wikEd.turnedOn
&& window.wikEd.useWikEd
&& window.wikEd.UpdateTextarea ) {
window.wikEd.UpdateTextarea();
}
r = this.$textarea.val();
} // editing
return r;
}; // .gui.feed()
BAK.gui.fence = function ( apply ) {
// Draw box around entire autoBAK rectangle
// apply -- true if to be shown, or false to remove
// Uses:
// this
// > .gui.$div
// jQuery().attr()
// 2012-10-29 PerfektesChaos@de.wikipedia
this.$div.attr( "style",
( apply ? "border: solid 1px #606060;"
+ " border-bottom: solid 5px #606060;"
+ " padding: 0.5em;"
+ " margin-bottom: 2em;"
: null ) );
}; // .gui.fence()
BAK.gui.fiat = function ( action, add ) {
// Create button
// Precondition:
// action -- identifier
// add -- data identifier
// Postcondition:
// Return html string; or ""
// 2012-10-29 PerfektesChaos@de.wikipedia
var r;
switch ( action ) {
case "ALL" :
case "SHOW" :
r = "<span"
+ " style='font-size: 200%;"
+ " font-weight: bold;"
+ " color: #008000;'>*</span>";
break;
case "DELETE" :
r = "<span"
+ " style='font-size: 200%;"
+ " font-weight: bold;"
+ " color: #FF0000;'>X</span>";
break;
default:
r = "";
} // switch action
if ( r ) {
r = "\n \n"
+ "<button type='button'"
+ " id='autoBackup" + action
+ ( add ? add : "" ) + "'>"
+ r
+ "</button>";
}
return r;
}; // .gui.fiat()
BAK.gui.fill = function () {
// Fill current page with offers
// Uses:
// > .pages
// > .pageID
// > .gui.$msg
// > .disk.stick
// >< .gui.$box
// >< .revID
// jQuery().find()
// jQuery().remove()
// mw.config.get()
// .gui.fence()
// .gui.face()
// Remark: Used as event handler -- 'this' is not BAK
// 2012-11-04 PerfektesChaos@de.wikipedia
var page = BAK.pages[ BAK.pageID ],
revs = false,
i, n, s;
BAK.gui.$msg.find( "#autoBackupALL" ).remove();
if ( BAK.gui.$box ) {
BAK.gui.$box.remove();
}
if ( page ) {
BAK.gui.$box = $( "<div />" );
BAK.gui.$msg.after( BAK.gui.$box );
if ( ! BAK.revID ) {
BAK.revID = mw.config.get( "wgCurRevisionId" );
}
for ( i in page ) {
if ( BAK.disk.stick.indexOf( i ) < 0 ) {
s = page[ i ].newest + " " + i;
if ( revs ) {
revs.push( s );
} else {
revs = [ s ];
}
}
} // for i in page
n = revs.length;
revs.sort();
for ( i = revs.length-1; i >= 0; i-- ) {
BAK.gui.folder( revs[ i ], page );
} // for i--
BAK.gui.fence( true );
} else {
BAK.gui.face( false );
}
}; // .gui.fill()
BAK.gui.finish = function ( access ) {
// Define additional hook on standard editform button
// Precondition:
// access -- button ID
// Uses:
// this
// > .gui.$editform
// jQuery().find()
// jQuery().click()
// (.fresh)
// 2012-10-29 PerfektesChaos@de.wikipedia
var $btn = this.$editform.find( "#" + access );
if ( $btn.length ) {
$btn.click( BAK.fresh );
}
}; // .gui.finish()
BAK.gui.flag = function ( apply, action ) {
// Display error message similar to mw.util.jsMessage() MW 1.19
// Precondition:
// apply -- text keyword
// action -- identifier for button, or false if error case
// Uses:
// this
// > .cnf.slang
// >< .cnf.self
// .cnf.feature()
// .gui.fiat()
// .gui.face()
// .gui.form()
// 2012-11-03 PerfektesChaos@de.wikipedia
var s;
if ( ! BAK.cnf.self ) {
BAK.cnf.self = BAK.cnf.feature( "BAKself" );
}
s = BAK.cnf.feature( apply );
s = "<div id='autoBackup'"
+ " style='border: solid "
+ (action ? 2 : 5)
+ "px #FF0000;"
+ " padding: 0.5em;"
+ (action ? ""
: " color: #FF0000;")
+ "'>\n"
+ "<span style='font-size: larger; font-weight: bold;'>"
+ BAK.cnf.self + "</span> \n"
+ (action ? ""
: "<span class='error'>")
+ s
+ (action ? "\n"
: "</span>\n")
+ this.fiat( action )
+ "</div>\n";
this.face( s );
if ( action ) {
this.form( action, "" );
}
}; // .gui.flag()
BAK.gui.folder = function ( access, album ) {
// Insert single revision data into current page
// Precondition:
// access -- string sortkey_space_symbol
// album -- page revisions
// Uses:
// this
// > .gui.$box
// > .revID
// jQuery().append()
// jQuery().find()
// .cnf.feature()
// mw.config.get()
// .gui.fiat()
// .gui.form()
// .util.focus()
// .jQuery()
// .gui.full()
// 2012-11-06 PerfektesChaos@de.wikipedia
var e = access.split( " " ),
k = e[ 1 ],
s = "autoBackupR" + k,
i, w, $div, $textarea;
this.$box.append( "<div id='" + s + "' />" );
$div = this.$box.find( "#" + s );
if ( parseInt( k, 10 ) === BAK.revID ) {
s = k + " (" + BAK.cnf.feature( "thisPage" ) + ")";
} else {
s = mw.config.get( "wgArticlePath" );
s = "<a href='"
+ s.replace( /\$1/, "Special:PermanentLink/" ) + k
+ "' target='_blank'>" + k + "</a>";
}
s = "<h4>oldid=" + s + "</h4>";
s = s + this.fiat( "DELETE", k );
//
$div.append( s );
this.form( "DELETE", k );
e = album[ k ].history;
for ( i = 0; i < e.length; i++ ) {
k = e[ i ];
w = k[ 1 ];
s = "<h5>" + BAK.util.focus( k[ 0 ] ) + "</h5>"
+ "<p>" + w.length + " bytes</p>";
$div.append( s );
$textarea = $( "<textarea rows='5' readonly />" );
$textarea.val( w );
$div.append( $textarea );
} // for i++
this.full();
}; // .gui.folder()
BAK.gui.form = function ( action, add ) {
// Provide click action for button
// Precondition:
// action -- identifier
// add -- data distinguisher, or ""
// Uses:
// this
// > .gui.$top
// jQuery().find()
// jQuery().click()
// (.fixed)
// 2012-11-04 PerfektesChaos@de.wikipedia
var fun = false,
sign,
$btn;
switch ( action ) {
case "ALL" :
fun = this.fill;
break;
case "DELETE" :
sign = "DELETE" + add;
fun = function () { BAK.fixed( add ); };
BAK[ sign ] = fun;
break;
case "SHOW" :
break;
} // switch action
if ( fun ) {
$btn = this.$top.find( "#autoBackup" + action + add );
if ( $btn.length ) {
$btn.click( fun );
}
}
}; // .gui.form()
BAK.gui.full = function () {
// Display otherPages offers on GUI
// Uses:
// this
// > .pages
// > .pageID
// > .gui.$div
// >< .gui.reSpace
// jQuery().empty()
// .cnf.feature()
// jQuery().append()
// jQuery().find()
// mw.config.get()
// mw.util.wikiUrlencode()
// .util.focus()
// .gui.fence()
// 2012-11-06 PerfektesChaos@de.wikipedia
var e, g, i, p, s, u, $x;
if ( BAK.pages ) {
g = false;
s = "" + BAK.pageID;
for ( i in BAK.pages ) {
if ( i !== s ) {
p = BAK.pages[ i ];
if ( p.subject ) {
if ( ! this.reSpace ) {
this.reSpace = new RegExp(" +", "g");
}
e = " " + p.subject.replace( this.reSpace, "_" );
} else {
e = "";
}
e = p.newest + " " + i + e;
if ( g ) {
g.push( e );
} else {
g = [ e ];
}
}
} // for i
if ( g ) {
s = "<h3>"
+ BAK.cnf.feature( "otherPages" )
+ "</h3>\n"
+ "<ul id='autoBackupPageList' />";
this.$div.append( s );
$x = this.$div.find( "#autoBackupPageList" );
u = "<a target='_blank'"
+ " href='" + mw.config.get( "wgScript" ) + "?";
g.sort();
for ( i = g.length - 1; i >= 0; i-- ) {
e = g[ i ];
p = e.split( " " );
s = p[ 1 ];
if ( s.substr( 0, 2 ) === "0_" ) {
s = s.substr( 2 );
s = u + "title=" + mw.util.wikiUrlencode( s )
+ "&redirect=no'>" + s + "</a> ";
} else {
s = "curid=" + u + "curid=" + s + "'>" + s + "</a> ";
if ( p[ 2 ] ) {
s = s + "(" + p[ 2 ].replace( /_/g, " " )
.replace( /</g, "<" )
+ ") ";
}
}
s = "<li>" + s + BAK.util.focus( p[ 0 ] )
+ "</li>";
$x.append( s );
} // for i--
}
this.fence( true );
}
}; // .gui.full()
BAK.gui.further = function () {
// Try to define additional hooks on buttons
// Uses:
// this
// > .gui.$editform
// .gui.finish()
// (.fresh)
// 2012-11-03 PerfektesChaos@de.wikipedia
if ( this.$editform ) { // editing
this.finish( "wpDiff" );
this.finish( "wpPreview" );
this.finish( "wpSave" );
this.$editform.find( ".mw-summary" ).focusin( BAK.fresh );
}
}; // .gui.further()
BAK.util.figure = function ( ask ) {
// Is ask a positive number or zero?
// Precondition:
// ask -- string
// Postcondition:
// Return true iff ask contains only digits
// 2012-10-29 PerfektesChaos@de.wikipedia
return (/^[0-9]+$/).test( ask );
}; // .util.figure()
BAK.util.flat = function ( album, amount, arrange ) {
// Reduce number of entries in object; remove lowest sorted
// Precondition:
// album -- object to be limited
// amount -- maximum number of components within album
// arrange -- Array with sort keys and IDs, or false
// every entry is string sortkey_space_symbol
// 2012-11-07 PerfektesChaos@de.wikipedia
var e, i, k, s;
if ( arrange ) {
k = arrange.length - amount;
if ( k > 0 ) {
arrange.sort();
for ( i = 0; i <= k; i++ ) {
e = arrange[ i ];
s = e.split( " " );
delete album[ s[ 1 ] ];
} // for i
}
}
}; // .util.flat()
BAK.util.focus = function ( appoint ) {
// Format ISO 8601 UTC timestamp according to local time
// Precondition:
// appoint -- Date object
// Postcondition:
// Return ISO 8601 string in local time zone
// Uses:
// this
// > mw.user
// > mw.user.options
// >< .cnf.justify
// .format()
// 2014-03-28 PerfektesChaos@de.wikipedia
var r = appoint + " UTC",
s = typeof BAK.cnf.justify,
g;
if ( s !== "boolean" && s !== "number" ) {
BAK.cnf.justify = false;
if ( typeof mw.user === "object" ) {
if ( mw.user.options ) {
s = mw.user.options.get( "timecorrection" );
if ( s ) { // "System|120"
g = /\|?([0-9]+)$/.exec( s );
if ( g ) {
BAK.cnf.justify = parseInt( g[1], 10 );
}
}
}
}
}
if ( BAK.cnf.justify === 0 ) {
r = appoint;
} else if ( typeof BAK.cnf.justify === "number" ) {
g = /^([0-9]+)-([01][0-9])-([0-3][0-9])T([0-2][0-9]):([0-6][0-9]):([0-6][0-9])$/.exec( appoint );
if ( g ) {
r = Date.UTC( parseInt( g[1], 10 ),
parseInt( g[2], 10 ) - 1,
parseInt( g[3], 10 ),
parseInt( g[4], 10 ),
parseInt( g[5], 10 ) + BAK.cnf.justify,
parseInt( g[6], 10 ) );
r = this.format( new Date( r ) );
}
}
return r;
}; // .util.focus()
BAK.util.format = function ( appoint ) {
// Format timestamp according to ISO 8601
// Precondition:
// appoint -- Date object
// Postcondition:
// Return ISO 8601 string in local time zone
// 2012-10-29 PerfektesChaos@de.wikipedia
var r = appoint.getUTCFullYear() + "-",
i = appoint.getUTCMonth() + 1;
if ( i < 10 ) {
i = "0" + i;
}
r = r + i + "-";
i = appoint.getUTCDate();
if ( i < 10 ) {
i = "0" + i;
}
r = r + i + "T";
i = appoint.getUTCHours();
if ( i < 10 ) {
i = "0" + i;
}
r = r + i + ":";
i = appoint.getUTCMinutes();
if ( i < 10 ) {
i = "0" + i;
}
r = r + i + ":";
i = appoint.getUTCSeconds();
if ( i < 10 ) {
i = "0" + i;
}
return r + i;
}; // .util.format()
BAK.family = function () {
// Establish distinguishing page identifier
// Postcondition:
// .pageID is available
// Uses:
// >< .pageID
// < .pageName
// mw.config.get()
// 2014-07-05 PerfektesChaos@de.wikipedia
var env;
if ( ! this.pageID ) {
env = mw.config.get( [ "wgArticleId",
"wgPageName" ] );
this.pageID = env.wgArticleId;
this.pageName = env.wgPageName;
if ( this.pageID === 0 ) {
this.pageID = "0_"
+ this.pageName.replace( /~/, "%7E" );
}
}
}; // .family()
BAK.fast = function () {
// Check sessionStorage for quick page id test on view
// Postcondition:
// Return true iff localStorage should be evaluated
// Uses:
// this
// > .disk.storage
// > window.sessionStorage
// >< .pageID
// >< .pageName
// < .later
// mw.config.get()
// 2013-08-23 PerfektesChaos@de.wikipedia
var r = true,
s = window.sessionStorage.getItem( this.disk.storage ),
q;
if ( s ) {
r = ( s.length > 1 );
if ( r ) {
if ( ! this.pageID ) {
this.pageID = mw.config.get( "wgArticleId" );
}
r = ( s.indexOf( "~" + this.pageID + "~" ) >= 0 );
if ( ! r ) {
if ( s.indexOf( "~0_" ) >= 0 ) {
if ( ! BAK.pageName ) {
BAK.pageName = mw.config.get( "wgPageName" );
}
q = "0_" + BAK.pageName.replace( /~/, "%7E" );
if ( s.indexOf( "~" + q + "~" ) >= 0 ) {
r = true;
this.later = true;
}
}
}
}
}
return r;
}; // .fast()
BAK.filter = function () {
// Cleanup repository, discard old and supernumerous entries
// Precondition:
// .pages is an object
// Uses:
// this
// > .disk.stick
// > .cnf.maxAge
// > .cnf.maxRev
// > .cnf.maxPages
// > .gui.$div
// > .disk.storage
// >< .pages
// >< .now
// >< window.sessionStorage
// .cnf.fetch()
// .util.format()
// .util.flat()
// .gui.fence()
// Requires: ECMA 262-3 § 11.8.5 (string comparison operators)
// 2013-08-23 PerfektesChaos@de.wikipedia
var lazy = true,
store = "~",
hist, page, pid, revs, rid, sift, stamp;
this.cnf.fetch();
if ( this.cnf.maxAge ) {
if ( ! this.now ) {
this.now = new Date();
}
sift = Date.UTC( this.now.getUTCFullYear(),
this.now.getUTCMonth(),
this.now.getUTCDate(),
this.now.getUTCHours() - this.cnf.maxAge,
0,
0 );
sift = this.util.format( new Date( sift ) );
} else {
sift = "1970-01-01T00:00:00";
}
for ( pid in this.pages ) {
page = this.pages[ pid ];
if ( page.newest < sift ) {
delete this.pages[ pid ];
} else {
revs = false;
for ( rid in page ) {
if ( this.disk.stick.indexOf( rid ) < 0 ) {
stamp = page[ rid ].newest;
if ( stamp > sift ) {
stamp = stamp + " " + rid;
if ( revs ) {
revs.push( stamp );
} else {
revs = [ stamp ];
}
} else {
delete page[ rid ];
}
}
} // for rid in page
if ( revs ) {
page = page.newest + " " + pid;
if ( hist ) {
hist.push( page );
} else {
hist = [ page ];
}
this.util.flat( page, this.cnf.maxRev, revs );
store = store + pid + "~";
lazy = false;
} else {
delete this.pages[ pid ];
}
}
} // for pid in .pages
this.util.flat( this.pages, this.cnf.maxPages, hist );
window.sessionStorage.setItem( this.disk.storage, store );
if ( lazy && this.gui.$div ) {
this.gui.fence();
}
}; // .filter()
BAK.finalize = function ( already, add ) {
// Remove trailing whitespace and compare to recent text
// Precondition:
// already -- old text, or empty if new
// add -- new text
// Postcondition:
// Return new text iff significant change, or false
// Requires: JavaScript 1.3 String.charCodeAt
// 2012-10-29 PerfektesChaos@de.wikipedia
var k = add.length,
r = add,
i;
for ( i = k; i > 0; i-- ) {
if ( add.charCodeAt( i - 1 ) > 32 ) {
break; // for i--
}
} // for i--
if ( i > 1 ) {
if ( i < k ) {
r = add.substr( 0, i );
}
if ( already ) {
if ( i === already.length ) {
if ( r === already ) {
r = false;
}
}
}
} else {
r = false;
}
return r;
}; // .finalize()
BAK.find = function () {
// Launch API query for revisions of the same user
// Uses:
// this
// > .pageID
// > .later
// > .pageName
// mw.Api
// mw.util.wikiUrlencode()
// mw.config.get()
// (.founder)
// (.found)
// 2015-07-07 PerfektesChaos@de.wikipedia
var q = new mw.Api(),
w = { action: "query",
"continue": "", // TEMP ??
pageids: this.pageID,
prop: "revisions",
rvlimit: 3,
rvuser: mw.util.wikiUrlencode(
mw.config.get( "wgUserName" ) )
};
if ( this.later ) {
delete w.pageids;
w.titles = this.pageName;
q.get( w ).done( this.founder );
} else {
q.get( w ).done( this.found );
}
}; // .find()
BAK.first = function () {
// Opening edit page; check for pending attempts
// Precondition:
// Page in edit::edit mode
// Uses:
// this
// > .pages
// > mw.user
// > mw.user.options
// > .pageID
// < .gui.leading
// < .livePreview
// .disk.fetch()
// .find()
// jQuery.bind()
// mw.hook()
// (.fresh)
// 2019-06-17 PerfektesChaos@de.wikipedia
this.$editform = false;
this.disk.fetch();
if ( this.pages ) {
if ( this.pages[ this.pageID ] ) {
this.find();
}
}
if ( typeof mw.user === "object" ) {
if ( mw.user.options &&
mw.user.options.get( "uselivepreview" ) ) {
this.livePreview = true;
$( mw ).bind( "LivePreviewDone", this.fresh );
}
}
this.gui.leading = true;
mw.hook( "wikipage.content" ).add( this.fresh );
}; // .first()
BAK.fixed = function ( apply ) {
// Remove current page revision from storage and GUI
// Precondition:
// apply -- revision ID
// Uses:
// this
// > .gui.$top
// > .pageID
// >< .pages
// < .disk.launch
// .flush()
// .gui.fence()
// .gui.face()
// 2012-11-04 PerfektesChaos@de.wikipedia
var p;
this.gui.$top.find( "#autoBackupR" + apply ).remove();
if ( this.pages ) {
p = this.pages[ BAK.pageID ];
if ( p ) {
if ( p[ apply ] ) {
delete p[ apply ];
this.disk.launch = true;
this.flush();
if ( ! this.pages ) {
this.gui.fence( false );
} else if ( ! this.pages[ BAK.pageID ] ) {
this.gui.face( false );
}
}
}
}
}; // .fixed()
BAK.flush = function () {
// Write repository
// Uses:
// this
// > .disk.launch
// > .pages
// .filter()
// .disk.flush()
// 2012-10-29 PerfektesChaos@de.wikipedia
if ( this.disk.launch ) {
if ( this.pages ) {
this.filter();
}
this.disk.flush();
}
}; // .flush()
BAK.folder = function () {
// API: Display list of links to all other pages on current page
// Uses:
// > .gui.$div
// > .gui.$msg
// >< .cnf.self
// .cnf.feature()
// jQuery().prepend()
// .gui.face()
// .gui.fill()
// .gui.filter()
// .gui.full()
// Remark: May be used as event handler -- 'this' is not BAK
// 2012-11-30 PerfektesChaos@de.wikipedia
BAK.gui.face();
if ( ! BAK.gui.$msg ) {
if ( ! BAK.cnf.self ) {
BAK.cnf.self = BAK.cnf.feature( "BAKself" );
}
BAK.gui.$div.prepend( "<h2>" + BAK.cnf.self + "</h2>" );
}
BAK.gui.fill();
BAK.gui.filter();
BAK.gui.full();
}; // .folder()
BAK.follow = function () {
// Check whether current page displays saved edit
// Precondition:
// Page in view mode
// Uses:
// this
// > .pages
// > .later
// > .pageID
// < .revID
// .disk.fetch()
// .find()
// mw.config.get()
// .gui.flag()
// 2012-11-30 PerfektesChaos@de.wikipedia
var h, i, p;
this.disk.fetch();
if ( this.later ) {
this.find();
} else if ( this.pages ) {
p = this.pages[ this.pageID ];
if ( p ) {
this.revID = mw.config.get( "wgCurRevisionId" );
for ( h in p ) {
i = parseInt( h, 10 );
if ( i ) {
if ( this.revID > i ) {
this.find();
break; // for h
} else if ( this.revID === i ) {
this.gui.flag( "pending", "ALL" );
break; // for h
}
}
} // for h in p
}
}
}; // .follow()
BAK.found = function ( arrived ) {
// Postprocess in page view after ajax request
// Precondition:
// arrived -- JSON result of ajax query
// Previously it has been detected that revID is open snapshot.
// Uses:
// > .pageID
// > .revID
// >< .pages
// < .disk.launch
// .flush()
// Remark: Used as event handler -- 'this' is not BAK
// 2012-10-29 PerfektesChaos@de.wikipedia
var query = ( typeof arrived === "object" ),
learnt = false,
i;
if ( query ) {
query = arrived.query;
if ( query ) {
query = query.pages[ BAK.pageID ];
if ( query ) {
query = query.revisions;
if ( query ) {
for ( i = 0; i < query.length; i++ ) {
if ( query[i].revid === BAK.revID ) {
learnt = true;
delete BAK.pages[ BAK.pageID ];
BAK.disk.launch = true;
break; // for i
}
} // for i
}
}
}
}
BAK.flush();
if ( ! learnt ) {
BAK.gui.flag( "pending", "ALL" );
}
}; // .found()
BAK.founder = function ( arrived ) {
// Postprocess a created page in page view after ajax request
// Precondition:
// arrived -- JSON result of ajax query
// Previously it has been detected revID=0 was open snapshot.
// Uses:
// > .pageName
// >< .pages
// < .pageID
// < .disk.launch
// .flush()
// Remark: Used as event handler -- 'this' is not BAK
// 2012-12-02 PerfektesChaos@de.wikipedia
var query = ( typeof arrived === "object" ),
learnt = false;
if ( query ) {
query = arrived.query;
if ( query ) {
query = query.pages[ BAK.pageID ];
if ( query ) {
BAK.pageID = "0_"
+ BAK.pageName.replace( /~/, "%7E" );
delete BAK.pages[ BAK.pageID ];
BAK.disk.launch = true;
learnt = true;
}
}
}
BAK.flush();
if ( ! learnt ) {
BAK.gui.flag( "pending", "ALL" );
}
}; // .founder()
BAK.fresh = function () {
// API: Add snapshot to storage if content changed
// Precondition:
// Start of preview/diff mode, or time-triggered
// Uses:
// > .pageID
// > .pageName;
// > .cnf.maxHist
// > .cnf.msec
// >< .timeoutID
// < .revID
// < .now
// < .disk.launch
// .gui.feed()
// .family()
// mw.config.get()
// .disk.fetch()
// .finalize()
// .util.format()
// .cnf.fetch()
// .flush()
// Remark: Used as event handler -- 'this' is not BAK
// 2013-02-17 PerfektesChaos@de.wikipedia
var shot = BAK.gui.feed(),
page, revs, stamp;
if ( shot ) {
BAK.family();
BAK.revID = mw.config.get( "wgCurRevisionId" );
if ( ! BAK.pages ) {
BAK.disk.fetch();
}
if ( ! BAK.pages ) {
BAK.pages = { };
}
if ( ! BAK.pages[ BAK.pageID ] ) {
BAK.pages[ BAK.pageID ] = { };
}
page = BAK.pages[ BAK.pageID ];
if ( ! page[ BAK.revID ] ) {
page[ BAK.revID ] = { };
}
revs = page[ BAK.revID ].history;
if ( revs ) {
shot = BAK.finalize( revs[0][1], shot );
if ( shot ) {
BAK.now = new Date();
stamp = BAK.util.format( BAK.now );
BAK.cnf.fetch();
if ( revs.length >= BAK.cnf.maxHist - 1 ) {
revs.pop();
}
revs.unshift( [ stamp, shot ] );
}
} else {
shot = BAK.finalize( false, shot );
if ( shot ) {
BAK.now = new Date();
stamp = BAK.util.format( BAK.now );
revs = [ [ stamp, shot ] ];
}
}
if ( shot ) {
page[ BAK.revID ].history = revs;
page[ BAK.revID ].newest = stamp;
page.newest = stamp;
page.subject = BAK.pageName;
BAK.pages[ BAK.pageID ] = page;
BAK.disk.launch = true;
BAK.flush();
}
if ( BAK.cnf.msec ) {
if ( BAK.timeoutID ) {
window.clearTimeout( BAK.timeoutID );
}
BAK.timeoutID = window.setTimeout( BAK.fresh,
BAK.cnf.msec );
}
}
}; // .fresh()
BAK.further = function () {
// Additional triggers in edit mode, to be called only once
// Uses:
// this
// > .gui.$editform
// > .cnf.msec
// >< .learnt
// .gui.further()
// .cnf.fetch()
// (.fresh)
// 2012-10-29 PerfektesChaos@de.wikipedia
if ( ! this.learnt ) { // only once
this.learnt = true;
if ( this.gui.$editform ) { // editing
this.gui.further();
this.cnf.fetch();
if ( this.cnf.msec ) {
window.setTimeout( this.fresh, this.cnf.msec );
}
}
}
}; // .further()
BAK.fire = function () {
// Start page processing; check whether situation is interesting
// Uses:
// > .disk.self
// < .disk.storage
// < .learn
// < .gui.leading
// mw.config.get()
// .follow()
// mw.util.getParamValue()
// mw.hook()
// (.firing)
// Remark: Used as event handler -- 'this' is not BAK
// 2017-01-04 PerfektesChaos@de.wikipedia
var env = mw.config.get( [ "wgAction",
"wgIsArticle",
"wgUserName" ] );
BAK.disk.storage = BAK.disk.self
+ " " + env.wgUserName;
if ( env.wgIsArticle ) {
if ( env.wgAction === "view" &&
BAK.fast() ) {
BAK.follow();
}
} else {
BAK.start = mw.util.getParamValue( "action" );
if ( BAK.start ) {
BAK.learn = true;
if ( "|edit|submit|".indexOf( BAK.start ) > 0 ) {
mw.hook( "wikipage.content" ).add( BAK.firing );
}
}
}
}; // .fire()
BAK.firing = function ( $all ) {
// Start content processing
// Precondition:
// $all -- mw.util.$content
// Uses:
// > .start
// < .gui.leading
// .fast()
// .fresh()
// .further()
// .first()
// Remark: Used as event handler -- 'this' is not BAK
// 2019-07-01 PerfektesChaos@de.wikipedia
BAK.$page = $all;
switch ( BAK.start ) {
case "submit" :
BAK.gui.leading = true;
BAK.fresh();
BAK.further();
break;
case "edit" :
BAK.first();
BAK.further();
} // switch .start
}; // .firing()
function first() {
// Initiate resource loading
// Uses:
// > .type
// < .error
// mw.loader.getState()
// mw.loader.using()
// mw.loader.state()
// (.fire)
// 2018-08-24 PerfektesChaos@de.wikipedia
var signature = "ext.gadget." + BAK.type,
rls;
if ( mw.loader.getState( signature ) !== "ready" ) {
rls = { };
rls[ signature ] = "ready";
mw.loader.state( rls );
if ( mw.config.get( "wgNamespaceNumber" ) >= 0 ) {
mw.loader.using( [ "user",
"mediawiki.api",
"mediawiki.user",
"mediawiki.util" ],
BAK.fire );
}
}
} // first()
first();
}( window.mediaWiki, window.jQuery ) );
// Emacs
// Local Variables:
// coding: utf-8-dos
// fill-column: 80
// End:
/// EOF </nowiki> autoBackup/d.js