प्रयोगकर्ता:SM7/extra.js: रिवीजन सभ के बीचा में अंतर

Content deleted Content added
 
updated
लाइन 2:
extra.js --- by Evad37
> Common helper functions, stored in the window.extraJs object.
> Version 1.3.1
----------------------------------------------------------------------------------------------------
Take care to load approriate resource loader modules, as specified for each function. Or just load
See < https://www.mediawiki.org/wiki/mw.loader >
all that may be required, like this:
***************************************************************************************************/
/* jshint esversion: 5, laxbreak: true, undef: true, maxerr: 999*/
mw.loader.using( ['mediawiki.util', 'mediawiki.api', 'mediawiki.Title', 'mediawiki.RegExp',
/* globals window, $, mw, OO, extraJs */
'oojs-ui-core', 'oojs-ui-widgets', 'oojs-ui-windows'], function () {
// <nowiki>
 
window.extraJs = { version: '2.2.0' };
// ... your code goes here...
 
/* ========== Polyfills to support IE11 and Edge<14 ============================================= */
});
// Array.prototype.includes polyfill
if (!Array.prototype.includes) {
***************************************************************************************************/
Array.prototype.includes = function(searchElement /*, fromIndex*/) {
// <nowiki>
return this.indexOf(searchElement) !== -1;
};
}
// String.prototype.includes polyfill, per https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes#Polyfill
if (!String.prototype.includes) {
String.prototype.includes = function(search, start) {
'use strict';
if (typeof start !== 'number') {
start = 0;
}
 
if (start + search.length > this.length) {
window.extraJs = {};
return false;
} else {
return this.indexOf(search, start) !== -1;
}
};
}
/* ============================================================================================== */
 
