MediaWiki:Gadget-warning.js

Megjegyzés: közzététel után frissítened kell a böngésződ gyorsítótárát, hogy lásd a változásokat.

  • Firefox / Safari: tartsd lenyomva a Shift gombot és kattints a Frissítés gombra a címsorban, vagy használd a Ctrl–F5 vagy Ctrl–R (Macen ⌘–R) billentyűkombinációt
  • Google Chrome: használd a Ctrl–Shift–R (Macen ⌘–Shift–R) billentyűkombinációt
  • Edge: tartsd nyomva a Ctrl-t, és kattints a Frissítés gombra, vagy nyomj Ctrl–F5-öt
/**
 * @name Járőrscript
 * @fileOverview Gyakran használt sablonok
 * 
 * @author [[user:Báthory Péter]]
 * hibajelentés, ötletek, kérések ide: [[Szerkesztővita:BáthoryPéter]]
 * 
 * 
 * @typedef {object} WarningTemplateParamInput
 * @property {string} label
 * @property {string|null} [description=null]
 * @property {boolean} [required=false]
 * 
 * @typedef {Required<WarningTemplateParamInput>} WarningTemplateParam
 * 
 * 
 * @typedef {object} WarningTemplateInput
 * @property {string} name Unique identifier of the warning
 * @property {number[]} ns Namespaces the warning should appear in
 * @property {string} template The warning content with MediaWiki message syntax (e.g. `{{foo|param=$1}}`)
 * @property {string} comment Edit summary used when adding the warning
 * @property {string} type The insertion type of the warning
 * @property {boolean} [autosave=true] Whether the page should be automatically saved after adding the template,
 *  or the user has to press the save button themselves
 * @property {WarningTemplateParamInput[]} [params=[]] Parameters used in the template
 * @property {string|null} [special=null]
 * 
 * @typedef {Required<WarningTemplateInput> & {params: WarningTemplateParam[]}} WarningTemplate
 */

