User:MJL/ARA-light.js

// // Everything is encapsulated in a private namespace object---``JJJ'': var JJJ = JJJ || {};

$(document).ready(function {	//initialize Constants	JJJ.Constants = getARAConstants;

//only execute on the edit page if (!JJJ.Constants.IS_EDIT_PAGE || JJJ.Constants.IS_JS_PAGE || JJJ.Constants.ARTICLE_TEXT_BOX_ELEMENT == null) return; //init functions and rules JJJ.Functions = getARAFunctions; JJJ.Rules    = getARARules; //init UI	$('#editform').prepend(JJJ.Constants.SUGGESTION_BOX_DIV); $('#wpSummaryLabel').prepend(JJJ.Constants.ADD_TO_SUMMARY_DIV); JJJ.Functions.scan;                                  //init scan now JJJ.Functions.observeWikiText(JJJ.Constants.delayScan); // ... and every time the user pauses typing });

function getARAConstants {	var ARA_Constants = ARA_Constants || {};

//article text box element ARA_Constants.ARTICLE_TEXT_BOX_ELEMENT = $("#wpTextbox1"); //are we on an Edit page? ARA_Constants.IS_EDIT_PAGE = mw.config.get('wgAction') === 'edit' || mw.config.get('wgAction') === 'submit'; //are we on a JS page? ARA_Constants.IS_JS_PAGE = mw.config.get('wgRelevantPageName').endsWith('.js'); //the ARA Suggestion box, which appears above the editing section ARA_Constants.SUGGESTION_BOX_DIV = $(' ', {'id':'suggestionBox.ARA', 'style':'border:dashed #ccc 1px;color:#888;'}); //the Add to Summary box, which appears near the edit summary ARA_Constants.ADD_TO_SUMMARY_DIV = $(' ', {'id':'addToSummaryBox.ARA', 'style':'border:dashed #ccc 1px;color:#888;display:none;'}); ARA_Constants.DEFAULT_MAX_SUGGESTIONS = 8; ARA_Constants.maxSuggestions = ARA_Constants.DEFAULT_MAX_SUGGESTIONS; ARA_Constants.suggestions; // : Suggestion[] ARA_Constants.appliedSuggestions = {}; // : Map ARA_Constants.scannedText = null; // remember what we scan, to check if it is	                      // still the same when we try to fix it	ARA_Constants.BIG_THRESHOLD = 100 * 1024; ARA_Constants.isBigScanConfirmed = false; // is the warning about a big article confirmed ARA_Constants.isTalkPageScanConfirmed = false; ARA_Constants.scanTimeoutId = null; // a timeout is set after a keystroke and before // a scan, this variable tracks its id	return ARA_Constants; }

function getARAFunctions {	var ARA_Functions = ARA_Functions || {};

// Browsers offer means to highlight text between two given offsets (``start	// and ``end) in a textarea, but some of them do not automatically scroll to it. // This function is an attempt to simulate cross-browser selection and scrolling. ARA_Functions.setSelectionRange = function (ta, start, end) { // Initialise static variables used within this function var _static = arguments.callee; // this is the Function we are in. It will be used as a poor man's function-local static scope. if (ta.setSelectionRange) { // Guess the vertical scroll offset by creating a			// separate hidden clone of the original textarea, filling it with the text // before ``start'' and computing its height. if (_static.NEWLINES == null) { _static.NEWLINES = '\n'; // 64 of them should be enough. for (var i = 0; i < 6; i++) { _static.NEWLINES += _static.NEWLINES; }			}			if (_static.helperTextarea == null) { _static.helperTextarea = document.createElement('TEXTAREA'); _static.helperTextarea.style.display = 'none'; document.body.appendChild(_static.helperTextarea); }			var hta = _static.helperTextarea; hta.style.display = ''; hta.style.width = ta.clientWidth + 'px'; hta.style.height = ta.clientHeight + 'px'; hta.value = _static.NEWLINES.substring(0, ta.rows) + ta.value.substring(0, start); var yOffset = hta.scrollHeight; hta.style.display = 'none'; ta.focus; ta.setSelectionRange(start, end); if (yOffset > ta.clientHeight) { yOffset -= Math.floor(ta.clientHeight / 2); ta.scrollTop = yOffset; // Opera does not support setting the scrollTop property if (ta.scrollTop != yOffset) { // todo: Warn the user or apply a workaround }			} else { ta.scrollTop = 0; }		} else { // IE incorrectly counts '\r\n' as a signle character start -= ta.value.substring(0, start).split('\r').length - 1; end -= ta.value.substring(0, end).split('\r').length - 1; var range = ta.createTextRange; range.collapse(true); range.moveStart('character', start); range.moveEnd('character', end - start); range.select; }	};	// getPosition(e), observe(e, x, f), stopObserving(e, x, f), // and stopEvent(event) are inspired by the prototype.js framework // http://prototypejs.org/ ARA_Functions.getPosition = function (e) { var x = 0; var y = 0; do { x += e.offsetLeft || 0; y += e.offsetTop || 0; e = e.offsetParent; } while (e); return {x: x, y: y}; };	ARA_Functions.observe = function (e, eventName, f) { if (e.addEventListener) { e.addEventListener(eventName, f, false); } else { e.attachEvent('on' + eventName, f); }	};	ARA_Functions.stopObserving = function (e, eventName, f) { if (e.removeEventListener) { e.removeEventListener(eventName, f, false); } else { e.detachEvent('on' + eventName, f); }	};	ARA_Functions.stopEvent = function (event) { if (event.preventDefault) { event.preventDefault; event.stopPropagation; } else { event.returnValue = false; event.cancelBubble = true; }	};	// ARA_Functions.anchor is a shortcut to creating a link as a DOM node: ARA_Functions.anchor = function (text, href, title) { var e = document.createElement('A'); e.href = href; e.appendChild(document.createTextNode(text)); e.title = title || ''; return e;	}; // ARA_Functions.link produces the HTML for a link to a Wikipedia article as a string. // It is convenient to embed in a help popup. ARA_Functions.hlink = function (toWhat, text) { var wgServer = window.wgServer || 'http://en.wikipedia.org'; var wgArticlePath = window.wgArticlePath || '/wiki/$1'; var url = (wgServer + wgArticlePath).replace('$1', toWhat); return '' + (text || toWhat) + ''; };	// === Helpers a la functional programming === // A higher-order function---produces a cached version of a one-arg function. ARA_Functions.makeCached = function (f) { var cache = {}; // a closure; the cache is private for f		return function (x) { return (cache[x] != null) ? cache[x] : (cache[x] = f(x)); };	};	// === Editor compatibility layer === // Controlling access to wpTextbox1 helps abstract out compatibility // with editors like wikEd (http://en.wikipedia.org/wiki/User:Cacycle/wikEd) ARA_Functions.getWikiText = function { if (window.wikEdUseWikEd) { var obj = {sel: WikEdGetSelection}; WikEdParseDOM(obj, wikEdFrameBody); return obj.plain; }		return JJJ.Constants.ARTICLE_TEXT_BOX_ELEMENT.val; };	ARA_Functions.setWikiText = function (s) { if (window.wikEdUseWikEd) { // todo: wikEd compatibility alert(JJJ.Functions._('Changing text in wikEd is not yet supported.')); return; };		JJJ.Constants.ARTICLE_TEXT_BOX_ELEMENT.val(s); };	ARA_Functions.focusWikiText = function { if (window.wikEdUseWikEd) { wikEdFrameWindow.focus; return; }		JJJ.Constants.ARTICLE_TEXT_BOX_ELEMENT.focus; };	ARA_Functions.selectWikiText = function (start, end) { if (window.wikEdUseWikEd) { var obj = x = {sel: WikEdGetSelection, changed: {}}; WikEdParseDOM(obj, wikEdFrameBody); var i = 0; while ((obj.plainStart[i + 1] != null) && (obj.plainStart[i + 1] <= start)) { i++; }			var j = i;			while ((obj.plainStart[j + 1] != null) && (obj.plainStart[j + 1] <= end)) { j++; }			obj.changed.range = document.createRange; obj.changed.range.setStart(obj.plainNode[i], start - obj.plainStart[i]); obj.changed.range.setEnd(obj.plainNode[j], end - obj.plainStart[j]); WikEdRemoveAllRanges(obj.sel); obj.sel.addRange(obj.changed.range); return; }		ARA_Functions.setSelectionRange(document.getElementById(JJJ.Constants.ARTICLE_TEXT_BOX_ELEMENT.prop('id')), start, end); };	ARA_Functions.observeWikiText = function (callback) { // todo: wikEd compatibility ARA_Functions.observe(document.getElementById(JJJ.Constants.ARTICLE_TEXT_BOX_ELEMENT.prop('id')), 'keyup', JJJ.Functions.delayScan); };	// === Interaction with the user === // ARA_Functions.scan analyses the text and handles how the proposals are reflected in the UI. ARA_Functions.scan = function (force) {		JJJ.Constants.scanTimeoutId = null; //get article text var s = JJJ.Functions.getWikiText; //determine if we actually need to scan if ((s === JJJ.Constants.scannedText) && !force) return; // Nothing to do, we've already scanned the very same text JJJ.Constants.scannedText = s;		//remove all current suggestions JJJ.Constants.SUGGESTION_BOX_DIV.empty; // Warn about scanning a big article if ((s.length > JJJ.Constants.BIG_THRESHOLD) && !JJJ.Constants.isBigScanConfirmed) { JJJ.Constants.SUGGESTION_BOX_DIV.append(document.createTextNode( JJJ.Functions._('This article is rather long. ARA may consume a lot of '					+ 'RAM and CPU resources while trying to parse the text.  You could limit '					+ 'your edit to a single section, or ') ));			JJJ.Constants.SUGGESTION_BOX_DIV.append(JJJ.Functions.anchor( JJJ.Functions._('scan the text anyway.'), 'javascript: JJJ.Constants.isBigScanConfirmed = true; JJJ.Functions.scan(true); void(0);', JJJ.Functions._('Ignore this warning.') ));			return; }		// Warn about scanning a talk page if ((  mw.config.get('wgCanonicalNamespace') === 'Talk' || mw.config.get('wgCanonicalNamespace') === 'User_talk' || mw.config.get('wgCanonicalNamespace') === 'Project_talk' || mw.config.get('wgCanonicalNamespace') === 'MediaWiki_talk' )		   && !JJJ.Constants.isTalkPageScanConfirmed		) {			JJJ.Constants.SUGGESTION_BOX_DIV.append(document.createTextNode( JJJ.Functions._('ARA is disabled on talk pages, because ' +					'it might suggest changing other users\' comments. That would be ' +					'something against talk page conventions.  If you promise to be ' +					'careful, you can ') ));			JJJ.Constants.SUGGESTION_BOX_DIV.append(JJJ.Functions.anchor( JJJ.Functions._('scan the text anyway.'), 'javascript: JJJ.Constants.isTalkPageScanConfirmed = true; JJJ.Functions.scan(true); void(0);', JJJ.Functions._('Ignore this warning.') ));			return; }		//get suggestions JJJ.Constants.suggestions = JJJ.Functions.getSuggestions(s); //if there aren't any suggestions, say so		if (JJJ.Constants.suggestions.length === 0) {			JJJ.Constants.SUGGESTION_BOX_DIV.append(document.createTextNode( JJJ.Functions._('OK \u2014 ARA found no referencing issues.') // U+2014 is an mdash ));			return; }		var nSuggestions = Math.min(JJJ.Constants.maxSuggestions, JJJ.Constants.suggestions.length); JJJ.Constants.SUGGESTION_BOX_DIV.append(document.createTextNode( (JJJ.Constants.suggestions.length == 1) ? JJJ.Functions._('1 suggestion: ') : JJJ.Functions._('$1 suggestions: ', JJJ.Constants.suggestions.length) ));		for (var i = 0; i < nSuggestions; i++) { var suggestion = JJJ.Constants.suggestions[i]; var eA = JJJ.Functions.anchor(					suggestion.name,					'javascript:JJJ.Functions.showSuggestion(' + i + '); void(0);',					suggestion.description			); suggestion.element = eA; JJJ.Constants.SUGGESTION_BOX_DIV.append(eA); if (suggestion.replacement != null) {				var eSup = document.createElement('SUP'); JJJ.Constants.SUGGESTION_BOX_DIV.append(eSup); var sup1 = suggestion.sup1 != null ? suggestion.sup1 : 'fix'; eSup.appendChild (					JJJ.Functions.anchor ( JJJ.Functions._(sup1), 'javascript:JJJ.Functions.fixSuggestion(' + i + '); void(0);' )				);				//sometimes, suggestions may have more than one fix link if (suggestion.replacement2 != null) {					var sup2 = suggestion.sup2 != null ? suggestion.sup2 : 'fix2'; eSup.appendChild(document.createTextNode(' | ')); eSup.appendChild(						JJJ.Functions.anchor( JJJ.Functions._(sup2), 'javascript:JJJ.Functions.fixSuggestion2(' + i + '); void(0);' )					);				}				if (suggestion.replacement3 != null) {					var sup3 = suggestion.sup3 != null ? suggestion.sup3 : 'fix3'; eSup.appendChild(document.createTextNode(' | ')); eSup.appendChild(						JJJ.Functions.anchor( JJJ.Functions._(sup3), 'javascript:JJJ.Functions.fixSuggestion3(' + i + '); void(0);' )					);				}			}			JJJ.Constants.SUGGESTION_BOX_DIV.append(document.createTextNode(' ')); }		if (JJJ.Constants.suggestions.length > JJJ.Constants.maxSuggestions) { JJJ.Constants.SUGGESTION_BOX_DIV.append(JJJ.Functions.anchor( '...', 'javascript: JJJ.Constants.maxSuggestions = 1000; JJJ.Functions.scan(true); void(0);', JJJ.Functions._('Show All') ));		}	};	// getSuggestions returns the raw data used by scan. // It is convenient for unit testing. ARA_Functions.getSuggestions = function (s) { var suggestions = []; var missingRefGroupSuggestions = []; //we want to keep track of the ones we already have so we don't push the same message twice for (var i = 0; i < JJJ.Rules.length; i++) //for each rule {			var a = JJJ.Rules[i](s); //execute rule for (var j = 0; j < a.length; j++) //for each suggestion pushed by the rule {				var returned_suggestion = a[j]; //if the suggestion is not a missing reference groups suggestion, or it is and we didn't already push this one if (!returned_suggestion.name.includes("missing reference groups") || !missingRefGroupSuggestions.includes(returned_suggestion.name)) {					suggestions.push(returned_suggestion); //add suggestion to list of suggestions missingRefGroupSuggestions.push(returned_suggestion.name); //add suggestion to list of suggestions we already have }			}		}		suggestions.sort(function (x, y) {			return (x.start < y.start) ? -1 :			      (x.start > y.start) ? 1 :			       (x.end < y.end) ? -1 :			       (x.end > y.end) ? 1 : 0;		}); return suggestions; };	// === Internationalisation === // ARA_Functions._ is a gettext-style internationalisation helper // (http://en.wikipedia.org/wiki/gettext) // If no translation is found for the parameter, it is returned as is. // Additionally, subsequent parameters are substituted for $1, $2, and so on. ARA_Functions._ = function (s) { if (JJJ.Constants.translation && JJJ.Constants.translation[s]) { s = JJJ.Constants.translation[s]; }		var index = 1; while (arguments[index]) { s = s.replace('$' + index, arguments[index]); // todo: replace all? index++; }		return s;	}; // showSuggestion handles clicks on the suggestions above the edit area // This does one of two things: // * on first click---highlight the corresponding text in the textarea // * on a second click, no later than a fixed number milliseconds after the // 		first one---show the help popup ARA_Functions.showSuggestion = function (k) { if (JJJ.Functions.getWikiText != JJJ.Constants.scannedText) { // The text has changed - just do another scan and don't change selection JJJ.Functions.scan; return; }		var suggestion = JJJ.Constants.suggestions[k]; var now = new Date.getTime; if ((suggestion.help != null) && (JJJ.Constants.lastShownSuggestionIndex === k) && (now - JJJ.Constants.lastShownSuggestionTime < 1000)) { // Show help var p = JJJ.Functions.getPosition(suggestion.element); var POPUP_WIDTH = 300; var eDiv = document.createElement('DIV'); eDiv.innerHTML = suggestion.help; eDiv.style.position = 'absolute'; eDiv.style.left = Math.max(0, Math.min(p.x, document.body.clientWidth - POPUP_WIDTH)) + 'px'; eDiv.style.top = (p.y + suggestion.element.offsetHeight) + 'px'; eDiv.style.border = 'solid ThreeDShadow 1px'; eDiv.style.backgroundColor = 'InfoBackground'; eDiv.style.fontSize = '12px'; eDiv.style.color = 'InfoText'; eDiv.style.width = POPUP_WIDTH + 'px'; eDiv.style.padding = '0.3em'; eDiv.style.zIndex = 10; document.body.appendChild(eDiv); JJJ.Functions.observe(document.body, 'click', function (event) {				event = event || window.event;				var target = event.target || event.srcElement;				var e = target;				while (e != null) {					if (e == eDiv) {						return;					}					e = e.parentNode;				}				document.body.removeChild(eDiv);				JJJ.Functions.stopObserving(document.body, 'click', arguments.callee);			}); JJJ.Functions.focusWikiText; return; }		JJJ.Constants.lastShownSuggestionIndex = k;		JJJ.Constants.lastShownSuggestionTime = now; JJJ.Functions.selectWikiText(suggestion.start, suggestion.end); };	// Usually, there is a ``fix'' link next to each suggestion. It is handled by: ARA_Functions.fixSuggestion = function(k) {		var s = JJJ.Functions.getWikiText; if (s != JJJ.Constants.scannedText) { JJJ.Functions.scan; return; }		var suggestion = JJJ.Constants.suggestions[k]; // the issue is not automatically fixable, return if (suggestion.replacement == null) { return; }		JJJ.Functions.setWikiText(				s.substring(0, suggestion.start)				+ suggestion.replacement				+ s.substring(suggestion.end)		); JJJ.Functions.selectWikiText(				suggestion.start,				suggestion.start + suggestion.replacement.length		); // Propose an edit summary unless it's a new section var editform = document.getElementById('editform'); if (!editform['wpSection'] || (editform['wpSection'].value != 'new')) { if (JJJ.Constants.appliedSuggestions[suggestion.name] == null) { JJJ.Constants.appliedSuggestions[suggestion.name] = 1; } else { JJJ.Constants.appliedSuggestions[suggestion.name]++; }			var a = []; for (var i in JJJ.Constants.appliedSuggestions) { a.push(i); }			a.sort(function (x, y) {				return (JJJ.Constants.appliedSuggestions[x] > JJJ.Constants.appliedSuggestions[y]) ? -1 :					  (JJJ.Constants.appliedSuggestions[x] < JJJ.Constants.appliedSuggestions[y]) ? 1 :					   (x < y) ? -1 : (x > y) ? 1 : 0;			}); var s = ''; for (var i = 0; i < a.length; i++) { var count = JJJ.Constants.appliedSuggestions[a[i]]; s += ', ' + ((count == 1) ? a[i] : (count + 'x ' + a[i])); }			// Cut off the leading ``,  and add ``using ARA s = JJJ.Functions._(					'fixed CS1 \'\'markup\'\' error(s) likely via script',					s.substring(2)	                       ); // Render in DOM JJJ.Constants.ADD_TO_SUMMARY_DIV.empty; JJJ.Constants.ADD_TO_SUMMARY_DIV.show; JJJ.Constants.ADD_TO_SUMMARY_DIV.append(JJJ.Functions.anchor( JJJ.Functions._('Add to summary'), 'javascript:JJJ.Functions.addToSummary(unescape("' + escape(s) + '"));', JJJ.Functions._('Append the proposed summary to the input field below') ));			JJJ.Constants.ADD_TO_SUMMARY_DIV.append(document.createTextNode(': "' + s + '"')); }		// Re-scan immediately JJJ.Functions.scan; };	// if a suggestion has two 'fix' options, the second option will be handled here ARA_Functions.fixSuggestion2 = function (k) {		var s = JJJ.Functions.getWikiText; if (s != JJJ.Constants.scannedText) { JJJ.Functions.scan; return; }		var suggestion = JJJ.Constants.suggestions[k];

// the issue is not automatically fixable, return if (suggestion.replacement2 == null) { return; }		//otherwise, if we are executing JS, do so		else if (suggestion.replacement2.includes("javascript:")) {			eval(suggestion.replacement2); return; }		JJJ.Functions.setWikiText(				s.substring(0, suggestion.start2)				+ suggestion.replacement2				+ s.substring(suggestion.end2)		); JJJ.Functions.selectWikiText(				suggestion.start2,				suggestion.start2 + suggestion.replacement2.length		); // Propose an edit summary unless it's a new section var editform = document.getElementById('editform'); if (!editform['wpSection'] || (editform['wpSection'].value != 'new')) { if (JJJ.Constants.appliedSuggestions[suggestion.name] == null) { JJJ.Constants.appliedSuggestions[suggestion.name] = 1; } else { JJJ.Constants.appliedSuggestions[suggestion.name]++; }			var a = []; for (var i in JJJ.Constants.appliedSuggestions) { a.push(i); }			a.sort(function (x, y) {				return (JJJ.Constants.appliedSuggestions[x] > JJJ.Constants.appliedSuggestions[y]) ? -1 :					  (JJJ.Constants.appliedSuggestions[x] < JJJ.Constants.appliedSuggestions[y]) ? 1 :					   (x < y) ? -1 : (x > y) ? 1 : 0;			}); var s = ''; for (var i = 0; i < a.length; i++) { var count = JJJ.Constants.appliedSuggestions[a[i]]; s += ', ' + ((count == 1) ? a[i] : (count + 'x ' + a[i])); }			// Cut off the leading ``,  and add ``using ARA s = JJJ.Functions._(					'fixed CS1 \'\'markup\'\' error(s) likely via script',					s.substring(2)	                       ); // Render in DOM JJJ.Constants.ADD_TO_SUMMARY_DIV.empty; JJJ.Constants.ADD_TO_SUMMARY_DIV.show; JJJ.Constants.ADD_TO_SUMMARY_DIV.append(JJJ.Functions.anchor( JJJ.Functions._('Add to summary'), 'javascript:JJJ.Functions.addToSummary(unescape("' + escape(s) + '"));', JJJ.Functions._('Append the proposed summary to the input field below') ));			JJJ.Constants.ADD_TO_SUMMARY_DIV.append(document.createTextNode(': "' + s + '"')); }		// Re-scan immediately JJJ.Functions.scan; };	ARA_Functions.fixSuggestion3 = function (k) {		var s = JJJ.Functions.getWikiText; if (s != JJJ.Constants.scannedText) { JJJ.Functions.scan; return; }		var suggestion = JJJ.Constants.suggestions[k]; if (suggestion.replacement3 == null) { // the issue is not automatically fixable return; }		JJJ.Functions.setWikiText(				s.substring(0, suggestion.start3)				+ suggestion.replacement3				+ s.substring(suggestion.end3)		); JJJ.Functions.selectWikiText(				suggestion.start3,				suggestion.start3 + suggestion.replacement3.length		); // Propose an edit summary unless it's a new section var editform = document.getElementById('editform'); if (!editform['wpSection'] || (editform['wpSection'].value != 'new')) { if (JJJ.Constants.appliedSuggestions[suggestion.name] == null) { JJJ.Constants.appliedSuggestions[suggestion.name] = 1; } else { JJJ.Constants.appliedSuggestions[suggestion.name]++; }			var a = []; for (var i in JJJ.Constants.appliedSuggestions) { a.push(i); }			a.sort(function (x, y) {				return (JJJ.Constants.appliedSuggestions[x] > JJJ.Constants.appliedSuggestions[y]) ? -1 :					  (JJJ.Constants.appliedSuggestions[x] < JJJ.Constants.appliedSuggestions[y]) ? 1 :					   (x < y) ? -1 : (x > y) ? 1 : 0;			}); var s = ''; for (var i = 0; i < a.length; i++) { var count = JJJ.Constants.appliedSuggestions[a[i]]; s += ', ' + ((count == 1) ? a[i] : (count + 'x ' + a[i])); }			// Cut off the leading ``,  and add ``using ARA s = JJJ.Functions._(					'fixed CS1 \'\'markup\'\' error(s) likely via script',					s.substring(2)	                       ); // Render in DOM JJJ.Constants.ADD_TO_SUMMARY_DIV.empty; JJJ.Constants.ADD_TO_SUMMARY_DIV.show; JJJ.Constants.ADD_TO_SUMMARY_DIV.append(JJJ.Functions.anchor( JJJ.Functions._('Add to summary'), 'javascript:JJJ.Functions.addToSummary(unescape("' + escape(s) + '"));', JJJ.Functions._('Append the proposed summary to the input field below') ));			JJJ.Constants.ADD_TO_SUMMARY_DIV.append(document.createTextNode(': "' + s + '"')); }		// Re-scan immediately JJJ.Functions.scan; };	// The mnemonics of the accepted suggestions are accumulated in JJJ.Constants.appliedSuggestions // and the user is presented with a sample edit summary. If she accepts it, // addToSummary gets called. ARA_Functions.addToSummary = function (summary) { var wpSummary = document.getElementById('wpSummary'); if (wpSummary.value != '') { summary = wpSummary.value + '; ' + summary; }		if ((wpSummary.maxLength > 0) && (summary.length > wpSummary.maxLength)) { alert(JJJ.Funtions._( 'Error: If the proposed text is added to the summary, ' + 'its length will exceed the $1-character maximum by $2 characters.', /* $1 = */ wpSummary.maxLength, /* $2 = */ summary.length - wpSummary.maxLength ));			return; }		wpSummary.value = summary; JJJ.Constants.ADD_TO_SUMMARY_DIV.hide; };	// delayScan postpones the invocation of scan with a certain timeout. // If delayScan is invoked once again during that time, the original // timeout is cancelled, and another, clean timeout is started from zero. //	// delayScan will normally be invoked when a key is pressed---this // prevents frequent re-scans while the user is typing. ARA_Functions.delayScan = function { if (JJJ.Constants.scanTimeoutId != null) { clearTimeout(JJJ.Constants.scanTimeoutId); JJJ.Constants.scanTimeoutId = null; }		JJJ.Constants.scanTimeoutId = setTimeout(JJJ.Functions.scan, 500); };	return ARA_Functions; }

function getARARules {	var ARA_Rules = []; // == Rules == // properties: // * start---the 0-based inclusive index of the first character to be replaced // * end---analogous to start, but exclusive // * replacement---the proposed wikitext // * name---this is what appears at the top of the page // * description---used as a tooltip for the name of the suggestion if (!mw.config.get('wgContentLanguage') || mw.config.get('wgContentLanguage') === 'en') { // from this line on, a level of indent is spared // The rules are stored in an array and are grouped into categories. //*****************************************************************************************	//*****************************************************************************************	// === Functions === /* ITALIC MARKUP HERE */ //***publisher parameter contains italic markup*** ARA_Rules.push(function (s) {		var b = [];

//get indices of all '|publisher='s	   var startIndex = 0; var searchStr = "|publisher="; var searchStrLen = searchStr.length; var index, indices = []; while ((index = s.indexOf(searchStr, startIndex)) > -1) {		   indices.push(index); startIndex = index + searchStrLen; }		var indicesLength = indices.length; for (i = 0; i < indicesLength; i++) //for each |publisher= {			var pubStartIndex = indices[i] + searchStr.length; var indexOnward  = s.substring(pubStartIndex); //+searchStr.length to exclude "|publisher=\'\'" //get to the actual beginning of the Publisher if there are spaces or newlines after the "publisher=" and before the start of the text while ((indexOnward[0] == ' ' || indexOnward[0] == '\n')) {				indexOnward = indexOnward.substring(1); //cut off the first character ++pubStartIndex; }			var fullRef         = indexOnward; var fullRefPrevIndex = pubStartIndex - 1; //indices of various characters in the citation var firstBracketAfterIndex = indexOnward.includes("}") ? indexOnward.indexOf("}") : s.length; var firstBarAfterIndex    = indexOnward.includes("|") ? indexOnward.indexOf("|") : s.length; //get to the end of the citation fullRef = fullRef.substring(0, firstBracketAfterIndex); //get to the beginning of the citation while (fullRefPrevIndex >= 0 && s.charAt(fullRefPrevIndex) != '{') {	             fullRef = s.charAt(fullRefPrevIndex) + fullRef; //prepend the character --fullRefPrevIndex; //decrement index }	   	//now we have the full ref. //get the entire publisher parameter. The parameter should either end with another | or }} for the end of the ref (if not malformed) //find the nearest delimeter var cutOffIndex = firstBarAfterIndex; if (firstBracketAfterIndex < cutOffIndex) cutOffIndex = firstBracketAfterIndex; var pub = indexOnward.substring(0, cutOffIndex).trim; //the pub parameter //If |publisher= ends with italic markup if (pub.endsWith('\'\'')) {				b.push({					start:       pubStartIndex + pub.length - 2,					end:          pubStartIndex + pub.length,					replacement:  '',					name:         '|publisher= ends with italic markup',					description:  '|publisher= ends with italic markup',				}); }		}		return b;	});	ARA_Rules.push(function (s) { var b = []; //If the publisher begins with italic markup var replaceableStrings = ["publisher=\'\'", " publisher = \'\'", " publisher= \'\'", "publisher =\'\'", "publisher= \'\'", " publisher=\'\'"]; for (i = 0; i < replaceableStrings.length; i++) {			var replaceableString = replaceableStrings[i]; if (s.includes(replaceableString)) {				b.push({					start: s.indexOf(replaceableString),					end:  s.indexOf(replaceableString) + replaceableString.length,					replacement: replaceableString.replace("\'\'", ""), 					name:         '|publisher= begins with italic markup',					description:  '|publisher= begins with italic markup',				}); }		}		return b;	});	//***website parameter contains italic markup***	ARA_Rules.push(function (s) { var b = [];

//get indices of all '|website='s	   var startIndex = 0; var searchStr = "|website="; var searchStrLen = searchStr.length; var index, indices = []; while ((index = s.indexOf(searchStr, startIndex)) > -1) {		   indices.push(index); startIndex = index + searchStrLen; }		var indicesLength = indices.length; for (i = 0; i < indicesLength; i++) //for each |website= {			var webStartIndex = indices[i] + searchStr.length; var indexOnward  = s.substring(webStartIndex); //+searchStr.length to exclude "|website=\'\'" //get to the actual beginning of the website if there are spaces or newlines after the "website=" and before the start of the text while ((indexOnward[0] == ' ' || indexOnward[0] == '\n')) {				indexOnward = indexOnward.substring(1); //cut off the first character ++webStartIndex; }			var fullRef         = indexOnward; var fullRefPrevIndex = webStartIndex - 1; //indices of various characters in the citation var firstBracketAfterIndex = indexOnward.includes("}") ? indexOnward.indexOf("}") : s.length; var firstBarAfterIndex    = indexOnward.includes("|") ? indexOnward.indexOf("|") : s.length; //get to the end of the citation fullRef = fullRef.substring(0, firstBracketAfterIndex); //get to the beginning of the citation while (fullRefPrevIndex >= 0 && s.charAt(fullRefPrevIndex) != '{') {	             fullRef = s.charAt(fullRefPrevIndex) + fullRef; //prepend the character --fullRefPrevIndex; //decrement index }	   	//now we have the full ref. //get the entire website parameter. The parameter should either end with another | or }} for the end of the ref (if not malformed) //find the nearest delimeter var cutOffIndex = firstBarAfterIndex; if (firstBracketAfterIndex < cutOffIndex) cutOffIndex = firstBracketAfterIndex; var web = indexOnward.substring(0, cutOffIndex).trim; //the web parameter //If the website ends with italic markup if (web.endsWith('\'\'')) {				b.push({					start:       webStartIndex + web.length - 2,					end:          webStartIndex + web.length,					replacement:  '',					name:         '|website= ends with italic markup',					description:  '|website= ends with italic markup',				}); }		}		return b;	});	ARA_Rules.push(function (s) { var b = []; //If the website begins with italic markup var replaceableStrings = ["website=\'\'", " website = \'\'", " website= \'\'", "website =\'\'", "website= \'\'", " website=\'\'"]; for (i = 0; i < replaceableStrings.length; i++) {			var replaceableString = replaceableStrings[i]; if (s.includes(replaceableString)) {				b.push({					start: s.indexOf(replaceableString),					end:  s.indexOf(replaceableString) + replaceableString.length,					replacement: replaceableString.replace("\'\'", ""), 					name:         '|website= begins with italic markup',					description:  '|website= begins with italic markup',				}); }		}		return b;	});		//***magazine parameter contains italic markup***	ARA_Rules.push(function (s) { var b = [];

//get indices of all '|magazine='s	   var startIndex = 0; var searchStr = "|magazine="; var searchStrLen = searchStr.length; var index, indices = []; while ((index = s.indexOf(searchStr, startIndex)) > -1) {		   indices.push(index); startIndex = index + searchStrLen; }		var indicesLength = indices.length; for (i = 0; i < indicesLength; i++) //for each |magazine= {			var magStartIndex = indices[i] + searchStr.length; var indexOnward  = s.substring(magStartIndex); //+searchStr.length to exclude "|magazine=\'\'" //get to the actual beginning of the magazine if there are spaces or newlines after the "magazine=" and before the start of the text while ((indexOnward[0] == ' ' || indexOnward[0] == '\n')) {				indexOnward = indexOnward.substring(1); //cut off the first character ++magStartIndex; }			var fullRef         = indexOnward; var fullRefPrevIndex = magStartIndex - 1; //indices of various characters in the citation var firstBracketAfterIndex = indexOnward.includes("}") ? indexOnward.indexOf("}") : s.length; var firstBarAfterIndex    = indexOnward.includes("|") ? indexOnward.indexOf("|") : s.length; //get to the end of the citation fullRef = fullRef.substring(0, firstBracketAfterIndex); //get to the beginning of the citation while (fullRefPrevIndex >= 0 && s.charAt(fullRefPrevIndex) != '{') {	             fullRef = s.charAt(fullRefPrevIndex) + fullRef; //prepend the character --fullRefPrevIndex; //decrement index }	   	//now we have the full ref. //get the entire magazine parameter. The parameter should either end with another | or }} for the end of the ref (if not malformed) //find the nearest delimeter var cutOffIndex = firstBarAfterIndex; if (firstBracketAfterIndex < cutOffIndex) cutOffIndex = firstBracketAfterIndex; var mag = indexOnward.substring(0, cutOffIndex).trim; //the mag parameter //If |magazine= ends with italic markup if (mag.endsWith('\'\'')) {				b.push({					start:       magStartIndex + mag.length - 2,					end:          magStartIndex + mag.length,					replacement:  '',					name:         '|magazine= ends with italic markup',					description:  '|magazine= ends with italic markup',				}); }		}		return b;	});	ARA_Rules.push(function (s) { var b = []; //If the magazine begins with italic markup var replaceableStrings = ["magazine=\'\'", " magazine = \'\'", " magazine= \'\'", "magazine =\'\'", "magazine= \'\'", " magazine=\'\'"]; for (i = 0; i < replaceableStrings.length; i++) {			var replaceableString = replaceableStrings[i]; if (s.includes(replaceableString)) {				b.push({					start: s.indexOf(replaceableString),					end:  s.indexOf(replaceableString) + replaceableString.length,					replacement: replaceableString.replace("\'\'", ""), 					name:         '|magazine= begins with italic markup',					description:  '|magazine= begins with italic markup',				}); }		}		return b;	});	//***work parameter contains italic markup***	ARA_Rules.push(function (s) { var b = [];

//get indices of all '|work='s	   var startIndex = 0; var searchStr = "|work="; var searchStrLen = searchStr.length; var index, indices = []; while ((index = s.indexOf(searchStr, startIndex)) > -1) {		   indices.push(index); startIndex = index + searchStrLen; }		var indicesLength = indices.length; for (i = 0; i < indicesLength; i++) //for each |work= {			var worStartIndex = indices[i] + searchStr.length; var indexOnward  = s.substring(worStartIndex); //+searchStr.length to exclude "|work=\'\'" //get to the actual beginning of the work if there are spaces or newlines after the "work=" and before the start of the text while ((indexOnward[0] == ' ' || indexOnward[0] == '\n')) {				indexOnward = indexOnward.substring(1); //cut off the first character ++worStartIndex; }			var fullRef         = indexOnward; var fullRefPrevIndex = worStartIndex - 1; //indices of various characters in the citation var firstBracketAfterIndex = indexOnward.includes("}") ? indexOnward.indexOf("}") : s.length; var firstBarAfterIndex    = indexOnward.includes("|") ? indexOnward.indexOf("|") : s.length; //get to the end of the citation fullRef = fullRef.substring(0, firstBracketAfterIndex); //get to the beginning of the citation while (fullRefPrevIndex >= 0 && s.charAt(fullRefPrevIndex) != '{') {	             fullRef = s.charAt(fullRefPrevIndex) + fullRef; //prepend the character --fullRefPrevIndex; //decrement index }	   	//now we have the full ref. //get the entire work parameter. The parameter should either end with another | or }} for the end of the ref (if not malformed) //find the nearest delimeter var cutOffIndex = firstBarAfterIndex; if (firstBracketAfterIndex < cutOffIndex) cutOffIndex = firstBracketAfterIndex; var wor = indexOnward.substring(0, cutOffIndex).trim; //the wor parameter //If the work ends with italic markup if (wor.endsWith('\'\'')) {				b.push({					start:       worStartIndex + wor.length - 2,					end:          worStartIndex + wor.length,					replacement:  '',					name:         '|work= ends with italic markup',					description:  '|work= ends with italic markup',				}); }		}		return b;	});	ARA_Rules.push(function (s) { var b = []; //If the work begins with italic markup var replaceableStrings = ["work=\'\'", " work = \'\'", " work= \'\'", "work =\'\'", "work= \'\'", " work=\'\'"]; for (i = 0; i < replaceableStrings.length; i++) {			var replaceableString = replaceableStrings[i]; if (s.includes(replaceableString)) {				b.push({					start: s.indexOf(replaceableString),					end:  s.indexOf(replaceableString) + replaceableString.length,					replacement: replaceableString.replace("\'\'", ""), 					name:         '|work= begins with italic markup',					description:  '|work= begins with italic markup',				}); }		}		return b;	});		//***periodical parameter contains italic markup***	ARA_Rules.push(function (s) { var b = [];

//get indices of all '|periodical='s	   var startIndex = 0; var searchStr = "|periodical="; var searchStrLen = searchStr.length; var index, indices = []; while ((index = s.indexOf(searchStr, startIndex)) > -1) {		   indices.push(index); startIndex = index + searchStrLen; }		var indicesLength = indices.length; for (i = 0; i < indicesLength; i++) //for each |periodical= {			var perStartIndex = indices[i] + searchStr.length; var indexOnward  = s.substring(perStartIndex); //+searchStr.length to exclude "|periodical=\'\'" //get to the actual beginning of the periodical if there are spaces or newlines after the "periodical=" and before the start of the text while ((indexOnward[0] == ' ' || indexOnward[0] == '\n')) {				indexOnward = indexOnward.substring(1); //cut off the first character ++perStartIndex; }			var fullRef         = indexOnward; var fullRefPrevIndex = perStartIndex - 1; //indices of various characters in the citation var firstBracketAfterIndex = indexOnward.includes("}") ? indexOnward.indexOf("}") : s.length; var firstBarAfterIndex    = indexOnward.includes("|") ? indexOnward.indexOf("|") : s.length; //get to the end of the citation fullRef = fullRef.substring(0, firstBracketAfterIndex); //get to the beginning of the citation while (fullRefPrevIndex >= 0 && s.charAt(fullRefPrevIndex) != '{') {	             fullRef = s.charAt(fullRefPrevIndex) + fullRef; //prepend the character --fullRefPrevIndex; //decrement index }	   	//now we have the full ref. //get the entire periodical parameter. The parameter should either end with another | or }} for the end of the ref (if not malformed) //find the nearest delimeter var cutOffIndex = firstBarAfterIndex; if (firstBracketAfterIndex < cutOffIndex) cutOffIndex = firstBracketAfterIndex; var per = indexOnward.substring(0, cutOffIndex).trim; //the per parameter //If |periodical= ends with italic markup if (per.endsWith('\'\'')) {				b.push({					start:       perStartIndex + per.length - 2,					end:          perStartIndex + per.length,					replacement:  '',					name:         '|periodical= ends with italic markup',					description:  '|periodical= ends with italic markup',				}); }		}		return b;	});	ARA_Rules.push(function (s) { var b = []; //If the periodical begins with italic markup var replaceableStrings = ["periodical=\'\'", " periodical = \'\'", " periodical= \'\'", "periodical =\'\'", "periodical= \'\'", " periodical=\'\'"]; for (i = 0; i < replaceableStrings.length; i++) {			var replaceableString = replaceableStrings[i]; if (s.includes(replaceableString)) {				b.push({					start: s.indexOf(replaceableString),					end:  s.indexOf(replaceableString) + replaceableString.length,					replacement: replaceableString.replace("\'\'", ""), 					name:         '|periodical= begins with italic markup',					description:  '|periodical= begins with italic markup',				}); }		}		return b;	});	//***newspaper parameter contains italic markup***	ARA_Rules.push(function (s) { var b = [];

//get indices of all '|newspaper='s	   var startIndex = 0; var searchStr = "|newspaper="; var searchStrLen = searchStr.length; var index, indices = []; while ((index = s.indexOf(searchStr, startIndex)) > -1) {		   indices.push(index); startIndex = index + searchStrLen; }		var indicesLength = indices.length; for (i = 0; i < indicesLength; i++) //for each |newspaper= {			var nwpStartIndex = indices[i] + searchStr.length; var indexOnward  = s.substring(nwpStartIndex); //+searchStr.length to exclude "|newspaper=\'\'" //get to the actual beginning of the newspaper if there are spaces or newlines after the "newspaper=" and before the start of the text while ((indexOnward[0] == ' ' || indexOnward[0] == '\n')) {				indexOnward = indexOnward.substring(1); //cut off the first character ++nwpStartIndex; }			var fullRef         = indexOnward; var fullRefPrevIndex = nwpStartIndex - 1; //indices of various characters in the citation var firstBracketAfterIndex = indexOnward.includes("}") ? indexOnward.indexOf("}") : s.length; var firstBarAfterIndex    = indexOnward.includes("|") ? indexOnward.indexOf("|") : s.length; //get to the end of the citation fullRef = fullRef.substring(0, firstBracketAfterIndex); //get to the beginning of the citation while (fullRefPrevIndex >= 0 && s.charAt(fullRefPrevIndex) != '{') {	             fullRef = s.charAt(fullRefPrevIndex) + fullRef; //prepend the character --fullRefPrevIndex; //decrement index }	   	//now we have the full ref. //get the entire newspaper parameter. The parameter should either end with another | or }} for the end of the ref (if not malformed) //find the nearest delimeter var cutOffIndex = firstBarAfterIndex; if (firstBracketAfterIndex < cutOffIndex) cutOffIndex = firstBracketAfterIndex; var nwp = indexOnward.substring(0, cutOffIndex).trim; //the nwp parameter //If the newspaper ends with italic markup if (nwp.endsWith('\'\'')) {				b.push({					start:       nwpStartIndex + nwp.length - 2,					end:          nwpStartIndex + nwp.length,					replacement:  '',					name:         '|newspaper= ends with italic markup',					description:  '|newspaper= ends with italic markup',				}); }		}		return b;	});	ARA_Rules.push(function (s) { var b = []; //If the newspaper begins with italic markup var replaceableStrings = ["newspaper=\'\'", " newspaper = \'\'", " newspaper= \'\'", "newspaper =\'\'", "newspaper= \'\'", " newspaper=\'\'"]; for (i = 0; i < replaceableStrings.length; i++) {			var replaceableString = replaceableStrings[i]; if (s.includes(replaceableString)) {				b.push({					start: s.indexOf(replaceableString),					end:  s.indexOf(replaceableString) + replaceableString.length,					replacement: replaceableString.replace("\'\'", ""), 					name:         '|newspaper= begins with italic markup',					description:  '|newspaper= begins with italic markup',				}); }		}		return b;	});		//***journal parameter contains italic markup***	ARA_Rules.push(function (s) { var b = [];

//get indices of all '|journal='s	   var startIndex = 0; var searchStr = "|journal="; var searchStrLen = searchStr.length; var index, indices = []; while ((index = s.indexOf(searchStr, startIndex)) > -1) {		   indices.push(index); startIndex = index + searchStrLen; }		var indicesLength = indices.length; for (i = 0; i < indicesLength; i++) //for each |journal= {			var jorStartIndex = indices[i] + searchStr.length; var indexOnward  = s.substring(jorStartIndex); //+searchStr.length to exclude "|journal=\'\'" //get to the actual beginning of the journal if there are spaces or newlines after the "journal=" and before the start of the text while ((indexOnward[0] == ' ' || indexOnward[0] == '\n')) {				indexOnward = indexOnward.substring(1); //cut off the first character ++jorStartIndex; }			var fullRef         = indexOnward; var fullRefPrevIndex = jorStartIndex - 1; //indices of various characters in the citation var firstBracketAfterIndex = indexOnward.includes("}") ? indexOnward.indexOf("}") : s.length; var firstBarAfterIndex    = indexOnward.includes("|") ? indexOnward.indexOf("|") : s.length; //get to the end of the citation fullRef = fullRef.substring(0, firstBracketAfterIndex); //get to the beginning of the citation while (fullRefPrevIndex >= 0 && s.charAt(fullRefPrevIndex) != '{') {	             fullRef = s.charAt(fullRefPrevIndex) + fullRef; //prepend the character --fullRefPrevIndex; //decrement index }	   	//now we have the full ref. //get the entire journal parameter. The parameter should either end with another | or }} for the end of the ref (if not malformed) //find the nearest delimeter var cutOffIndex = firstBarAfterIndex; if (firstBracketAfterIndex < cutOffIndex) cutOffIndex = firstBracketAfterIndex; var jor = indexOnward.substring(0, cutOffIndex).trim; //the jor parameter //If |journal= ends with italic markup if (jor.endsWith('\'\'')) {				b.push({					start:       jorStartIndex + jor.length - 2,					end:          jorStartIndex + jor.length,					replacement:  '',					name:         '|journal= ends with italic markup',					description:  '|journal= ends with italic markup',				}); }		}		return b;	});	ARA_Rules.push(function (s) { var b = []; //If the journal begins with italic markup var replaceableStrings = ["journal=\'\'", " journal = \'\'", " journal= \'\'", "journal =\'\'", "journal= \'\'", " journal=\'\'"]; for (i = 0; i < replaceableStrings.length; i++) {			var replaceableString = replaceableStrings[i]; if (s.includes(replaceableString)) {				b.push({					start: s.indexOf(replaceableString),					end:  s.indexOf(replaceableString) + replaceableString.length,					replacement: replaceableString.replace("\'\'", ""), 					name:         '|journal= begins with italic markup',					description:  '|journal= begins with italic markup',				}); }		}		return b;	});	/* BOLD MARKUP HERE */		//***publisher parameter contains bold markup***	ARA_Rules.push(function (s) { var b = [];

//get indices of all '|publisher='s	   var startIndex = 0; var searchStr = "|publisher="; var searchStrLen = searchStr.length; var index, indices = []; while ((index = s.indexOf(searchStr, startIndex)) > -1) {		   indices.push(index); startIndex = index + searchStrLen; }		var indicesLength = indices.length; for (i = 0; i < indicesLength; i++) //for each |publisher= {			var pubStartIndex = indices[i] + searchStr.length; var indexOnward  = s.substring(pubStartIndex); //+searchStr.length to exclude "|publisher=\'\'\'" //get to the actual beginning of the Publisher if there are spaces or newlines after the "publisher=" and before the start of the text while ((indexOnward[0] == ' ' || indexOnward[0] == '\n')) {				indexOnward = indexOnward.substring(1); //cut off the first character ++pubStartIndex; }			var fullRef         = indexOnward; var fullRefPrevIndex = pubStartIndex - 1; //indices of various characters in the citation var firstBracketAfterIndex = indexOnward.includes("}") ? indexOnward.indexOf("}") : s.length; var firstBarAfterIndex    = indexOnward.includes("|") ? indexOnward.indexOf("|") : s.length; //get to the end of the citation fullRef = fullRef.substring(0, firstBracketAfterIndex); //get to the beginning of the citation while (fullRefPrevIndex >= 0 && s.charAt(fullRefPrevIndex) != '{') {	             fullRef = s.charAt(fullRefPrevIndex) + fullRef; //prepend the character --fullRefPrevIndex; //decrement index }	   	//now we have the full ref. //get the entire publisher parameter. The parameter should either end with another | or }} for the end of the ref (if not malformed) //find the nearest delimeter var cutOffIndex = firstBarAfterIndex; if (firstBracketAfterIndex < cutOffIndex) cutOffIndex = firstBracketAfterIndex; var pub = indexOnward.substring(0, cutOffIndex).trim; //the pub parameter //If |publisher= ends with bold markup if (pub.endsWith('\'\'\'')) {				b.push({					start:       pubStartIndex + pub.length - 2,					end:          pubStartIndex + pub.length,					replacement:  '',					name:         '|publisher= ends with bold markup',					description:  '|publisher= ends with bold markup',				}); }		}		return b;	});	ARA_Rules.push(function (s) { var b = []; //If the publisher begins with bold markup var replaceableStrings = ["publisher=\'\'\'", " publisher = \'\'\'", " publisher= \'\'\'", "publisher =\'\'\'", "publisher= \'\'\'", " publisher=\'\'\'"]; for (i = 0; i < replaceableStrings.length; i++) {			var replaceableString = replaceableStrings[i]; if (s.includes(replaceableString)) {				b.push({					start: s.indexOf(replaceableString),					end:  s.indexOf(replaceableString) + replaceableString.length,					replacement: replaceableString.replace("\'\'\'", ""), 					name:         '|publisher= begins with bold markup',					description:  '|publisher= begins with bold markup',				}); }		}		return b;	});	//***website parameter contains bold markup***	ARA_Rules.push(function (s) { var b = [];

//get indices of all '|website='s	   var startIndex = 0; var searchStr = "|website="; var searchStrLen = searchStr.length; var index, indices = []; while ((index = s.indexOf(searchStr, startIndex)) > -1) {		   indices.push(index); startIndex = index + searchStrLen; }		var indicesLength = indices.length; for (i = 0; i < indicesLength; i++) //for each |website= {			var webStartIndex = indices[i] + searchStr.length; var indexOnward  = s.substring(webStartIndex); //+searchStr.length to exclude "|website=\'\'\'" //get to the actual beginning of the website if there are spaces or newlines after the "website=" and before the start of the text while ((indexOnward[0] == ' ' || indexOnward[0] == '\n')) {				indexOnward = indexOnward.substring(1); //cut off the first character ++webStartIndex; }			var fullRef         = indexOnward; var fullRefPrevIndex = webStartIndex - 1; //indices of various characters in the citation var firstBracketAfterIndex = indexOnward.includes("}") ? indexOnward.indexOf("}") : s.length; var firstBarAfterIndex    = indexOnward.includes("|") ? indexOnward.indexOf("|") : s.length; //get to the end of the citation fullRef = fullRef.substring(0, firstBracketAfterIndex); //get to the beginning of the citation while (fullRefPrevIndex >= 0 && s.charAt(fullRefPrevIndex) != '{') {	             fullRef = s.charAt(fullRefPrevIndex) + fullRef; //prepend the character --fullRefPrevIndex; //decrement index }	   	//now we have the full ref. //get the entire website parameter. The parameter should either end with another | or }} for the end of the ref (if not malformed) //find the nearest delimeter var cutOffIndex = firstBarAfterIndex; if (firstBracketAfterIndex < cutOffIndex) cutOffIndex = firstBracketAfterIndex; var web = indexOnward.substring(0, cutOffIndex).trim; //the web parameter //If the website ends with bold markup if (web.endsWith('\'\'\'')) {				b.push({					start:       webStartIndex + web.length - 2,					end:          webStartIndex + web.length,					replacement:  '',					name:         '|website= ends with bold markup',					description:  '|website= ends with bold markup',				}); }		}		return b;	});	ARA_Rules.push(function (s) { var b = []; //If the website begins with bold markup var replaceableStrings = ["website=\'\'\'", " website = \'\'\'", " website= \'\'\'", "website =\'\'\'", "website= \'\'\'", " website=\'\'\'"]; for (i = 0; i < replaceableStrings.length; i++) {			var replaceableString = replaceableStrings[i]; if (s.includes(replaceableString)) {				b.push({					start: s.indexOf(replaceableString),					end:  s.indexOf(replaceableString) + replaceableString.length,					replacement: replaceableString.replace("\'\'\'", ""), 					name:         '|website= begins with bold markup',					description:  '|website= begins with bold markup',				}); }		}		return b;	});	/* TECHNICAL - HELPS SCRIPT FUNCTION */	//***unnecessary whitespace in citation***	ARA_Rules.push(function (s) { var b = []; var replaceableStrings = [" publisher=","publisher ="," publisher =", " website=","website ="," website =", " magazine=","magazine ="," magazine =", " work=","work ="," work =", " periodical=","periodical ="," periodical =", " newspaper=","newspaper ="," newspaper =", " journal=", "journal ="," journal= "]; for (i = 0; i < replaceableStrings.length; i++) {	   	var replaceableString = replaceableStrings[i]; if (s.includes(replaceableString)) {	   		b.push({					start: s.indexOf(replaceableString),					end:   s.indexOf(replaceableString) + replaceableString.length,					replacement: replaceableString.replace(" ", ""),					name: 'extra whitespace in citation (' + replaceableString + ')',					description: 'extra whitespace in citation (' + replaceableString + ')'				}); }	   }		return b;	});	} // end if mw.config.get('wgContentLanguage') === 'en'	return ARA_Rules; } //