/**
Line 64 ⟶ 81:
}
return $('<a>').attr({
'href':'https://bh.wikipedia.org/wiki/'+ mw.util.wikiUrlencodegetUrl(linktarget),
'target':'_blank'
}).text(linktext);
};
 
/**
* makeRcatCapsuleMultiselect
*
* Creates an OOjs UI CapsuleMultiselect with Rcat templates as options,
* grouped as per https://en.wikipedia.org/wiki/Template:R_template_index
*
* @requires {Modules} oojs-ui-core, oojs-ui-widgets
* @param {function} onChangeCallback({String[]} datas)
* Callback function for when the selected rcats change, is passed an array of Strings
* each of which is a selected rcat template (including braces `{{` and `}}`). When all
* prior selections are removed, an empty array is passed.
* @param {object} context
* The context to be used as the `this` value when executing the callback function
* @param {jQuery} overlay
* Overlay element. If ommited, element with id `ejs-rcats-overlay` will be emptied and used
* if it exists, or else a div with that id will be created and used.
* @return {OO.ui.CapsuleMultiselectWidget}
*/
extraJs.makeRcatCapsuleMultiselect = function(onChangeCallback, context, overlay) {
 
// Extend OO.ui.MenuSelectWidget and OO.ui.CapsuleMultiselectWidget to use a more intuitive
// lookup system, such that e.g. typing "section" brings up `{{R to section}}` as a match
LookupMenuSelectWidget = function(config) {
OO.ui.MenuSelectWidget.call(this, config);
};
LookupMenuSelectWidget.prototype = Object.create(OO.ui.MenuSelectWidget.prototype);
LookupMenuSelectWidget.prototype.getItemMatcher = function ( s, exact ) {
var re;
if ( s.normalize ) {
s = s.normalize();
}
s = exact ? s.trim() : s.replace( /^\s+/, '' );
re = s.replace( /([\\{}()|.?*+\-^$[\]])/g, '\\$1' ).replace( /\s+/g, '\\s+' );
if ( exact ) {
re = '^\\s*' + re + '\\s*$';
}
re = new RegExp( re, 'i' );
return function ( item ) {
var matchText = item.getMatchText();
if ( matchText.normalize ) {
matchText = matchText.normalize();
}
return re.test( matchText );
};
};
var LookupCapsuleMultiselectWidget = function ( config ) {
OO.ui.CapsuleMultiselectWidget.call(this, config);
// Override menu widget
this.menu = new LookupMenuSelectWidget( $.extend(
{
widget: this,
$input: this.$input,
$floatableContainer: this.$element,
filterFromInput: true,
disabled: this.isDisabled()
},
config.menu
) );
this.menu.connect( this, {
choose: 'onMenuChoose',
toggle: 'onMenuToggle',
add: 'onMenuItemsChange',
remove: 'onMenuItemsChange'
} );
if ( this.$input ) {
this.$input.prop( 'disabled', this.isDisabled() );
this.$input.attr( {
role: 'combobox',
'aria-owns': this.menu.getElementId(),
'aria-autocomplete': 'list'
} );
}
if ( !this.popup ) {
this.$content.append( this.$input );
this.$overlay.append( this.menu.$element );
}
this.onMenuItemsChange();
};
LookupCapsuleMultiselectWidget.prototype = Object.create(OO.ui.CapsuleMultiselectWidget.prototype);
// Define new overlay, or use/reuse already defined element
if ( overlay == null ) {
if ( $('#ejs-rcats-overlay').length ) {
overlay = $('#ejs-rcats-overlay').first().empty();
} else {
overlay = $('<div>')
.attr('id', 'ejs-rcats-overlay')
.css({'z-index':'2000', 'position':'fixed', 'top':'0px', 'font-size':'85%'})
.prependTo('body');
}
}
// Make menu option widgets based on template name
var newRcatOption = function(val) {
return new OO.ui.MenuOptionWidget( {data: '{{'+val+'}}', label: '{{'+val+'}}'} );
};
// Make the widget
var rcatCapsuleMultiselect = new LookupCapsuleMultiselectWidget( {
allowArbitrary: true,
$overlay: overlay,
popup: false,
menu: {
items: [
// Common Rcats
new OO.ui.MenuSectionOptionWidget({label:'Common'}),
newRcatOption('R to related topic'),
newRcatOption('R from subtopic'),
newRcatOption('R to list entry'),
newRcatOption('R to section'),
new OO.ui.MenuSectionOptionWidget({label:'Related information'}),
newRcatOption('R from album'),
newRcatOption('R to article without mention'),
newRcatOption('R from book'),
newRcatOption('R to decade'),
newRcatOption('R from domain name'),
newRcatOption('R from top-level domain'),
newRcatOption('R from film'),
newRcatOption('R from gender'),
newRcatOption('R from list topic'),
newRcatOption('R from member'),
newRcatOption('R to related topic'),
newRcatOption('R from related word'),
newRcatOption('R from phrase'),
newRcatOption('R from school'),
newRcatOption('R from song'),
newRcatOption('R from subtopic'),
newRcatOption('R to subtopic'),
newRcatOption('R from Unicode'),
new OO.ui.MenuSectionOptionWidget({label:'Fiction'}),
newRcatOption('R from fictional character'),
newRcatOption('R from fictional element'),
newRcatOption('R from fictional location'),
newRcatOption('R to TV episode list entry'),
// Grammar, punctuation, and spelling
new OO.ui.MenuSectionOptionWidget({label:'Abbreviation'}),
newRcatOption('R to acronym'),
newRcatOption('R from acronym'),
newRcatOption('R to initialism'),
newRcatOption('R from initialism'),
new OO.ui.MenuSectionOptionWidget({label:'Capitalisation'}),
newRcatOption('R from CamelCase'),
newRcatOption('R from other capitalisation'),
newRcatOption('R from miscapitalisation'),
new OO.ui.MenuSectionOptionWidget({label:'Grammar & punctuation'}),
newRcatOption('R from modification'),
newRcatOption('R from plural'),
newRcatOption('R to plural'),
new OO.ui.MenuSectionOptionWidget({label:'Parts of speech'}),
newRcatOption('R from adjective'),
newRcatOption('R from adverb'),
newRcatOption('R from common noun'),
newRcatOption('R from gerund'),
newRcatOption('R from proper noun'),
newRcatOption('R from verb'),
new OO.ui.MenuSectionOptionWidget({label:'Spelling'}),
newRcatOption('R from alternative spelling'),
newRcatOption('R from ASCII-only'),
newRcatOption('R to ASCII-only'),
newRcatOption('R from diacritic'),
newRcatOption('R to diacritic'),
newRcatOption('R from misspelling'),
newRcatOption('R from stylization'),
// Alternative names
new OO.ui.MenuSectionOptionWidget({label:'Alternative names (general)'}),
newRcatOption('R from alternative language'),
newRcatOption('R from alternative name'),
newRcatOption('R from former name'),
newRcatOption('R from historic name'),
newRcatOption('R from incorrect name'),
newRcatOption('R from long name'),
newRcatOption('R from portmanteau'),
newRcatOption('R from short name'),
newRcatOption('R from sort name'),
newRcatOption('R from less specific name}'),
newRcatOption('R from more specific name'),
newRcatOption('R from synonym'),
newRcatOption('R from antonym'),
new OO.ui.MenuSectionOptionWidget({label:'Alternative names (people)'}),
newRcatOption('R from birth name'),
newRcatOption('R from given name'),
newRcatOption('R to joint biography'),
newRcatOption('R from married name'),
newRcatOption('R from name with title'),
newRcatOption('R from personal name'),
newRcatOption('R from pseudonym'),
newRcatOption('R from surname'),
new OO.ui.MenuSectionOptionWidget({label:'Alternative names (technical)'}),
newRcatOption('R from Java package name'),
newRcatOption('R from molecular formula'),
newRcatOption('R from technical name'),
newRcatOption('R to technical name'),
newRcatOption('R from trade name'),
new OO.ui.MenuSectionOptionWidget({label:'Alternative names (organisms)'}),
newRcatOption('R from scientific name'),
newRcatOption('R from alternative scientific name'),
newRcatOption('R to scientific name'),
new OO.ui.MenuSectionOptionWidget({label:'Alternative names (geography)'}),
newRcatOption('R from name and country'),
newRcatOption('R from more specific geographic name'),
newRcatOption('R from postal code'),
// Navigation aids
new OO.ui.MenuSectionOptionWidget({label:'Navigation'}),
newRcatOption('R to anchor'),
newRcatOption('R avoided double redirect'),
newRcatOption('R from file metadata link'),
newRcatOption('R to list entry'),
newRcatOption('R mentioned in hatnote'),
newRcatOption('R to section'),
newRcatOption('R from shortcut'),
newRcatOption('R from template shortcut'),
new OO.ui.MenuSectionOptionWidget({label:'Disambiguation'}),
newRcatOption('R from ambiguous term'),
newRcatOption('R to anthroponymy page'),
newRcatOption('R to disambiguation page'),
newRcatOption('R from incomplete disambiguation'),
newRcatOption('R from incorrect disambiguation'),
newRcatOption('R from other disambiguation'),
newRcatOption('R from unnecessary disambiguation'),
new OO.ui.MenuSectionOptionWidget({label:'Merge, duplicate & move'}),
newRcatOption('R from duplicated article'),
newRcatOption('R with history'),
newRcatOption('R from merge'),
newRcatOption('R from move'),
newRcatOption('R with old history'),
new OO.ui.MenuSectionOptionWidget({label:'To namespaces'}),
newRcatOption('R to category namespace'),
newRcatOption('R to draft namespace'),
newRcatOption('R to help namespace'),
newRcatOption('R to main namespace'),
newRcatOption('R to portal namespace'),
newRcatOption('R to project namespace'),
newRcatOption('R to talk page'),
newRcatOption('R to template namespace'),
newRcatOption('R to user namespace'),
// Miscellaneous
new OO.ui.MenuSectionOptionWidget({label:'ISO codes'}),
newRcatOption('R from ISO 4'),
newRcatOption('R from ISO 639 code'),
newRcatOption('R from ISO 3166 code'),
newRcatOption('R from ISO 4217 code'),
newRcatOption('R from ISO 15924 code'),
new OO.ui.MenuSectionOptionWidget({label:'Miscellaneous'}),
newRcatOption('R printworthy'),
newRcatOption('R unprintworthy'),
newRcatOption('Wikidata redirect')
]
}
} );
// Execute callback when selector data changes
rcatCapsuleMultiselect.on('change', function(d) {
// Only care about the sring data (or no data), not the widgets
if ( typeof d[0] === 'string' ) {
onChangeCallback.call(context, d);
} else if ( d.length === 0 ) {
onChangeCallback.call(context, ['']);
}
});
return rcatCapsuleMultiselect;
};
 