mw.loader.using( 'mediawiki.util', function () {
	if ( mw.util.getParamValue( 'printable' ) === 'yes' || mw.config.get( 'wgIsMainPage' ) ) {
		return false;
	}

	/** @type {WarningTemplate[]} */
	var warningTemplates = [],
		defaultList = [];

	mw.messages.set( {
		'gadget-warning-label-monobook': 'Sablonok▼',
		'gadget-warning-label-vector': 'S',
		'gadget-warning-tooltip': 'Gyakran használt sablonok',
		'gadget-warning-save': 'Beszúrás',
		'gadget-warning-cancel': 'Mégse',
		'gadget-warning-noconfig': 'Nincs konfiguráció',
		'gadget-warning-noconfig-body': 'A járőrscript [[$1|konfigurációja]] nem található. Ha nem a magyar Wikipédián használod, másold át [$2 onnan].',
		'gadget-warning-invalid-json': 'Érvénytelen JSON',
		'gadget-warning-invalid-json-body': 'A járőrscript JSON-konfigurációja szintaktikai hibát tartalmaz.',
		'gadget-warning-bad-json': 'Hibás JSON',
		'gadget-warning-bad-json-body': 'A járőrscript JSON-konfigurációja szemantikai hibát tartalmaz.',
		'gadget-warning-bad-template-data': 'Hibás sablonadatok',
		'gadget-warning-bad-template-data-body': 'A járőrscript egy vagy több sablonjának adatai hibásak, ezek nem jelennek meg a listában.',
		'gadget-warning-bad-template-list': 'Hibás sablonlista',
		'gadget-warning-bad-template-list-body': 'A járőrscript alapértelmezett sablonlistájában egy vagy több ismeretlen sablon szerepel. Ha saját sablonlistád van, ellenőrizd a neveket.',
		'gadget-warning-bad-template-name': 'Hibás sablonnév',
		'gadget-warning-bad-template-name-body': 'A járőrscriptnek megadott sablon (<nowiki>$1</nowiki>) nem létezik. Kérjük, jelezd a hibát [$2 műszaki kocsmafalon].',
		'gadget-warning-page-missing': 'A lap nem létezik',
		'gadget-warning-page-missing-body': 'A lap nem létezik (lehet, hogy közben törölve lett), ezért a járőrscript nem mentette el.'
	} );

	/**
	 * 
	 * @param {string} key The message key
	 * @param {'error'|'warn'|'info'|'success'|null} [type='error'] The message severity
	 * @param {any[]} [params] Any parameters to the body message
	 */
	function notify( key, type, params ) {
		params = params || [];
		params.unshift( 'gadget-warning-' + key + '-body' );
		mw.notify( 
			mw.message.apply( undefined, params ),
			{
				title: mw.msg( 'gadget-warning-' + key ),
				type: type || 'error'
			}
		);
	}

	/**
	 * Validate the templates JSON and store
	 * valid template informations in `warningTemplates`.
	 * 
	 * @param {WarningTemplateInput[]} templates The JSON config's template list as a JavaScript array
	 * @return {0|1|2} Error level:
	 *  - 0: everything OK
	 *  - 1: invalid template description(s), some or all templates have not been exported
	 *  - 2: fatal error, argument not an array, no data exported
	 */
	function validateTemplates( templates ) {
		var i, j, ns, params, param,
			knownTemplates = [],
			state = 0;

		/**
		 * @template T
		 * @param {T} obj
		 * @param {keyof T} name
		 * @returns {boolean}
		 */
		function checkProp( obj, name ) {
			return Object.prototype.hasOwnProperty.call( obj, name );
		}

		/**
		 * @param {number} i
		 * @param {WarningTemplateInput} tl
		 */
		function checkTemplate( i, tl ) {
			if (
				$.isPlainObject( tl )
				&& ( checkProp( tl, 'name' ) && typeof tl.name === 'string' && knownTemplates.indexOf( tl.name ) === -1 )
				&& ( checkProp( tl, 'ns' ) && $.isArray( tl.ns ) )
				&& ( checkProp( tl, 'template' ) && typeof tl.template === 'string' )
				&& ( checkProp( tl, 'comment' ) && typeof tl.comment === 'string' )
				&& ( checkProp( tl, 'type' ) && typeof tl.type === 'string' )
				&& ( !checkProp( tl, 'autosave' ) || typeof tl.autosave === 'boolean' )
				&& ( !checkProp( tl, 'params' ) || $.isArray( tl.params ) )
				&& ( !checkProp( tl, 'special' ) || typeof tl.special === 'string' )
			) {
				ns = [];
				for ( j = 0; j < tl.ns.length; ++j ) {
					if ( typeof tl.ns[ j ] === 'number' ) {
						ns.push( tl.ns[ j ] );
					} else {
						mw.log.warn( 'warning.js: ' + tl.name + ': invalid namespace "' + ns[ j ] + '"' );
						return 1;
					}
				}

				params = [];
				if ( tl.params ) {
					for ( j = 0; j < tl.params.length; ++j ) {
						param = tl.params[ j ];
						if (
							$.isPlainObject( param )
							&& ( checkProp( param, 'label' ) && typeof param.label === 'string' )
							&& ( !checkProp( param, 'description' ) || typeof param.description === 'string' || param.description === null )
							&& ( !checkProp( param, 'required' ) || typeof param.required === 'boolean' )
						) {
							params.push( {
								label: param.label,
								description: param.description || null,
								required: param.required || false
							} );
						} else {
							mw.log.warn( 'warning.js: ' + tl.name + ': invalid parameter #' + j );
							return 1;
						}
					}
				}

				warningTemplates.push( {
					name: tl.name,
					ns: ns,
					template: tl.template,
					comment: tl.comment,
					type: tl.type,
					autosave: checkProp( tl, 'autosave' ) ? tl.autosave : true,
					params: params,
					special: checkProp( tl, 'special' ) ? tl.special : null
				} );
			} else {
				mw.log.warn( 'warning.js: invalid template #' + i );
			}
		}

		if ( !$.isArray( templates ) ) {
			return 2;
		}
		for ( i = 0; i < templates.length; ++i ) {
			checkTemplate( i, templates[ i ] );
		}
		return 0;
	}

	/**
	 * Validate the default templates list and store `warningTemplates` indexes
	 * for valid names in `defaultList`. This must be run after validateTemplates()
	 * terminated, or some valid keys may be marked as invalid.
	 * 
	 * @param {Array} sitewide The JSON config's default list as a JavaScript array
	 * @return {0|1|2} Error level:
	 *  - 0: everything OK
	 *  - 1: invalid template key(s), some or all indexes have not been exported
	 *  - 2: fatal error, argument not an array, no data exported
	 */
	function validateDefaultList( sitewide ) {
		var list = window.hasOwnProperty( 'jarorSablonLista' ) ? jarorSablonLista : sitewide,
			/** @type {0|1} */
			status = 0,
			i, j;
		if ( !$.isArray( list ) ) {
			return 2;
		}
		for ( i = 0; i < list.length; ++i ) {
			j = 0;
			while ( j < warningTemplates.length && warningTemplates[ j ].name !== list[ i ] ) {
				++j;
			}
			if ( j < warningTemplates.length ) {
				defaultList.push( j );
			} else {
				mw.log.warn( 'warning.js: unknown template "' + list[ i ] + '"' );
				status = 1;
			}
		}
		return status;
	}

	/*Sablonok listája. Megadandó tulajdonságok:
	 * 'ns': melyik névtérben jelenjen meg (wgNamespaceNumber). Szögletes zárójelek között vesszővel elválasztva kell felsorolni
	 *     a névterek számát. (A negatív értékűt nem rakja ki magától, arról külön kód gondoskodik)
	 * 'template': beillesztendő sablon
	 * 'comment': szerkesztési összefoglaló
	 * 'autosave': azonnali mentés (true/false)
	 * 'type': működési mód: 'pre'=elejére, 'post'=végére, 'del'=tartalom törlése, 'comment'=tartalom kikommentezése
	 * 'param1':
	 * 'param2': (opcionális) paraméter leírása (akkor kell, ha a beillesztendőben van %1, %2)
	 */
	/**
	 * Load and validate data, and run postprocessing functions if
	 * the validation is successful.
	 * @param {(() => void)[]} functionsToRun The functions to run
	 *  after page load if valid data is found.
	 */
	function loadData( functionsToRun ) {
		function success( content ) {
			var state;
			if ( !$.isPlainObject( content ) ) {
				return fail( null, 'semantic-error', 'Root element of JSON data must be an object.' );
			}
			state = content.hasOwnProperty( 'templates' ) ? validateTemplates( content.templates ) : 2;
			if ( state === 2 ) {
				return fail( null, 'semantic-error', 'The `templates` property must be an array.' );
			} else if ( state === 1 ) {
				notify( 'bad-template-data', 'warn' );
			}
			state = content.hasOwnProperty( 'defaultlist' ) ? validateDefaultList( content.defaultlist ) : 2;
			if ( state === 2 ) {
				return fail( null, 'semantic-error', 'The `defaultlist` property must be an array.' );
			} else if ( state === 1 ) {
				notify( 'bad-template-list', 'warn' );
			}
			for ( var i = 0; i < functionsToRun.length; ++i ) {
				$( functionsToRun[ i ] );
			}
		}
		function fail( xhr, code, msg ) {
			var title, message;
			if ( code == 'error' && msg == 'Not Found' ) {
				notify(
					'noconfig',
					null,
					[ 'MediaWiki:Gadget-warning.json', 'https://hu.wiki.x.io/wiki/MediaWiki:Gadget-warning.json' ]
				);
				mw.log.warn( 'Gadget-warning.js: No config' );
				mw.log.warn( xhr );
			} else if ( code == 'parsererror' ) {
				notify( 'invalid-json' );
				mw.log.warn( 'Gadget-warning.js: Invalid JSON' );
				mw.log.warn( xhr );
				mw.log.warn( msg );
			} else if ( code == 'semantic-error' ) {
				notify( 'bad-json' );
				mw.log.warn( 'Gadget-warning.js: Bad JSON: ' + msg );
			}
		}
		var url = mw.util.getUrl('MediaWiki:Gadget-warning.json', {action: 'raw'});
		$.get(url, null, null, 'json').done(success).fail(fail);
	}

	/**
	 * Megállapítja, hogy van-e jogosultságunk a lap szerkesztésére
	 * @return {boolean} True, ha jogosultak vagyunk szerkeszteni a lapot
	 */
	function mayEdit() {
		var L,
			restrictions = mw.config.get( 'wgRestrictionEdit' ) || mw.config.get( 'wgRestrictionCreate' ) || [],
			groups = mw.config.get( 'wgUserGroups' );
		for ( var i = 0; i < restrictions.length; ++i ) {
			L = false;
			for ( var j = 0; j < groups.length; ++j ) {
				if ( restrictions[i] === groups[j] ) {
					L = true;
				}
			}
			if ( !L ) {
				return false;
			}
		}
		return true;
	}

	/**
	 * Toggle the template list.
	 * @param {JQuery.Event} e jQuery Event object
	 * @param {string} [showall] If `all`, show all available templates
	 */
	function jaror_show(e, showall) {
		e.preventDefault();
		showall = showall || e.data || null;
		
		// Ha nyitva volt, bezárja.
		// Ha nyitva volt, de "all" paraméterrel lett meghívva, bezárja és kinyitja újra all paraméterrel
		if ( $( '#jarorSablonLista' ).length ) {
			$( '#jarorSablonLista' ).remove();
			if ( !showall ) {
				return true;
			}
		}

		/**
		 * Prompt for template parameters.
		 * 
		 * @param {string} tlName The template name
		 * @param {WarningTemplateParam[]} paramsList The parameter data
		 * @return {JQuery.Promise<string[]>} Resolved with given parameters,
		 *  or rejected if user clicks the "Cancel" button
		 */
		function promptParams( tlName, paramsList ) {
			var deferred = $.Deferred();

			/**
			 * @param {number} i
			 * @param {WarningTemplateParam} paramData
			 * @returns {OO.ui.FieldLayout}
			 */
			function getParamField( i, paramData ) {
				var input = new OO.ui.TextInputWidget( {
					name: 'params[]',
					autofocus: (i === 0),
					required: paramData.required
				} );
				return new OO.ui.FieldLayout(
					input,
					{
						label: paramData.label,
						help: paramData.description
					}
				);
			}

			mw.loader.using( [ 'oojs-ui-core', 'oojs-ui-windows' ] )
				.done( function () {
					function ParamsDialog( config ) {
						ParamsDialog.super.call( this, config );
					}
					OO.inheritClass( ParamsDialog, OO.ui.ProcessDialog );

					// Specify a name for .addWindows()
					ParamsDialog.static.name = 'warningJsParamsDialog';
					// Specify a static title and actions.
					ParamsDialog.static.title = '{' + '{' + tlName + '}}';
					ParamsDialog.static.actions = [
						{ action: 'save', label: mw.msg( 'gadget-warning-save' ), flags: 'primary' },
						{ action: 'cancel', label: mw.msg( 'gadget-warning-cancel' ), flags: 'safe' }
					];

					ParamsDialog.prototype.initialize = function () {
						ParamsDialog.super.prototype.initialize.apply( this, arguments );

						this.panel = new OO.ui.PanelLayout( { padded: true, expanded: false, classes: [ 'warningJsPanelLayout' ] } );
						this.fieldset = new OO.ui.FieldsetLayout();
						this.content = new OO.ui.FormLayout( {
							items: [ this.fieldset ],
							action: mw.util.wikiScript(),
							method: 'get'
						} );
						this.fields = [];
						for ( var i = 0; i < paramsList.length; ++i ) {
							this.fields.push( getParamField( i, paramsList[ i ] ) );
						}
						this.fields.push( new OO.ui.HiddenInputWidget( {
							name: 'action',
							value: 'submit'
						} ) );
						this.fields.push( new OO.ui.HiddenInputWidget( {
							name: 'title',
							value: mw.config.get( 'wgPageName' )
						} ) );
						this.fields.push( new OO.ui.HiddenInputWidget( {
							name: 'jaror',
							value: tlName
						} ) );
						this.content.addItems( this.fields );
						this.panel.$element.append( this.content.$element );
						this.$body.append( this.panel.$element );
					};

					ParamsDialog.prototype.getReadyProcess = function () {
						var dialog = this;
						return new OO.ui.Process( function () {
							dialog.fields[ 0 ].$element.find( 'input' ).focus();
						} );
					}

					ParamsDialog.prototype.getActionProcess = function ( action ) {
						var dialog = this;
						if ( action === 'save' ) {
							return new OO.ui.Process( function () {
								var params = [];
								for ( var i = 0; i < dialog.fields.length; ++i ) {
									if ( dialog.fields[ i ] instanceof OO.ui.FieldLayout ) {
										params.push( dialog.fields[ i ].fieldWidget.value );
									}
								}
								deferred.resolve( params );
								dialog.close( { action: action } );
							} );
						}
						if ( action === 'cancel' ) {
							return new OO.ui.Process( function () {
								deferred.reject();
								dialog.close( { action: action } );
							} );
						}
						// Fall back to parent handler
						return ParamsDialog.super.prototype.getActionProcess.call( this, action );
					};

					var paramsDialog = new ParamsDialog( { size: 'large' } );
					var windowManager = new OO.ui.WindowManager();
					$( 'body' ).append( windowManager.$element );
					windowManager.addWindows( [ paramsDialog ] );
					windowManager.openWindow( paramsDialog );
				} )
				.fail( deferred.reject );

			return deferred.promise();
		}

		/**
		 * Navigate to the edit window.
		 * 
		 * @param {string} tlName The template name
		 * @param {string[]} [params] The filled template parameters
		 */
		function navigate( tlName, params ) {
			var urlparams = {
				action: 'submit',
				jaror: tlName,
				params: params
			};
			document.location = mw.util.getUrl( null, urlparams );
		}

		/**
		 * A sablon adatai alapján elkészíti az URL paramétereket, majd átugrik szerkesztőmódba.
		 * Ha a sablon igényel felhasználói inputot, azokat egy prompt ablakkal bekéri
		 * @param {JQuery.Event} e jQuery Event objektum
		 * @returns {boolean|void} False, ha egy promptban mégsemre kattintott, vagy ha nem kapott Event.data objektumot
		 */
		function jarorClick( e ) {
			e.preventDefault();
			var
				/** @type {number} */
				i,
				/** @type {WarningTemplate} */
				tl,
				/** @type {string} */
				tlName;
			if (e.data) {
				tlName = e.data.tlName;
				for ( i = 0; i < warningTemplates.length; ++i ) {
					if ( warningTemplates[ i ].name === tlName ) {
						tl = warningTemplates[ i ];
						break;
					}
				}
			} else {
				return false;
			}
			if ( tl.params.length ) {
				promptParams( tlName, tl.params )
					.done( function ( params ) {
						navigate( tlName, params );
					} );
			} else {
				navigate( tlName );
			}
		}

		/**
		 * Get template objects for templates listed in `defaultList`
		 * @return {WarningTemplate[]}
		 */
		function getListedTemplates() {
			/** @type {WarningTemplate[]} */
			var ret = [];
			for ( var i = 0; i < defaultList.length; ++i ) {
				ret.push( warningTemplates[ defaultList[ i ] ] );
			}
			return ret;
		}

		var $warningsNode = $("<div>").attr('id','jarorSablonLista');
		var templateObjects = ( showall === 'all' ) ? warningTemplates : getListedTemplates();

		// Show templates present in `templateObjects`
		for ( var i = 0; i < templateObjects.length; ++i ) {
			var tl = templateObjects[ i ];
			if ( tl.ns.indexOf( mw.config.get( 'wgNamespaceNumber' ) ) > -1 ) {
				$( '<a>' )
					.attr( 'title', tl.template )
					.text( tl.name )
					.click( { tlName: tl.name }, jarorClick )
					.appendTo( $warningsNode );
				$warningsNode.append( ' | ' );
			}
		}
		if ( showall !== 'all' ) {
			$( '<a>' )
				.addClass( 'showall' )
				.text( '(összes)' )
				.click( 'all', jaror_show )
				.appendTo( $warningsNode );
		}

		mw.util.$content.prepend( $warningsNode );

		// Welcome templates on non-existent user talk pages
		//Megíratlan szerkesztői vitalapokhoz üdvözlő sablonok
		if (
			mw.config.get( 'wgNamespaceNumber' ) === 3 
			&& (
				mw.config.get( 'wgArticleId' ) === 0
				|| ( mw.config.get( 'wgAction' ) === 'edit' && $( '#wpTextbox1' ).val() === '' )
			)
		) {
			// Search for IPv4 or IPv6 address (v6 source: home.deds.nl/~aeron/regex/)
			var ip_reg = /(^(?:\d{1,3}\.){3}\d{1,3}$)|(^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$)/i;
			var $welcomeNode = $( '<div>' ).attr( 'id', 'udvozloSablonok' );
			var is_anon = ip_reg.test( mw.config.get( 'wgTitle' ) );
			var first = true;
			for ( i = 0; i < warningTemplates.length; ++i ) {
				if ( warningTemplates[ i ].special === 'welcome-' + ( is_anon ? 'anon' : 'registered' ) ) {
					if ( first ) {
						first = false;
					} else {
						$welcomeNode.append( ' | ' );
					}
					$( '<a>' )
						.text( warningTemplates[ i ].name )
						.click( { tlName: warningTemplates[ i ].name }, jarorClick )
						.appendTo( $welcomeNode );
				}
			}
			$warningsNode.prepend( $welcomeNode );
		}
	}

	/**
	 * Add the templates banner to the page.
	 */
	function addBanner() {
		var portletId = 'p-cactions',
			text = mw.msg( 'gadget-warning-label-monobook' ),
			previousElementId = null;
		switch ( mw.config.get( 'skin' ) ) {
			case 'vector':
			case 'vector-2022':
				break; // doesn't work, see T313666
				// Vector has separate menus for visible (p-views) and hidden (p-cactions) actions
				portletId = 'p-views';
				text = mw.msg( 'gadget-warning-label-vector' );
				break;
			case 'minerva':
				portletId = 'p-tb';
				break;
		}
		var menuItem = mw.util.addPortletLink( portletId, '#', text, 'ca-jaror',
			mw.msg( 'gadget-warning-tooltip' ), 'o', previousElementId );
		$( menuItem ).click( jaror_show );
	}

	/**
	 * Insert a template in the textbox.
	 * TODO: currently we force using the 2003/2010 wikitext editor by sending
	 * the user to `action=submit` instead of `action=edit`. Rather than making
	 * the user use the editor we like, we should support the editor the user
	 * likes: 2017WTE, VisualEditor, MobileFrontend editor overlay...
	 */
	function insertTemplate() {
		var tlName = mw.util.getParamValue( 'jaror' ),
			$tb = $( '#wpTextbox1' );
		if ( !$tb.length || !$( '#wpSummary' ).length ) {
			mw.log.warn( 'Gadget-warning.js: `#wpTextbox1` or `#wpSummary` not found' );
			return;
		}

		/** @type {WarningTemplate} */
		var tl;
		for ( var i = 0; i < warningTemplates.length; ++i ) {
			if ( warningTemplates[ i ].name === tlName ) {
				tl = warningTemplates[ i ];
				break;
			}
		}
		if ( !tl ) {
			notify( 'bad-template-name', null, [ tlName, 'https://hu.wiki.x.io/wiki/Kocsmafal_(műszaki)' ] );
			return;
		}
		var m,
			argv = [ tl.template ],
			param_re = /[&?]params(?:%5B%5D|\[\])=([^&]*)/g,
			href = location.href.replace( /#.*$/, '' );
		do {
			m = param_re.exec( href );
			if ( m ) {
				argv.push( decodeURIComponent( m[ 1 ].replace( /\+/g, '%20' ) ) );
			}
		} while ( m !== null );
		var template = mw.format.apply( null, argv );

		// Insert location (prepend, append, replace, comment out)
		switch ( tl.type ) {
			case 'pre':
				$tb.val( template + '\n' + $tb.val() );
				break;
			case 'post':
				$tb.val( $tb.val() + template + '\n' );
				break;
			case 'del':
				$tb.val( template + '\n' );
				break;
			case 'comment':
				$tb.val( template + '\n\n<!--\n' + $tb.val() + '-->\n' );
				break;
		}
		$( '#wpSummary' ).val( tl.comment );

		if ( tl.autosave ) {
			// Create new page only in talk spaces
			if ( mw.config.get( 'wgArticleId' ) > 0 || mw.config.get( 'wgNamespaceNumber' ) % 2 ) {
				if ( !window.jarorNoAutosave ) {
					window.onbeforeunload = null;
					// FIXME: no save while testing
					// $tb.closest( 'form' ).submit();
					mw.log( 'Gadget-warning.js would have saved automatically' );
				} else {
					mw.log( 'Gadget-warning.js would have saved' );
				}
			} else {
				notify( 'page-missing', 'warn' );
			}
		}
	}

	function init() {
		var functionsToRun = [];
		
		var namespaceNumber = mw.config.get( 'wgNamespaceNumber' ),
			action = mw.config.get( 'wgAction' );
		if (
			mayEdit()
			&& (
				( [ 0, 1, 4, 6, 118 ].indexOf( namespaceNumber ) > -1 && action === 'view' )
				|| namespaceNumber == 3
			)
		) {
			functionsToRun.push( addBanner );
		}

		// Evaluate, insert template. This runs on new page load after clicking on a template
		if ( mw.util.getParamValue( 'jaror' ) !== null && ( action === 'edit' || action === 'submit' ) ) {
			functionsToRun.push( insertTemplate );
		}

		if ( functionsToRun.length ) {
			loadData( functionsToRun );
		}
	}
	
	init();
} );