<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh">
	<id>https://zybkcn.com/w/index.php?action=history&amp;feed=atom&amp;title=MediaWiki%3AGadget-SettingsManager.js</id>
	<title>MediaWiki:Gadget-SettingsManager.js - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="https://zybkcn.com/w/index.php?action=history&amp;feed=atom&amp;title=MediaWiki%3AGadget-SettingsManager.js"/>
	<link rel="alternate" type="text/html" href="https://zybkcn.com/w/index.php?title=MediaWiki:Gadget-SettingsManager.js&amp;action=history"/>
	<updated>2026-06-13T18:23:51Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.45.3</generator>
	<entry>
		<id>https://zybkcn.com/w/index.php?title=MediaWiki:Gadget-SettingsManager.js&amp;diff=26294&amp;oldid=prev</id>
		<title>入我相思门：​创建页面，内容为“/**  * Localization required. User:Liangent 2013年4月8日 (一) 10:20 (UTC)  *  * :commons:MediaWiki:Gadget-SettingsManager.js  * Managing user preferences of scripts  * Managing gadgets and gadget preferences  *  * Use it for good, not for evil.  *  * @author Rillke, 2012  * @license GPL v.3  * &lt;nowiki&gt;  */   // List the global variables for jsHint-Validation. // Scheme: globalVariable:allowOverwriting[, globalVariable:allowOverwriting][, globalVaria…”</title>
		<link rel="alternate" type="text/html" href="https://zybkcn.com/w/index.php?title=MediaWiki:Gadget-SettingsManager.js&amp;diff=26294&amp;oldid=prev"/>
		<updated>2022-12-05T11:21:23Z</updated>

		<summary type="html">&lt;p&gt;创建页面，内容为“&lt;span class=&quot;autocomment&quot;&gt;*  * Localization required. &amp;#91;&amp;#91;User:Liangent&amp;#93;&amp;#93; 2013年4月8日 (一) 10:20 (UTC)  *  * &amp;#91;&amp;#91;:commons:MediaWiki:Gadget-SettingsManager.js&amp;#93;&amp;#93;  * Managing user preferences of scripts  * Managing gadgets and gadget preferences  *  * Use it for good, not for evil.  *  * @author Rillke, 2012  * @license GPL v.3  * &amp;lt;nowiki&amp;gt;：​&lt;/span&gt;   // List the global variables for jsHint-Validation. // Scheme: globalVariable:allowOverwriting[, globalVariable:allowOverwriting][, globalVaria…”&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;/**&lt;br /&gt;
 * Localization required. [[User:Liangent]] 2013年4月8日 (一) 10:20 (UTC)&lt;br /&gt;
 *&lt;br /&gt;
 * [[:commons:MediaWiki:Gadget-SettingsManager.js]]&lt;br /&gt;
 * Managing user preferences of scripts&lt;br /&gt;
 * Managing gadgets and gadget preferences&lt;br /&gt;
 *&lt;br /&gt;
 * Use it for good, not for evil.&lt;br /&gt;
 *&lt;br /&gt;
 * @author Rillke, 2012&lt;br /&gt;
 * @license GPL v.3&lt;br /&gt;
 * &amp;lt;nowiki&amp;gt;&lt;br /&gt;
 */&lt;br /&gt;
 &lt;br /&gt;
