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;

}

//