प्रयोगकर्ता:SM7/extra.js: रिवीजन सभ के बीचा में अंतर
Content deleted Content added
updated |
|||
लाइन 2:
extra.js --- by Evad37
> Common helper functions, stored in the window.extraJs object.
----------------------------------------------------------------------------------------------------
Take care to load approriate resource loader modules, as specified for each function.
See < https://www.mediawiki.org/wiki/mw.loader >
***************************************************************************************************/
/* jshint esversion: 5, laxbreak: true, undef: true, maxerr: 999*/
/* globals window, $, mw, OO, extraJs */
// <nowiki>
window.extraJs = { version: '2.2.0' };
/* ========== Polyfills to support IE11 and Edge<14 ============================================= */
// Array.prototype.includes polyfill
if (!Array.prototype.includes) {
Array.prototype.includes = function(searchElement /*, fromIndex*/) {
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) {
return false;
} else {
return this.indexOf(search, start) !== -1;
}
};
}
/* ============================================================================================== */
/**
Line 64 ⟶ 81:
}
return $('<a>').attr({
'href':
'target':'_blank'
}).text(linktext);
};
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(' ? ');
};
/**
* 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'> ? </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 {
* @return {String[]} Filtered array.
*/
extraJs.uniqueArray = function(a) {
var table = {};
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.
* @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.
mw.
mw.
// Add to regex strings
normal_regex_str += "\\[\\[\\s*(?:[Ii]mage|[Ff]ile
"\\s*\\|?.*?(?:(?:\\[\\[.*?\\]\\]).*?)*\\]\\]";
gallery_regex_str += "^\\s*(?:[Ii]mage|[Ff]ile
free_regex_str += "\\|\\s*(?:[\\w\\s]+\\=)?\\s*(?:(?:[Ii]mage|[Ff]ile
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.
mw.
mw.
// 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++ ) {
wikitext = wikitext.replace(seealso[kk].trim(),
}
}
// Other lists need manual review, in case the item should be retained unlinked (e.g. complete lists per [[WP:CSC]])
}
// Mark any other list items with backlinks for manual review, using {{subst:void}}
|