Line 337 ⟶ 90:
*
* Make a question mark in a circle that shows a 'tooltip' when hovered over
*
* @deprecated Use addTooltip instead.
*
* @param {string} tipText
Line 350 ⟶ 105:
}
return $('<span>').attr({'title':tipText, 'class':'ejs-tooltip'}).html('&thinsp;?&thinsp;');
};
 
/**
* addTooltip
*
* Appends a question mark in a circle to an element, and shows a
* 'tooltip' when the element is hovered over
*
* @param {jQuery} $el jQuery element to add the tooltip to.
* @param {string} tipText The text for the tooltip.
* @return {jQuery} jQuery element witj the tooltip
*/
extraJs.addTooltip = function($el, tipText) {
// Add css rule, if not already added
if ( !extraJs.tooltipStyles ) {
var s = mw.loader.addStyleTag(
".ejs-tooltips { display: inline-block; border-bottom: 1px dotted black; cursor:help; } "+
".ejs-tooltipstext-container { visibility: hidden; position: absolute; z-index: 2000; width:auto; max-width:500px; padding:2px 0 0 10px; white-space:normal; } "+
".ejs-tooltips:hover .ejs-tooltipstext-container { visibility: visible; } "+
".ejs-tooltips .ejs-tooltipstext { display:inline-block; background-color: #333; color: #ddd; text-align: center; border-radius: 5px; padding: 5px; } "+
".ejs-tooltips-symbol { border:1px solid #33a; border-radius:20px; font-weight:bold; font-size:80%; color:#22a; padding:0px; cursor:help }"
);
extraJs.tooltipStyles = s.sheet || s.styleSheet || s;
}
return $el.addClass("ejs-tooltips").append(
$("<span class='ejs-tooltips-symbol'>&thinsp;?&thinsp;</span>"),
$("<div class='ejs-tooltipstext-container'>").append(
$("<span class='ejs-tooltipstext'>").text(tipText)
)
);
};
 