// List the global variables for jsHint-Validation.&lt;br /&gt;
// Scheme: globalVariable:allowOverwriting[, globalVariable:allowOverwriting][, globalVariable:allowOverwriting]&lt;br /&gt;
/*global jQuery:false, mediaWiki:false*/&lt;br /&gt;
&lt;br /&gt;
// Set jsHint-options.&lt;br /&gt;
/*jshint forin:true, noarg:true, noempty:true, eqeqeq:true, bitwise:true, strict:true, undef:true, curly:false, browser:true*/&lt;br /&gt;
&lt;br /&gt;
( function ( $, mw, undefined ) {&lt;br /&gt;
&amp;quot;use strict&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
* Refresh edit token&lt;br /&gt;
*&lt;br /&gt;
* @example&lt;br /&gt;
*      refreshToken( function() { doGoodStuff.retry(); } );&lt;br /&gt;
*&lt;br /&gt;
* @param cb {Function} Callback function. The first argument supplied is whether the operation succeeded.&lt;br /&gt;
* @context {closure} private function&lt;br /&gt;
* @return {Object} a jQuery deferred-object-queue&lt;br /&gt;
*/&lt;br /&gt;
var refreshToken = function(cb) {&lt;br /&gt;
	var mwa = new mw.Api(),&lt;br /&gt;
		apiDef = mwa.get( {&lt;br /&gt;
			action: &amp;#039;query&amp;#039;,&lt;br /&gt;
			meta: &amp;#039;tokens&amp;#039;,&lt;br /&gt;
			type: &amp;#039;csrf&amp;#039;&lt;br /&gt;
		} );&lt;br /&gt;
		&lt;br /&gt;
	apiDef.done(function(result) {&lt;br /&gt;
		if (!result.query || !result.query.tokens) return cb( false, &amp;#039;wrong-response&amp;#039; );&lt;br /&gt;
		mw.user.tokens.set( &amp;#039;csrfToken&amp;#039;, result.query.tokens.csrftoken );&lt;br /&gt;
		cb( true );&lt;br /&gt;
	});&lt;br /&gt;
	apiDef.fail(function(code, result) {&lt;br /&gt;
		if (!result.query || !result.query.tokens) return cb( false, code );&lt;br /&gt;
	});&lt;br /&gt;
	return apiDef;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var firstItem = function(o) { &lt;br /&gt;
	for (var i in o) {&lt;br /&gt;
		if (o.hasOwnProperty( i )) { &lt;br /&gt;
			return o[i]; &lt;br /&gt;
		} &lt;br /&gt;
	} &lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var valByString = function(identifier) {&lt;br /&gt;
	var arr = identifier.split( &amp;#039;.&amp;#039; ),&lt;br /&gt;
		lenArr = arr.length,&lt;br /&gt;
		i,&lt;br /&gt;
		elemArr,&lt;br /&gt;
		objCurrent = window;&lt;br /&gt;
		&lt;br /&gt;
	for (i = 0; i &amp;lt; lenArr; i++) {&lt;br /&gt;
		elemArr = arr[i];&lt;br /&gt;
		objCurrent = objCurrent[elemArr];&lt;br /&gt;
	}&lt;br /&gt;
	return objCurrent;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var sm = {&lt;br /&gt;
	version: &amp;#039;0.1.0.1&amp;#039;,&lt;br /&gt;
	errorPrefix: &amp;quot;SettingsWizard encountered a problem. We regret the inconvenience. &amp;quot;,&lt;br /&gt;
	/**&lt;br /&gt;
	* Constructor-method. Returns an option-object you should perform the actions on.&lt;br /&gt;
	*&lt;br /&gt;
	* @example&lt;br /&gt;
	*      var opt = mw.libs.settingsManager.option( { optionName: &amp;#039;CatALotOptions&amp;#039;, value: { watchCopy: false, watchRemove: false } } );&lt;br /&gt;
	*      // Save the options we&amp;#039;ve set before and make the script triggering events on the document, you can listen to&lt;br /&gt;
	*      opt.save( $(document), &amp;#039;CatALotSaveProgress&amp;#039; );&lt;br /&gt;
	*      // or, use the deferred-object returned:&lt;br /&gt;
	*      opt.save().done(function(msg, status, jsFile) { &lt;br /&gt;
	*          alert( msg );&lt;br /&gt;
	*      }).status(function(msg, status, jsFile) { &lt;br /&gt;
	*          console.log( &amp;#039;settings progress&amp;gt;&amp;#039; + msg );&lt;br /&gt;
	*      });&lt;br /&gt;
	*&lt;br /&gt;
	* @param specsIn {Object} specifications passed in. List of defaults (cf. specs) follows.&lt;br /&gt;
	* @context {mw.libs.settingsManager}&lt;br /&gt;
	* @return {Object} option-object you can use for performing actions on.&lt;br /&gt;
	*/&lt;br /&gt;
	option: function(specsIn) {&lt;br /&gt;
		// List of defaults:&lt;br /&gt;
		var specs = {&lt;br /&gt;
			// The global name the option will be saved under&lt;br /&gt;
			// This can be also something like &amp;quot;mw.settingsOfToolX&amp;quot;&lt;br /&gt;
			optionName: &amp;#039;&amp;#039;,&lt;br /&gt;
			// The position where to save them. By default options are&lt;br /&gt;
			// saved at the user&amp;#039;s common.js or &amp;lt;skin&amp;gt;.js (e.g. vector.js)&lt;br /&gt;
			// specify other locations like &amp;quot;settingsOfToolX&amp;quot; --&amp;gt; &amp;quot;User:Example/prefs/settingsOfToolX.js&amp;quot;&lt;br /&gt;
			saveAt: false,&lt;br /&gt;
			// By default the option is not enclosed in a comment-block&lt;br /&gt;
			// Comment-blocks are recommended for larger configurations&lt;br /&gt;
			// specifies the signature that will be used for the enclosing comments&lt;br /&gt;
			// blockSettingsOfToolX --&amp;gt; //blockSettingsOfToolX///////////////////////&lt;br /&gt;
			// (ignored when saveAt is set)&lt;br /&gt;
			encloseSignature: false,&lt;br /&gt;
			// Specify additional block comments added below the signature&lt;br /&gt;
			// Should be something that explains what the following JSON does or is good for&lt;br /&gt;
			// Recommended line-length for consistent alignment: 48 chars&lt;br /&gt;
			encloseBlock: false,&lt;br /&gt;
			// If no own location for saving the option is used (options that must be&lt;br /&gt;
			// available while loading the script should not be saved to a separate file while &lt;br /&gt;
			// complex options should), if the RegExp will have a match on either the common.js&lt;br /&gt;
			// or the &amp;lt;skin&amp;gt;.js, and this option is not saved yet to another .js, the option&lt;br /&gt;
			// will be saved to this js-file. In case the option is not saved yet and there is&lt;br /&gt;
			// no RegExp supplied or it did not match, the option will be saved to the larger&lt;br /&gt;
			// JavaScript&lt;br /&gt;
			triggerSaveAt: false,&lt;br /&gt;
			// Should the new content be insered in front of the match by triggerSaveAt&lt;br /&gt;
			// If none of the following options is specified, the new content &lt;br /&gt;
			// will be appended to the script&lt;br /&gt;
			insertBeforeTrigger: false,&lt;br /&gt;
			insertAfterTrigger: false,&lt;br /&gt;
			replaceTrigger: false,&lt;br /&gt;
			// Finally the option&amp;#039;s value. Objects are possible. They will be automatically&lt;br /&gt;
			// transformed into a JSON-string&lt;br /&gt;
			value: undefined,&lt;br /&gt;
			// Edit summary to use while saving the JavaScript&lt;br /&gt;
			editSummary: &amp;quot;&amp;quot;&lt;br /&gt;
		};&lt;br /&gt;
		if (!specsIn) throw new Error(sm.errorPrefix + &amp;quot;Data to save or retrieve was not supplied by the script using SettingsWizard.&amp;quot;);&lt;br /&gt;
		if (!specsIn.optionName &amp;amp;&amp;amp; !specsIn.saveAt) throw new Error(sm.errorPrefix + &amp;quot;The options\&amp;#039;s name was not supplied by the script using SettingsWizard.&amp;quot;);&lt;br /&gt;
		$.extend( true, specs, specsIn );&lt;br /&gt;
		&lt;br /&gt;
		// Prepare variables we need later&lt;br /&gt;
		var nsUser   = mw.config.get(&amp;#039;wgFormattedNamespaces&amp;#039;)[2],&lt;br /&gt;
			skin     = mw.config.get(&amp;#039;skin&amp;#039;),&lt;br /&gt;
			user     = mw.config.get(&amp;#039;wgUserName&amp;#039;),&lt;br /&gt;
			skinJS   = [nsUser, &amp;#039;:&amp;#039;, user, &amp;#039;/&amp;#039;, skin, &amp;#039;.js&amp;#039;].join(&amp;#039;&amp;#039;),&lt;br /&gt;
			commonJS = [nsUser, &amp;#039;:&amp;#039;, user, &amp;#039;/&amp;#039;,&amp;#039;common&amp;#039;, &amp;#039;.js&amp;#039;].join(&amp;#039;&amp;#039;);&lt;br /&gt;
		&lt;br /&gt;
		// Event-handler system&lt;br /&gt;
		var $el, evt, jsFiles, process, $progress = new $.Deferred(), customJS;&lt;br /&gt;
		var triggerEvt = function(any) {&lt;br /&gt;
			return (evt &amp;amp;&amp;amp; $el &amp;amp;&amp;amp; $el instanceof jQuery &amp;amp;&amp;amp; $el.triggerHandler( evt, Array.prototype.slice.call( arguments, 0 ) ));&lt;br /&gt;
		};&lt;br /&gt;
		&lt;br /&gt;
		process = {&lt;br /&gt;
			updateVars: function() {&lt;br /&gt;
				// Reset variables that could be polluted&lt;br /&gt;
				jsFiles = [];&lt;br /&gt;
				$progress = new $.Deferred();&lt;br /&gt;
				customJS = [nsUser, &amp;#039;:&amp;#039;, user, &amp;#039;/prefs/&amp;#039;, specs.saveAt, &amp;#039;.js&amp;#039;].join(&amp;#039;&amp;#039;);&lt;br /&gt;
			},&lt;br /&gt;
			start: function() {&lt;br /&gt;
				this.updateVars();&lt;br /&gt;
				&lt;br /&gt;
				// Subscribe to any event: We want to know everything :-)&lt;br /&gt;
				$progress.then( triggerEvt, triggerEvt, triggerEvt );&lt;br /&gt;
				&lt;br /&gt;
				// Always async&lt;br /&gt;
				setTimeout( $.proxy( this.getScripts, this ), 1 );&lt;br /&gt;
				&lt;br /&gt;
				return $progress;&lt;br /&gt;
			},&lt;br /&gt;
			getScripts: function() {&lt;br /&gt;
				var i, len;&lt;br /&gt;
				&lt;br /&gt;
				$progress.notify( &amp;quot;Preparing&amp;quot;, 1 );&lt;br /&gt;
				&lt;br /&gt;
				// First, we need something to work on/ edit token, etc. - request the JavaScript(s)&lt;br /&gt;
				if (specs.saveAt) {&lt;br /&gt;
					jsFiles.push( sm.script( customJS ) );&lt;br /&gt;
				} else {&lt;br /&gt;
					jsFiles.push( sm.script( skinJS ) );&lt;br /&gt;
					jsFiles.push( sm.script( commonJS ) );&lt;br /&gt;
				}&lt;br /&gt;
				len = jsFiles.length;&lt;br /&gt;
				for (i = 0; i &amp;lt; len; i++) {&lt;br /&gt;
					var jsFile = jsFiles[i];&lt;br /&gt;
					jsFile.fetchText( process.gotJS, process.gotJSErr );&lt;br /&gt;
					$progress.notify( &amp;quot;Requesting &amp;quot; + jsFile.getSource(), Math.round( (i+1)*(9/len) ) + 1, jsFile );&lt;br /&gt;
				}&lt;br /&gt;
				return $progress;&lt;br /&gt;
			},&lt;br /&gt;
			gotJS: function(jsFile, r){&lt;br /&gt;
				jsFile.gotContent = true;&lt;br /&gt;
				&lt;br /&gt;
				var i, len = jsFiles.length, pendings = 0;&lt;br /&gt;
				for (i = 0; i &amp;lt; len; i++) {&lt;br /&gt;
					if (!jsFiles[i].gotContent) {&lt;br /&gt;
						pendings++;&lt;br /&gt;
					}&lt;br /&gt;
				}&lt;br /&gt;
				$progress.notify( &amp;quot;Got &amp;quot; + jsFile.getSource() + &amp;#039;. File length: &amp;#039; + jsFile.get().length + &amp;#039; characters.&amp;#039; , Math.round( (len - pendings)*(9/len) ) + 10, jsFile );&lt;br /&gt;
				&lt;br /&gt;
				if (pendings) return;&lt;br /&gt;
				process.process();&lt;br /&gt;
			},&lt;br /&gt;
			gotJSErr: function(jsFile) {&lt;br /&gt;
				$progress.reject( &amp;quot;Failed. Could not retrieve &amp;quot; + jsFile.getSource(), -1, jsFile );&lt;br /&gt;
			},&lt;br /&gt;
			getStartBlock: function(sig) {&lt;br /&gt;
				// String concat is sloooow&lt;br /&gt;
				return &amp;#039;//&amp;#039; + sig + new Array(48 - 2 - sig.length + 1).join(&amp;#039;/&amp;#039;);&lt;br /&gt;
			},&lt;br /&gt;
			getEndBlock: function(sig) {&lt;br /&gt;
				return new Array(48 - 2 - 3 - sig.length + 1).join(&amp;#039;/&amp;#039;) + sig + &amp;#039;End&amp;#039; + &amp;#039;//&amp;#039;;&lt;br /&gt;
			},&lt;br /&gt;
			getBlockRegExp: function(sig) {&lt;br /&gt;
				var escSig = process.escapeRE(sig);&lt;br /&gt;
				return new RegExp(&amp;#039;\\n?\\n?\\/\\/&amp;#039; + escSig + &amp;#039;(?:.|\\n)*&amp;#039; + escSig + &amp;#039;End\\/\\/&amp;#039;, &amp;#039;g&amp;#039;);&lt;br /&gt;
			},&lt;br /&gt;
			escapeRE: function(string) {&lt;br /&gt;
				string = $.escapeRE(string);&lt;br /&gt;
				&lt;br /&gt;
				var specials = [&amp;#039;t&amp;#039;, &amp;#039;n&amp;#039;, &amp;#039;v&amp;#039;, &amp;#039;0&amp;#039;, &amp;#039;f&amp;#039;];&lt;br /&gt;
				$.each(specials, function(i, s) {&lt;br /&gt;
					var rx = new RegExp(&amp;#039;\\&amp;#039;+s, &amp;#039;g&amp;#039;);&lt;br /&gt;
					string = string.replace(rx, &amp;#039;\\&amp;#039;+s);&lt;br /&gt;
				});&lt;br /&gt;
				return string;&lt;br /&gt;
			},&lt;br /&gt;
			getVariableRegExp: function(varName) {&lt;br /&gt;
				var escVar = process.escapeRE(varName);&lt;br /&gt;
				return {&lt;br /&gt;
					varRE: new RegExp(&amp;#039;\\s*(?:var\\s+|window\\.)?&amp;#039; + escVar + &amp;#039;\\s*=.+&amp;#039;, &amp;#039;g&amp;#039;),&lt;br /&gt;
					// Throw a warning if the last char of the line is a &amp;quot;+&amp;quot; , &amp;quot;{&amp;quot;, &amp;quot;(&amp;quot; or &amp;quot;,&amp;quot;&lt;br /&gt;
					varWarnRE: new RegExp(&amp;#039;\\s*(?:var\\s+|window\\.)?&amp;#039; + escVar + &amp;#039;\\s*=.+(?:\\n?\\s*[\\,\\+\\{\\(])\\s*\\n&amp;#039;)&lt;br /&gt;
				};&lt;br /&gt;
			},&lt;br /&gt;
			process: function() {&lt;br /&gt;
				var JSONVal = $.toJSON( specs.value ),&lt;br /&gt;
					sig = specs.encloseSignature,&lt;br /&gt;
					tsa = specs.triggerSaveAt,&lt;br /&gt;
					opn = specs.optionName,&lt;br /&gt;
					jsFile, i, len = jsFiles.length,&lt;br /&gt;
					plainJSON = !opn &amp;amp;&amp;amp; !!jsFile,&lt;br /&gt;
					oldText, newText, hadMatch;&lt;br /&gt;
				&lt;br /&gt;
				if (opn) {&lt;br /&gt;
					// No semicolon for valid JSON!&lt;br /&gt;
					JSONVal = &amp;#039;window.&amp;#039; + opn + &amp;#039; = &amp;#039; + JSONVal + &amp;#039;;&amp;#039;;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				if (!plainJSON) JSONVal = ((specs.encloseBlock &amp;amp;&amp;amp; (&amp;#039;\n&amp;#039; + specs.encloseBlock)) || &amp;#039;&amp;#039;) + JSONVal;&lt;br /&gt;
				&lt;br /&gt;
				if (sig &amp;amp;&amp;amp; !plainJSON) JSONVal = process.getStartBlock( sig ) + JSONVal + &amp;#039;\n&amp;#039; + process.getEndBlock( sig );&lt;br /&gt;
				&lt;br /&gt;
				JSONVal = &amp;#039;\n\n&amp;#039; + JSONVal;&lt;br /&gt;
				&lt;br /&gt;
				// Fine, we&amp;#039;ve constructed everything we&amp;#039;ll need. Now look up where to insert.&lt;br /&gt;
				// Looking for signature&lt;br /&gt;
				if (sig) {&lt;br /&gt;
					var reBl = process.getBlockRegExp( sig );&lt;br /&gt;
						&lt;br /&gt;
					for (i = 0; i &amp;lt; len; i++) {&lt;br /&gt;
						jsFile = jsFiles[i];&lt;br /&gt;
						oldText = jsFile.get();&lt;br /&gt;
						newText = oldText.replace( reBl, JSONVal );&lt;br /&gt;
						if (reBl.test( oldText )) {&lt;br /&gt;
							$progress.notify( &amp;quot;Replacing text enclosed by signature &amp;quot; + jsFile.getSource(), 25, jsFile );&lt;br /&gt;
							process.save( jsFile.set( newText ) );&lt;br /&gt;
							hadMatch = true;&lt;br /&gt;
						}&lt;br /&gt;
					}&lt;br /&gt;
				}&lt;br /&gt;
				if (hadMatch) return;&lt;br /&gt;
				&lt;br /&gt;
				// Looking for variable-name&lt;br /&gt;
				if (opn) {&lt;br /&gt;
					var vre = process.getVariableRegExp( opn ),&lt;br /&gt;
						warnFile;&lt;br /&gt;
					&lt;br /&gt;
					for (i = 0; i &amp;lt; len; i++) {&lt;br /&gt;
						jsFile = jsFiles[i];&lt;br /&gt;
						oldText = jsFile.get();&lt;br /&gt;
						&lt;br /&gt;
						if (vre.varWarnRE.test(oldText)) {&lt;br /&gt;
							// WARNING!!!&lt;br /&gt;
							$progress.notify( &amp;quot;Unable to remove config from &amp;quot; + jsFile.getSource(), -2, jsFile );&lt;br /&gt;
							warnFile = jsFile;&lt;br /&gt;
						} else {&lt;br /&gt;
							newText = oldText.replace( vre.varRE, JSONVal );&lt;br /&gt;
							if (vre.varRE.test( oldText )) {&lt;br /&gt;
								$progress.notify( &amp;quot;Replacing variable &amp;quot; + jsFile.getSource(), 25, jsFile );&lt;br /&gt;
								process.save( jsFile.set( newText ) );&lt;br /&gt;
								hadMatch = true;&lt;br /&gt;
							}&lt;br /&gt;
						}&lt;br /&gt;
						// Only append in case of warning if it was not added to another file&lt;br /&gt;
						if (warnFile &amp;amp;&amp;amp; !hadMatch) {&lt;br /&gt;
							$progress.notify( &amp;quot;Appending variable after warning to &amp;quot; + jsFile.getSource(), 25, jsFile );&lt;br /&gt;
							process.save( warnFile.set( oldText + JSONVal ) );&lt;br /&gt;
							hadMatch = true;&lt;br /&gt;
						}&lt;br /&gt;
					}&lt;br /&gt;
				}&lt;br /&gt;
				if (hadMatch) return;&lt;br /&gt;
				&lt;br /&gt;
				// If it&amp;#039;s just JSON, replace the whole thingy&lt;br /&gt;
				if (!opn &amp;amp;&amp;amp; specs.saveAt) {&lt;br /&gt;
					jsFile = jsFiles[0];&lt;br /&gt;
					$progress.notify( &amp;quot;Replacing whole content of &amp;quot; + jsFile.getSource(), 25, jsFile );&lt;br /&gt;
					process.save( jsFile.set( JSONVal ) );&lt;br /&gt;
					hadMatch = true;&lt;br /&gt;
				}&lt;br /&gt;
				if (hadMatch) return;&lt;br /&gt;
				&lt;br /&gt;
				// Looking whether supplied RegExp can find something&lt;br /&gt;
				if (tsa) {&lt;br /&gt;
					var searchMatch,&lt;br /&gt;
						triggerLen = 0;&lt;br /&gt;
					&lt;br /&gt;
					for (i = 0; i &amp;lt; len; i++) {&lt;br /&gt;
						jsFile = jsFiles[i];&lt;br /&gt;
						oldText = jsFile.get();&lt;br /&gt;
						&lt;br /&gt;
						searchMatch = oldText.search( tsa );&lt;br /&gt;
						if (-1 !== searchMatch) {&lt;br /&gt;
							if (specs.insertBeforeTrigger) {&lt;br /&gt;
								$progress.notify( &amp;quot;Inserting before pattern in &amp;quot; + jsFile.getSource(), 25, jsFile );&lt;br /&gt;
								jsFile.set( oldText.slice( 0, searchMatch ) + JSONVal + oldText.slice( searchMatch ) );&lt;br /&gt;
							} else if (specs.insertAfterTrigger) {&lt;br /&gt;
								triggerLen = oldText.match( tsa )[0].length;&lt;br /&gt;
								$progress.notify( &amp;quot;Inserting after pattern in &amp;quot; + jsFile.getSource(), 25, jsFile );&lt;br /&gt;
								jsFile.set( oldText.slice( 0, searchMatch + triggerLen ) + JSONVal + oldText.slice( searchMatch + triggerLen ) );&lt;br /&gt;
							} else if (specs.replaceTrigger) {&lt;br /&gt;
								$progress.notify( &amp;quot;Replacing pattern with new content in &amp;quot; + jsFile.getSource(), 25, jsFile );&lt;br /&gt;
								jsFile.set( oldText.replace( tsa, JSONVal ) );&lt;br /&gt;
							} else {&lt;br /&gt;
								$progress.notify( &amp;quot;Found pattern, appending to &amp;quot; + jsFile.getSource(), 25, jsFile );&lt;br /&gt;
								jsFile.set( oldText + &amp;#039;\n//&amp;lt;nowiki&amp;gt;&amp;#039; + JSONVal + &amp;#039;\n//&amp;lt;\/nowiki&amp;gt;&amp;#039; );&lt;br /&gt;
							}&lt;br /&gt;
							process.save( jsFile );&lt;br /&gt;
							hadMatch = true;&lt;br /&gt;
							break;&lt;br /&gt;
						}&lt;br /&gt;
					}&lt;br /&gt;
				}&lt;br /&gt;
				if (hadMatch) return;&lt;br /&gt;
				&lt;br /&gt;
				// Finally compare file size&lt;br /&gt;
				var biggest = { size: 0, jsFile: null };&lt;br /&gt;
					&lt;br /&gt;
				for (i = 0; i &amp;lt; len; i++) {&lt;br /&gt;
					jsFile = jsFiles[i];&lt;br /&gt;
					oldText = jsFile.get();&lt;br /&gt;
					var oldTextLen = oldText.length;&lt;br /&gt;
					&lt;br /&gt;
					if (oldTextLen &amp;gt;= biggest.size) biggest = {&lt;br /&gt;
						size: oldTextLen,&lt;br /&gt;
						jsFile: jsFile&lt;br /&gt;
					};&lt;br /&gt;
				}&lt;br /&gt;
				$progress.notify( &amp;quot;Appending to bigger file: &amp;quot; + biggest.jsFile.getSource(), 25, biggest.jsFile );&lt;br /&gt;
				biggest.jsFile.set( biggest.jsFile.get() + &amp;#039;\n//&amp;lt;nowiki&amp;gt;&amp;#039; + JSONVal + &amp;#039;\n//&amp;lt;\/nowiki&amp;gt;&amp;#039; );&lt;br /&gt;
				process.save( biggest.jsFile );&lt;br /&gt;
			},&lt;br /&gt;
			save: function(jsFile) {&lt;br /&gt;
				jsFile.saving = true;&lt;br /&gt;
				$progress.notify( &amp;quot;Saving &amp;quot; + jsFile.getSource(), 30, jsFile );&lt;br /&gt;
				jsFile.save( process.saved, process.savedErr, &amp;quot;[[MediaWiki:Gadget-SettingsManager.js|SettingsManager]]: &amp;quot; + specs.editSummary );&lt;br /&gt;
			},&lt;br /&gt;
			saved: function(jsFile) {&lt;br /&gt;
				var i, len = jsFiles.length, jsf, waitingFor = [];&lt;br /&gt;
				&lt;br /&gt;
				jsFile.saving = false;&lt;br /&gt;
				&lt;br /&gt;
				for (i = 0; i &amp;lt; len; i++) {&lt;br /&gt;
					jsf = jsFiles[i];&lt;br /&gt;
					if (jsf.saving) {&lt;br /&gt;
						waitingFor.push(jsf.getSource());&lt;br /&gt;
					}&lt;br /&gt;
				}&lt;br /&gt;
				$progress.notify( &amp;quot;Saved &amp;quot; + jsFile.getSource() + &amp;quot;. Waiting for &amp;quot; + (waitingFor.join(&amp;#039;, &amp;#039;) || &amp;#039;-&amp;#039;), Math.round( (len - waitingFor.length)*(20/len) ) + 50,  jsFile );&lt;br /&gt;
				&lt;br /&gt;
				if (waitingFor.length) return;&lt;br /&gt;
				$progress.resolve( &amp;quot;Success!&amp;quot;, 100, jsFile );&lt;br /&gt;
			},&lt;br /&gt;
			savedErr: function(jsFile, code, errObj) {&lt;br /&gt;
				$progress.reject( &amp;quot;Error saving &amp;quot; + jsFile.getSource() + &amp;quot;. Code is &amp;quot; + code + &amp;quot;.\n&amp;quot;, -1, errObj );&lt;br /&gt;
			}&lt;br /&gt;
		};&lt;br /&gt;
		&lt;br /&gt;
		return {&lt;br /&gt;
			getSpecs: function() {&lt;br /&gt;
				return specs;&lt;br /&gt;
			},&lt;br /&gt;
			setSpecs: function(specsIn) {&lt;br /&gt;
				specs = specsIn;&lt;br /&gt;
				return this;&lt;br /&gt;
			},&lt;br /&gt;
			// Warning: If you specified a different save-position (&amp;quot;saveAt&amp;quot;)&lt;br /&gt;
			// and also an optionName, the script has to be fetched and evaluated&lt;br /&gt;
			// We recommend omitting setting &amp;quot;optionName&amp;quot; when using &amp;quot;saveAt&amp;quot;&lt;br /&gt;
			fetchValue: function(cb, errCb) {&lt;br /&gt;
				process.updateVars();&lt;br /&gt;
				&lt;br /&gt;
				if (specs.saveAt) {&lt;br /&gt;
					var s = sm.script( customJS );&lt;br /&gt;
					if (specs.optionName) {&lt;br /&gt;
						s.fetchText(function() {&lt;br /&gt;
							s.doEval();&lt;br /&gt;
							cb( valByString( specs.optionName ) );&lt;br /&gt;
						}, errCb);&lt;br /&gt;
					} else {&lt;br /&gt;
						s.fetchJSON(function(scriptObj, JSON) {&lt;br /&gt;
							cb( JSON );&lt;br /&gt;
						}, errCb);&lt;br /&gt;
					}&lt;br /&gt;
					return this;&lt;br /&gt;
				}&lt;br /&gt;
				cb( valByString( specs.optionName ) );&lt;br /&gt;
				return this;&lt;br /&gt;
			},&lt;br /&gt;
			getValue: function() {&lt;br /&gt;
				return specs.value;&lt;br /&gt;
			},&lt;br /&gt;
			setValue: function(val) {&lt;br /&gt;
				specs.value = val;&lt;br /&gt;
				return this;&lt;br /&gt;
			},&lt;br /&gt;
			save: function($elem, event) {&lt;br /&gt;
				// We won&amp;#039;t check whether the value is undefined. This is your task.&lt;br /&gt;
				$el = $elem;&lt;br /&gt;
				evt = event;&lt;br /&gt;
				return process.start();&lt;br /&gt;
			},&lt;br /&gt;
			getProgress: function() {&lt;br /&gt;
				return $progress;&lt;br /&gt;
			}&lt;br /&gt;
		};&lt;br /&gt;
	},&lt;br /&gt;
	/**&lt;br /&gt;
	* Constructor-method. Returns a script-object you should perform the actions on.&lt;br /&gt;
	*&lt;br /&gt;
	* @example&lt;br /&gt;
	*      var commonJS = mw.libs.settingsManager.script( &amp;#039;User:Example/common.js&amp;#039; );&lt;br /&gt;
	*      commonJS.set( &amp;#039;// empty!&amp;#039; ).setSummary( &amp;#039;Removing Content&amp;#039; ).save( function() { console.log( &amp;#039;Successfully removed content from &amp;#039; + commonJS.getSource() ) } )&lt;br /&gt;
	*&lt;br /&gt;
	*      // Enable a gadget and load it:&lt;br /&gt;
	*      mw.libs.settingsManager.gadget( &amp;#039;Slideshow&amp;#039; ).load().enable();&lt;br /&gt;
	*&lt;br /&gt;
	* @param source {String} The name of the JavaScript file with namespace.&lt;br /&gt;
	* @context {mw.libs.settingsManager}&lt;br /&gt;
	* @return {Object} script-object you can use for performing actions on.&lt;br /&gt;
	*/&lt;br /&gt;
	script: function(source) {&lt;br /&gt;
		var content,&lt;br /&gt;
			page,&lt;br /&gt;
			summary = &amp;quot;Changing configuration using [[:commons:MediaWiki:Gadget-SettingsManager.js]]&amp;quot;,&lt;br /&gt;
			minor = 1,&lt;br /&gt;
			exists,&lt;br /&gt;
			fetch,&lt;br /&gt;
			save;&lt;br /&gt;
&lt;br /&gt;
		fetch = function() {&lt;br /&gt;
			var mwa = new mw.Api();&lt;br /&gt;
			return mwa.get( {&lt;br /&gt;
				prop: &amp;#039;info|revisions&amp;#039;,&lt;br /&gt;
				titles: source,&lt;br /&gt;
				rvprop: &amp;#039;timestamp|content&amp;#039;,&lt;br /&gt;
				intoken: &amp;#039;edit&amp;#039;&lt;br /&gt;
			} );&lt;br /&gt;
		};&lt;br /&gt;
		&lt;br /&gt;
		save = function() {&lt;br /&gt;
			var mwa = new mw.Api(),&lt;br /&gt;
				edit = {&lt;br /&gt;
					action: &amp;#039;edit&amp;#039;,&lt;br /&gt;
					title: source,&lt;br /&gt;
					text: &amp;#039;object&amp;#039; === typeof content ? $.toJSON(content) : content,&lt;br /&gt;
					summary: summary,&lt;br /&gt;
					watchlist: &amp;#039;nochange&amp;#039;,&lt;br /&gt;
					recreate: 1&lt;br /&gt;
				};&lt;br /&gt;
				&lt;br /&gt;
			if (minor) edit.minor = 1;&lt;br /&gt;
			if (exists) {&lt;br /&gt;
				edit.basetimestamp = page.revisions[0].timestamp;&lt;br /&gt;
			} else {&lt;br /&gt;
				edit.starttimestamp = page.starttimestamp;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			edit.token = page.edittoken;&lt;br /&gt;
			return mwa.post( edit );&lt;br /&gt;
		};&lt;br /&gt;
			&lt;br /&gt;
		return {&lt;br /&gt;
			get: function() {&lt;br /&gt;
				return content;&lt;br /&gt;
			},&lt;br /&gt;
			getSource: function() {&lt;br /&gt;
				return source;&lt;br /&gt;
			},&lt;br /&gt;
			doEval: function() {&lt;br /&gt;
				/*jshint evil:true */&lt;br /&gt;
				return eval(content);&lt;br /&gt;
			},&lt;br /&gt;
			parseJSON: function() {&lt;br /&gt;
				// jquery.json - plugin required&lt;br /&gt;
				return (&amp;#039;string&amp;#039; === typeof content &amp;amp;&amp;amp; &amp;#039;&amp;#039; !== content) ? $.secureEvalJSON( content ) : &amp;#039;&amp;#039;;&lt;br /&gt;
			},&lt;br /&gt;
			// Supplied callback called with a string as second argument&lt;br /&gt;
			fetchText: function(cb, errCb) {&lt;br /&gt;
				var pgs, pg, scriptObj = this;&lt;br /&gt;
				&lt;br /&gt;
				fetch().done( function(result) {&lt;br /&gt;
					pgs = result.query.pages;&lt;br /&gt;
					page = firstItem( pgs );&lt;br /&gt;
					exists = !!(page.revisions &amp;amp;&amp;amp; page.revisions[0]);&lt;br /&gt;
					content = (exists &amp;amp;&amp;amp; page.revisions[0][&amp;#039;*&amp;#039;]) || &amp;#039;&amp;#039;;&lt;br /&gt;
					cb( scriptObj, content );&lt;br /&gt;
				} ).fail( function( status, errObj ) {&lt;br /&gt;
					errCb( scriptObj, status, errObj );&lt;br /&gt;
				} );&lt;br /&gt;
				return this;&lt;br /&gt;
			},&lt;br /&gt;
			// Supplied callback called with parsed JSON-data as second argument&lt;br /&gt;
			fetchJSON: function(cb, errCb) {&lt;br /&gt;
				this.fetchText( function(scriptObj, content) {&lt;br /&gt;
					cb( scriptObj, scriptObj.parseJSON() );&lt;br /&gt;
				}, function(scriptObj, status, errObj) {&lt;br /&gt;
					errCb( scriptObj, status, errObj );&lt;br /&gt;
				} );&lt;br /&gt;
				return this;&lt;br /&gt;
			},&lt;br /&gt;
			set: function(newContent) {&lt;br /&gt;
				content = newContent;&lt;br /&gt;
				return this;&lt;br /&gt;
			},&lt;br /&gt;
			setMinor: function(newMinor) {&lt;br /&gt;
				minor = !!newMinor;&lt;br /&gt;
			},&lt;br /&gt;
			setSummary: function(newSummary) {&lt;br /&gt;
				summary = newSummary;&lt;br /&gt;
			},&lt;br /&gt;
			save: function(cb, errCb, newSummary, newContent, newMinor) {&lt;br /&gt;
				var scriptObj = this;&lt;br /&gt;
				if (newContent !== undefined) content = newContent;&lt;br /&gt;
				if (newSummary !== undefined) summary = newSummary;&lt;br /&gt;
				if (newMinor !== undefined) minor = !!newMinor;&lt;br /&gt;
				save().done( function(result) {&lt;br /&gt;
					cb( scriptObj, result );&lt;br /&gt;
				} ).fail( function(status, errObj) {&lt;br /&gt;
					errCb( scriptObj, status, errObj );&lt;br /&gt;
				} );&lt;br /&gt;
				return this;&lt;br /&gt;
			}&lt;br /&gt;
		};&lt;br /&gt;
	},&lt;br /&gt;
	/**&lt;br /&gt;
	* Switch a user preference using Ajax!&lt;br /&gt;
	*&lt;br /&gt;
	* @example&lt;br /&gt;
	*      mw.libs.settingsManager.switchPref( &amp;#039;myOption&amp;#039;, &amp;#039;new value&amp;#039; );&lt;br /&gt;
	*&lt;br /&gt;
	* @param prefName {String} The name of the preference.&lt;br /&gt;
	* @param prefName {String} The new value the preference should set to.&lt;br /&gt;
	* @param cb {Function} Callback in case of success.&lt;br /&gt;
	* @param cb {Function} Callback in case of an error.&lt;br /&gt;
	* @context {mw.libs.settingsManager}&lt;br /&gt;
	* @return {Object} a jQuery deferred-object-queue. Don&amp;#039;t use it for error-handling - Done by this method.&lt;br /&gt;
	*/&lt;br /&gt;
	switchPref: function(prefName, prefVal, cb, errCb) {&lt;br /&gt;
		var mwa = new mw.Api(),&lt;br /&gt;
			args = arguments,&lt;br /&gt;
			apiDef = mwa.post( {&lt;br /&gt;
				action: &amp;#039;options&amp;#039;,&lt;br /&gt;
				token: mw.user.tokens.get(&amp;#039;csrfToken&amp;#039;),&lt;br /&gt;
				optionname: prefName,&lt;br /&gt;
				optionvalue: prefVal || 0&lt;br /&gt;
			} );&lt;br /&gt;
&lt;br /&gt;
		// If we changed a preference successfully, update user.options reflecting the change&lt;br /&gt;
		apiDef.done( function() {&lt;br /&gt;
			mw.user.options.set( prefName, prefVal );&lt;br /&gt;
		} );&lt;br /&gt;
		if (cb) apiDef.done( cb );&lt;br /&gt;
		// Catch badtoken and some other common errors&lt;br /&gt;
		apiDef.fail( function(code, result) {&lt;br /&gt;
			switch (code) {&lt;br /&gt;
				case &amp;#039;badtoken&amp;#039;:&lt;br /&gt;
					refreshToken(function (gotANewToken) {&lt;br /&gt;
						if (gotANewToken) return sm.switchPref.apply( sm, Array.prototype.slice.call( args, 0 ) );&lt;br /&gt;
					} );&lt;br /&gt;
					// Stop the propagation of &lt;br /&gt;
					return false;&lt;br /&gt;
				case &amp;#039;http&amp;#039;:&lt;br /&gt;
				case &amp;#039;ok-but-empty&amp;#039;:&lt;br /&gt;
					setTimeout( function() {&lt;br /&gt;
						return sm.switchPref.apply( sm, Array.prototype.slice.call(args, 0) );&lt;br /&gt;
					}, 1000 );&lt;br /&gt;
					return false;&lt;br /&gt;
				default:&lt;br /&gt;
					return (errCb &amp;amp;&amp;amp; errCb(code, result) &amp;amp;&amp;amp; false);&lt;br /&gt;
			}&lt;br /&gt;
		} );&lt;br /&gt;
		return apiDef;&lt;br /&gt;
	},&lt;br /&gt;
	/**&lt;br /&gt;
	* Constructor-method. Returns an option-object you should perform the actions on.&lt;br /&gt;
	*&lt;br /&gt;
	* @example&lt;br /&gt;
	*      var slideshowGadget = mw.libs.settingsManager.gadget( &amp;#039;Slideshow&amp;#039; );&lt;br /&gt;
	*      if (slideshowGadget.isEnabled()) { slideshowGadget.disable( myCallback ) }&lt;br /&gt;
	*&lt;br /&gt;
	*      // Enable a gadget and load it:&lt;br /&gt;
	*      mw.libs.settingsManager.gadget( &amp;#039;Slideshow&amp;#039; ).load().enable();&lt;br /&gt;
	*&lt;br /&gt;
	* @param gadgetName {Object} The name of the gadget. (Not the script file; without Gadget- prefix or other decoration)&lt;br /&gt;
	* @context {mw.libs.settingsManager}&lt;br /&gt;
	* @return {Object} gadget-object you can use for performing actions on.&lt;br /&gt;
	*/&lt;br /&gt;
	gadget: function(gadgetName) {&lt;br /&gt;
		var optGadget = &amp;#039;gadget-&amp;#039; + gadgetName,&lt;br /&gt;
			rlGadget = &amp;#039;ext.gadget.&amp;#039; + gadgetName;&lt;br /&gt;
			&lt;br /&gt;
		return {&lt;br /&gt;
			getName: function() {&lt;br /&gt;
				return gadgetName;&lt;br /&gt;
			},&lt;br /&gt;
			isDefault: function() {&lt;br /&gt;
				var opt = mw.user.options.get( optGadget );&lt;br /&gt;
				return (&amp;#039;number&amp;#039; === typeof opt || &amp;#039;&amp;#039; === opt);&lt;br /&gt;
			},&lt;br /&gt;
			isEnabled: function() {&lt;br /&gt;
				var opt = mw.user.options.get( optGadget );&lt;br /&gt;
				return !!opt;&lt;br /&gt;
			},&lt;br /&gt;
			getState: function() {&lt;br /&gt;
				return mw.loader.getState( rlGadget );&lt;br /&gt;
			},&lt;br /&gt;
			isLoaded: function() {&lt;br /&gt;
				return (&amp;#039;ready&amp;#039; === this.getState());&lt;br /&gt;
			},&lt;br /&gt;
			load: function(cb, errCb) {&lt;br /&gt;
				// Always async&lt;br /&gt;
				if (this.isLoaded &amp;amp;&amp;amp; cb) return setTimeout( function() {&lt;br /&gt;
					cb( gadgetName, true );&lt;br /&gt;
				}, 1 );&lt;br /&gt;
				mw.loader.using( rlGadget, &lt;br /&gt;
					cb ? function() { &lt;br /&gt;
						cb( gadgetName ); &lt;br /&gt;
					} : undefined, &lt;br /&gt;
					errCb ? function() { &lt;br /&gt;
						errCb( gadgetName ); &lt;br /&gt;
					} : undefined &lt;br /&gt;
				);&lt;br /&gt;
				return this;&lt;br /&gt;
			},&lt;br /&gt;
			enable: function(cb, errCb) {&lt;br /&gt;
				// Type wouldn&amp;#039;t matter due to URL-encoding but we also want to update&lt;br /&gt;
				// the user.options object&lt;br /&gt;
				sm.switchPref( optGadget, this.isDefault() ? 1 : &amp;#039;1&amp;#039;, cb, errCb );&lt;br /&gt;
				return this;&lt;br /&gt;
			},&lt;br /&gt;
			disable: function(cb, errCb) {&lt;br /&gt;
				sm.switchPref( optGadget, this.isDefault() ? &amp;#039;&amp;#039; : null, cb, errCb );&lt;br /&gt;
				return this;&lt;br /&gt;
			}&lt;br /&gt;
		};&lt;br /&gt;
	}&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mw.libs.settingsManager = sm;&lt;br /&gt;
&lt;br /&gt;
// TODO add to gadget-def&lt;br /&gt;
// mw.loader.load([&amp;#039;jquery.json&amp;#039;, &amp;#039;mediawiki.user&amp;#039;, &amp;#039;user.options&amp;#039;]);&lt;br /&gt;
}( jQuery, mediaWiki ));&lt;br /&gt;
// &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>入我相思门</name></author>
	</entry>
</feed>