Line 463 ⟶ 248:
};
 
/** Template
*
* @class
* Represents the wikitext of template transclusion. Used by #parseTemplates.
* @prop {String} name Name of the template
* @prop {String} wikitext Full wikitext of the transclusion
* @prop {Object[]} parameters Parameters used in the translcusion, in order, of form:
{
name: {String|Number} parameter name, or position for unnamed parameters,
value: {String} Wikitext passed to the parameter (whitespace trimmed),
wikitext: {String} Full wikitext (including leading pipe, parameter name/equals sign (if applicable), value, and any whitespace)
}
* @constructor
* @param {String} wikitext Wikitext of a template transclusion, starting with '{{' and ending with '}}'.
*/
extraJs.Template = function(wikitext) {
this.wikitext = wikitext;
this.parameters = [];
};
extraJs.Template.constructor = extraJs.Template;
extraJs.Template.prototype.addParam = function(name, val, wikitext) {
this.parameters.push({
'name': name,
'value': val,
'wikitext': '|' + wikitext
});
};
/**
* Get a parameter data by parameter name
*/
extraJs.Template.prototype.getParam = function(paramName) {
return this.parameters.find(function(p) { return p.name == paramName; });
};
extraJs.Template.prototype.setName = function(name) {
this.name = name.trim();
};
 
/**
* parseTemplates
*
* Parses templates from wikitext.
* Based on SD0001's version at <https://en.wikipedia.org/wiki/User:SD0001/parseAllTemplates.js>.
* Returns an array containing the template details:
* var templates = parseTemplates("Hello {{foo |Bar|baz=qux |2=loremipsum|3=}} world");
* console.log(templates[0]); // --> object
{
name: "foo",
wikitext:"{{foo |Bar|baz=qux | 2 = loremipsum |3=}}",
parameters: [
{
name: 1,
value: 'Bar',
wikitext: '|Bar'
},
{
name: 'baz',
value: 'qux',
wikitext: '|baz=qux '
},
{
name: '2',
value: 'loremipsum',
wikitext: '| 2 = loremipsum '
},
{
name: '3',
value: '',
wikitext: '|3='
}
],
getParam: function(paramName) {
return this.parameters.find(function(p) { return p.name == paramName; });
}
}
*
*
* @param {String} wikitext
* @param {Boolean} recursive Set to `true` to also parse templates that occur within other templates,
* rather than just top-level templates.
* @return object[]
*/
extraJs.parseTemplates = function(wikitext, recursive) {
var strReplaceAt = function(string, index, char) {
return string.slice(0,index) + char + string.slice(index + 1);
};
 
var result = [];
var processTemplateText = function (startIdx, endIdx) {
var text = wikitext.slice(startIdx, endIdx);
 
var template = new extraJs.Template('{{' + text.replace(/\1/g,'|') + '}}');
// swap out pipe in links with \1 control character
// [[File: ]] can have multiple pipes, so might need multiple passes
while ( /(\[\[[^\]]*?)\|(.*?\]\])/g.test(text) ) {
text = text.replace(/(\[\[[^\]]*?)\|(.*?\]\])/g, '$1\1$2');
}
 
var chunks = text.split('|').map(function(chunk) {
// change '\1' control characters back to pipes
return chunk.replace(/\1/g,'|');
});
 
template.setName(chunks[0]);
var parameterChunks = chunks.slice(1);
 
var unnamedIdx = 1;
parameterChunks.forEach(function(chunk) {
var indexOfEqualTo = chunk.indexOf('=');
var indexOfOpenBraces = chunk.indexOf('{{');
var isWithoutEquals = !chunk.includes('=');
var hasBracesBeforeEquals = chunk.includes('{{') && indexOfOpenBraces < indexOfEqualTo;
var isUnnamedParam = ( isWithoutEquals || hasBracesBeforeEquals );
var pName, pNum, pVal;
if ( isUnnamedParam ) {
// Get the next number not already used by either an unnamed parameter, or by a
// named parameter like `|1=val`
while ( template.getParam(unnamedIdx) ) {
unnamedIdx++;
}
pNum = unnamedIdx;
pVal = chunk.trim();
} else {
pName = chunk.slice(0, indexOfEqualTo).trim();
pVal = chunk.slice(indexOfEqualTo + 1).trim();
}
template.addParam(pName || pNum, pVal, chunk);
});
result.push(template);
};
 
var n = wikitext.length;
// number of unclosed braces
var numUnclosed = 0;
 
// are we inside a comment or between nowiki tags?
var inComment = false;
var inNowiki = false;
 
var startIdx, endIdx;
for (var i=0; i<n; i++) {
if ( !inComment && !inNowiki ) {
if (wikitext[i] === '{' && wikitext[i+1] === '{') {
if (numUnclosed === 0) {
startIdx = i+2;
}
numUnclosed += 2;
i++;
} else if (wikitext[i] === '}' && wikitext[i+1] === '}') {
if (numUnclosed === 2) {
endIdx = i;
processTemplateText(startIdx, endIdx);
}
numUnclosed -= 2;
i++;
} else if (wikitext[i] === '|' && numUnclosed > 2) {
// swap out pipes in nested templates with \1 character
wikitext = strReplaceAt(wikitext, i,'\1');
} else if ( /^<!--/.test(wikitext.slice(i, i + 4)) ) {
inComment = true;
i += 3;
} else if ( /^<nowiki ?>/.test(wikitext.slice(i, i + 9)) ) {
inNowiki = true;
i += 7;
}
 
} else { // we are in a comment or nowiki
if (wikitext[i] === '|') {
// swap out pipes with \1 character
wikitext = strReplaceAt(wikitext, i,'\1');
} else if (/^-->/.test(wikitext.slice(i, i + 3))) {
inComment = false;
i += 2;
} else if (/^<\/nowiki ?>/.test(wikitext.slice(i, i + 10))) {
inNowiki = false;
i += 8;
}
}
 
}
if ( recursive ) {
var subtemplates = result.map(function(template) {
return template.wikitext.slice(2,-2);
})
.filter(function(templateWikitext) {
return /\{\{.*\}\}/.test(templateWikitext);
})
.map(function(templateWikitext) {
return extraJs.parseTemplates(templateWikitext, true);
});
return result.concat.apply(result, subtemplates);
}
 
return result;
 
};
 
/**
* toSentenceCase
Line 482 ⟶ 478:
* uniqueArray
*
* Filters out possible duplicate values from an array of strings.
*
* @param {arrayString[]} a Array to be filtered.
* @return {String[]} Filtered array.
* Array to be filtered.
* @return {array} Filtered array.
*/
extraJs.uniqueArray = function(a) {
var table = {};
return a.filter(function(val, i, arr){ return arr.indexOf(val) === i; });
a.forEach(function(e) {
table[e] = true;
});
return Object.keys(table);
};
 
Line 498 ⟶ 497:
* Derived from XFDcloser < https://en.wikipedia.org/wiki/User:Evad37/XFDcloser.js >
*
* @requires {Module} mediawiki.RegExputil, User:SD0001/parseTemplate.js
* @param {string} wikitext
* Wikitext in which to search for links or file usages.
Line 518 ⟶ 517:
var gallery_regex_str = "(";
var free_regex_str = "(";
var filename, filename_regex_str;
for ( var i=0; i<unlinkFiles.length; i++ ) {
// Take off namespace prefix
लाइन 523:
// For regex matching: first character can be either upper or lower case, special
// characters need to be escaped, spaces/underscores can be either spaces or underscores
filename_regex_str = "[" + mw.RegExputil.escapeescapeRegExp(filename.slice(0, 1).toUpperCase()) +
mw.RegExputil.escapeescapeRegExp(filename.slice(0, 1).toLowerCase()) + "]" +
mw.RegExputil.escapeescapeRegExp(filename.slice(1)).replace(/(?: |_)/g, "[ _]");
// Add to regex strings
normal_regex_str += "\\[\\[\\s*(?:[Ii]mage|[Ff]ile|चित्र)\\s*:\\s*" + filename_regex_str +
"\\s*\\|?.*?(?:(?:\\[\\[.*?\\]\\]).*?)*\\]\\]";
gallery_regex_str += "^\\s*(?:[Ii]mage|[Ff]ile|चित्र):\\s*" + filename_regex_str + ".*?$";
free_regex_str += "\\|\\s*(?:[\\w\\s]+\\=)?\\s*(?:(?:[Ii]mage|[Ff]ile|चित्र):\\s*)?" +
filename_regex_str;
लाइन 557:
var free_regex = new RegExp( free_regex_str, "mg" );
wikitext = wikitext.replace(free_regex, "");
}
// Remove portal links/templates, if there are any
var unlinkPortals = unlinkThese.filter(function(t){ return /^Portal:/i.test(t); });
if ( unlinkPortals.length > 0 ) {
// Build regex string
var portal_regex_str = "(" +
unlinkPortals.map(function(portal) {
// Take off namespace prefix
var portalname = portal.replace("Portal:", "");
// For regex matching: first character can be either upper or lower case, special
// characters need to be escaped, spaces/underscores can be either spaces or underscores
return "[" + mw.util.escapeRegExp(portalname.slice(0, 1).toUpperCase()) +
mw.util.escapeRegExp(portalname.slice(0, 1).toLowerCase()) + "]" +
mw.util.escapeRegExp(portalname.slice(1)).replace(/(?: |_)/g, "[ _]");
}).join('|') +
")(?![^<]*?-->)"; // Close off regex string
var portal_regex = new RegExp(portal_regex_str);
 
// Find templates to remove parameters from, or remove entirely
var templatesInWikitext = extraJs.parseTemplates(wikitext, true);
// templates using numbered/unnamed parameters, e.g.{{Portal|Foo|Bar}}
var numberedParameterTemplates = [
// {{Portal}} and its redirects:
'portal', 'portalpar', 'portal box', 'ports', 'portal-2',
// {{Portal-inline}} and its redirects:
'portal-inline', 'portal inline', 'portal frameless', 'portal-inline-template',
// {{Portal bar}} and its redirects:
'portal bar', 'portalbar'
];
// templates using named parameters, e.g. {{Subject bar |portal=Foo |portal2=Bar}}
var namedParameterTemplates = ['subject bar'];
// helper functions for filtering/mapping
var isNumberedParameter = function(param) {
return !isNaN(Number(param.name));
};
var isNamedPortalParameter = function(param) {
return /portal\d*/.test(param.name);
};
 
/**
* @param {TemplateObject[]} existingTemplates Subset of TemplateObjects from extraJs.parseTemplates
* @param {Function(ParamObject)=>boolean} paramTypeFilter Function that returns `true` if
* the passed in parameter might contain a portal, and `false` otherwise
* @param {Function(ParamObject[])=>boolean} keepFilter Function that returns `true` if the
* template should be kept (and edited), or `false` if the template should just be removed
* @sideEffect modifies variable `wikitext`
*/
var editOrRemoveTemplates = function( existingTemplates, paramTypeFilter, keepFilter ) {
existingTemplates.forEach(function(template) {
var paramsToKeep = template.parameters.filter(function(param) {
return !paramTypeFilter(param) || !portal_regex.test(param.value);
});
if ( paramsToKeep.length === template.parameters.length ) {
// No changes needed
return;
}
if ( keepFilter(paramsToKeep) ) {
var updatedTemplateWikitext = template.wikitext.replace(/\|(.|\n)*/, '') +
paramsToKeep.map(function(p) { return p.wikitext; }).join('') +
'}}';
wikitext = wikitext.replace(template.wikitext, updatedTemplateWikitext);
} else {
// Remove template wikitext, including any preceding * or : characters:
// - if on it's own line, remove a linebreak
wikitext = wikitext.replace(
new RegExp('\\n[\\*\\:]*[\\t ]*' + mw.util.escapeRegExp(template.wikitext) + '\\n'),
'\n'
)
// - if something else is on the line, leave the linebreaks alone
.replace(
new RegExp('[\\*\\:]*[\\t ]*' + mw.util.escapeRegExp(template.wikitext)),
''
);
}
});
};
 
// Deal with numbered-parameter templates
editOrRemoveTemplates(
templatesInWikitext.filter(function(template) {
var name = template.name.toLowerCase().replace(/_/g, ' ');
return numberedParameterTemplates.includes(name);
}),
isNumberedParameter,
function(params) { return params.some(isNumberedParameter); }
);
// Deal with named parameter templates
editOrRemoveTemplates(
templatesInWikitext.filter(function(template) {
var name = template.name.toLowerCase().replace(/_/g, ' ');
return namedParameterTemplates.includes(name);
}),
isNamedPortalParameter,
function(params) { return params.length > 0; }
);
// Remove any "See also" sections that are now empty
var seeAlsoSection = /(==+)\s*[Ss]ee [Aa]lso\s*==+([.\n]*?)(?:(==+)|$)/g.exec(wikitext);
if ( seeAlsoSection ) {
var hasSubsection = seeAlsoSection[1] && seeAlsoSection[3] && seeAlsoSection[3].length > seeAlsoSection[1].length;
var isEmpty = seeAlsoSection[2].trim() === '';
if ( isEmpty && !hasSubsection ) {
wikitext = wikitext.replace(seeAlsoSection[0], seeAlsoSection[3]);
}
}
}
Line 566 ⟶ 675:
// For regex matching: first character can be either upper or lower case, special
// characters need to be escaped, spaces/underscores can be either spaces or underscores
var unlink_regex_str = "[" + mw.RegExputil.escapeescapeRegExp(unlinkThese[ii].slice(0, 1).toUpperCase()) +
mw.RegExputil.escapeescapeRegExp(unlinkThese[ii].slice(0, 1).toLowerCase()) + "]" +
mw.RegExputil.escapeescapeRegExp(unlinkThese[ii].slice(1)).replace(/(?: |_)/g, "[ _]");
// Add to regex strings
simple_regex_str += unlink_regex_str;
Line 606 ⟶ 715:
if ( navboxes ) {
// remove regex matches from wikitext
var replacement;
for ( var jj=0; jj<navboxes.length; jj++ ) {
replacement = navboxes[jj].replace(navbox_simple_regex, "").replace(navbox_named_regex, "");
Line 626 ⟶ 736:
if ( seealso ) {
// remove regex matches from wikitext
var replacement_seealso;
for ( var kk=0; kk<seealso.length; kk++ ) {
replacementreplacement_seealso = (seealso[kk]+"\n").replace(seealso_simple_regex, "").replace(seealso_named_regex, "");
wikitext = wikitext.replace(seealso[kk].trim(), replacementreplacement_seealso.trim());
}
}
// Other lists need manual review, in case the item should be retained unlinked (e.g. complete lists per [[WP:CSC]])
// For other lists, entirely remove list items if the only content is a single backlink,
// including the preceding *'s and the following newline
var list_simple_regex = new RegExp( "\\*+[\\t ]*" + simple_regex_str + "[\\t ]*\\n", "g" );
var list_named_regex = new RegExp( "\\*+[\\t ]*" + named_regex_str + "[\\t ]*\\n", "g" );
wikitext = wikitext.replace(list_simple_regex, "").replace(list_named_regex, "");
}
// Mark any other list items with backlinks for manual review, using {{subst:void}}