「利用者:Dragoniez/scripts/PrimaryTopicColors.js」の版間の差分
表示
削除された内容 追加された内容
PrimaryTopicColors.js |
(相違点なし)
|
2022年5月23日 (月) 01:00時点における版
/*******************************
* Name: PrimaryTopicColors *
* Author: Dragoniez *
* Version: 1.0 *
*******************************/
//<nowiki>
/*global mediaWiki, jQuery */
(function(mw, $) { // Create a function scope
// ********************** VARIABLES **********************
const articleLinks = {}; // {'pageTitle': [<link1>, <link2>, ...], 'pageTitle2': [<link3>, <link4>, ...], ...}
const DEVTALK = '利用者‐会話:Dragoniez/scripts/PrimaryTopicColors';
const RFD = 'Wikipedia:リダイレクトの削除依頼/受付';
const devLink = `<a href="${mw.util.getUrl(DEVTALK + '#リンク修正依頼')}" target="_blank">開発者</a>`;
const TEST = '利用者:Dragoniez/test2';
const TESTTALK = '利用者‐会話:Dragoniez/test2';
const scriptAd = ' ([[User:Dragoniez/scripts/PrimaryTopicColors|PTC]])';
const debuggingMode = {
'pageToEdit': false
};
// ********************** DOM READY FUNCTION **********************
$(async function() {
// Don't run the script on certain pages
if (
mw.config.get('wgAction') === 'edit' ||
mw.config.get('wgCanonicalSpecialPageName') === 'Recentchanges' ||
mw.config.get('wgCanonicalSpecialPageName') === 'Watchlist'
) {
return;
}
// Append <style>
$('head').append(
'<style id="primary-topic-colors">' +
' .prc-primarytopic:link,' +
' .prc-primarytopic-toresolve:link {' +
' color: #23AF3A;' +
' }' +
' .prc-primarytopic:visited,' +
' .prc-primarytopic-toresolve:visited {' +
' color: #1B842C;' +
' }' +
' .prc-primarytopic-toresolve::after {' +
' content: "RD";' +
' color: red;' +
' font-size: smaller;' +
' vertical-align: super;' +
' }' +
'</style>'
);
// Mark links
const articleTitles = collectLinks();
if (!articleTitles) return;
const markLinksAsyc = []; // Stores looped async function
for (const article of articleTitles) {
markLinksAsyc.push(markLinks(article));
}
const result = await Promise.all(markLinksAsyc); // Wait until all the async procedures are finished
// Append a portletlink
if ($.inArray('autoconfirmed', mw.config.get('wgUserGroups')) === -1) return;
const ptsToResolve = []; // Stores 'PAGETITLE (DISAMB)', which is subject to deletion
for (const el of result) { // 'result' is an array that stores the result of each async procedure
if (el) ptsToResolve.push(el); // If not undefined, the relevant element of the array has a pagename
}
if (ptsToResolve.length === 0) return;
mw.loader.using('jquery.ui', function() {
appendPortletlink(ptsToResolve);
});
});
// ********************** MAIN FUNCTIONS **********************
function collectLinks() {
// RegExp for links
const pageRegExp = new RegExp(mw.config.get('wgArticlePath').replace('$1', '') + '([^#]+)'); // Matches '/wiki/PAGENAME' in URLs
const scriptRegExp = new RegExp('^' + mw.config.get('wgScript') + '\\?title=([^#&]+)'); // Matches '/w/index.php?title=PAGENAME' in URLs
// Find all article links that match the RegExps and save them in articleLinks
const articleTitles = [];
var $container, url, matchedArr, pageTitle;
switch(mw.config.get('wgAction')) {
case 'submit':
$container = $('.mw-content-ltr'); // The parsed preview
break;
case 'history':
$container = $('.comment'); // Edit summaries
break;
default:
$container = $('.mw-body-content');
}
$container.find('a').each(function(i, lnk) { // Loop through all the links in the page's content
// No need to look at certain links
if (
$(lnk).hasClass('mw-changeslist-date') || // Revision link
$(lnk).hasClass('mw-changeslist-diff') || // Diff link
$(lnk).hasClass('mw-changeslist-history') || // History link
$(lnk).hasClass('mw-thanks-thank-link') || // Thanks link
$(lnk).parent('span').hasClass('mw-usertoollinks') || // Links to user namespace on some pages
$(lnk).parent('span').hasClass('mw-history-undo') || // Undo link
$(lnk).parent('span').hasClass('mw-rollback-link') || // Rollback link
$(lnk).parent('span').hasClass('autocomment') || // Section link in edit summary
$(lnk).parent('span').hasClass('mw-editsection') || // 'Edit section' link
$(lnk).hasClass('extiw') || // Interwiki link
$(lnk).hasClass('external') || // External link
$(lnk).hasClass('new') || // Red link
$(lnk).hasClass('mw-redirect') || // Redirect link
$(lnk).hasClass('mw-disambig') // Disambiguation link
) {
return;
}
var id;
if (id = $(lnk).closest('div').attr('id')) {
if (id.match(/^mw-diff-[on]title[1245]$/)) return; // Diff page: -title3 contains edit summaries
}
// Get the href of the link
url = $(lnk).attr('href');
if (!url) return;
if (url.indexOf('www.wikidata.org') !== -1) return;
// Extract a page title from the href
if (matchedArr = pageRegExp.exec(url)) {
pageTitle = matchedArr[1];
} else if (matchedArr = scriptRegExp.exec(url)) {
pageTitle = matchedArr[1];
} else {
return;
}
pageTitle = decodeURIComponent(pageTitle).replace(/_/g, ' ');
// Exclude page titles inclduing "(", ")", ":", "#", "/" and push the jQuery object into the array
if (pageTitle.match(/[#\:\(\)\/]/)) return;
if (!articleLinks[pageTitle]) articleLinks[pageTitle] = [];
articleLinks[pageTitle].push(lnk);
if ($.inArray(pageTitle, articleTitles) === -1) articleTitles.push(pageTitle);
});
if (articleTitles.length === 0) return;
//console.log(articleTitles);
return articleTitles;
}
function markLinks(pageTitle) {
return new Promise(function(resolve) {
new mw.Api().get({
'action': 'query',
'generator': 'prefixsearch',
'gpssearch': pageTitle + ' (',
'gpslimit': 3,
'gpsprofile': 'strict',
'redirects': true,
'formatversion': 2
}).done(function(res){
var resPgs, resRedirs, links;
if (!res || !res.query || !(resPgs = res.query.pages)) return resolve();
if (resPgs.length === 0) return resolve();
if (resRedirs = res.query.redirects) {
if (resRedirs.length !== 0) {
for (const redir of resRedirs) {
for (const pg of resPgs) {
if (pg.index == redir.index) {
pg.title = redir.from; // Title key has the redirect target: Replace it with the redirect source
pg.redirectTo = redir.to; // Create a new key in the object and store the redirect target
}
}
}
}
}
for (let i = 0; i < resPgs.length; i++) {
if (resPgs[i].title.indexOf('(曖昧さ回避)') !== -1) { // If the title contains '(曖昧さ回避)'
resPgs.splice(i, 1); // Remove the object element from the array
break;
}
}
if (resPgs.length === 0) return resolve(); // If resPgs has elements left in it, the page without parentheses is a primary topic
links = articleLinks[pageTitle];
if (resPgs.length === 1 && resPgs[0].redirectTo === pageTitle) { // If resPgs has only one page left and if it's a redirect to the PT
for (let i = 0; links && i < links.length; i++) {
$(links[i]).addClass('prc-primarytopic-toresolve'); // The page is potentially unnecessarily disambiguated
}
resolve(resPgs[0].title);
} else { // Or else, just mark up the relevant link as a primary topic
for (let i = 0; links && i < links.length; i++) {
$(links[i]).addClass('prc-primarytopic');
}
resolve();
}
});
});
}
function appendPortletlink(ptsToResolve) {
// Define the position of the portletlink (skin-dependent)
var lkPosition;
if (mw.config.get('skin') === 'minerva') {
lkPosition = 'p-personal';
} else {
lkPosition = 'p-cactions';
}
// Add a portletlink
$(mw.util.addPortletLink(lkPosition, '#', 'リンク修正依頼', 'ca-ptc', '不要な曖昧さ回避リンクの修正依頼またはリダイレクトの削除依頼', null, '#ca-move')).click({'arg1': ptsToResolve}, openDialog);
}
var firsttime = true, pagelist = [];
function openDialog(e) {
e.preventDefault();
var ptsToResolve = e.data.arg1;
if (firsttime) { // When the dialog is opened for the first time
firsttime = false;
pagelist = ptsToResolve; // The list of the potentially unnecessarily db-ed pages need to be updated when the dialog is re-opened
}
const ptList = [];
for (const pt of pagelist) {
ptList.push(
'<li>' +
'<input class="ptc-request-checkbox" type="checkbox" style="margin-right: 0.5em;">' +
`<a class="ptc-request-target" href="${mw.util.getUrl(pt, {'redirect': 'no'})}" target="_blank">${pt}</a>` +
' <span style="font-size: smaller;">(' +
`<a href="${mw.util.getUrl('特別:pagehistory/' + pt)}" target="_blank">履歴</a>` +
' / ' +
`<a href="${mw.util.getUrl('特別:リンク元/' + pt)}" target="_blank">リンク元</a>` +
' / ' +
`<a href="${mw.util.getUrl('特別:前方一致ページ一覧', {'prefix': pt.replace(/ {1}\(.+\)$/, ' ('), 'namespace': 0})}" target="_blank">前方一致ページ検索</a>` +
')</span>' +
'</li>'
);
}
const dialogHtml =
'<div id="ptc-dialog" title="Primary Topic Colors" style="max-height: 80vh;">' +
' <div id="ptc-dialog-header">' +
' <h2>リンク修正依頼</h2>' +
' </div>' +
' <div id="ptc-dialog-body">' +
' <form>' +
' <div id="ptc-dialog-pagelist" style="border: 1px solid #a2a9b1; padding: 0.5em; margin-bottom: 0.5em; box-sizing: border-box;">' +
' <ul style="list-style: none; font-size: 110%; margin-left: 0;">' +
ptList.join('') +
' </ul>' +
' <input id="ptc-checkall-btn" type="button" value="全てチェック" style="margin-top: 0.2em;">' +
' </div>' +
' <p>' +
`修正依頼: ${devLink}にスクリプトによる一括リンク修正を依頼<br>` +
'削除依頼: リダイレクトの削除依頼を提出 (リンク修正が不要な場合)' +
' </p>' +
' </form>' +
' <div style="magin: 0.5em 0;">' +
' <p id="ptc-editmessage" style="display: none;"></p>' +
' </div>' +
' </div>' +
'</div>';
// Add the frame div to the page
$('body').append(dialogHtml);
// Show dialog
$('#ptc-dialog').dialog({
'resizable': false,
'height': 'auto',
'width': 'auto',
'modal': true,
'buttons': [{
'text': '修正依頼',
'click': submitRequest
}, {
'text': '削除依頼',
'click': submitRequest
}, {
'text': '閉じる',
'click': function() {
$(this).dialog('close');
}
}]
});
}
async function submitRequest(e) {
if (!/autoconfirmed/.test(mw.config.get('wgUserGroups'))) { // Just in case
$('#ptc-dialog, #ca-ptc').remove();
return;
}
const reqType = e.target.innerText; // '修正依頼' or '削除依頼'
var ep = editPrep(reqType);
if (!ep) return;
ep = await checkDuplicates(ep); // If requests are already submitted, remove the related pages from the request list
if (ep.reportText.indexOf('RFD') === -1) return editDone(ep, 'dr'); // If reportText has no RFD template in it, all the redirects have already been reported
const ts = await getTimestamps(ep);
if (!ts) return editDone(ep, 'ts');
const sectNum = await getSectionNumber(ep);
if (!sectNum) return editDone(ep, 'sect');
const result = await edit(ep, sectNum, ts.baseTS, ts.curTS);
switch(result) {
case true: // Edit succeeded
editDone(ep, true);
return;
case false: // Edit failed with an unknown error
editDone(ep, false);
return;
default: // Edit failed with a known error ('result' stores error info)
editDone(ep, result);
}
}
function editPrep(reqType) {
// Variables
const pageToEdit = reqType === '修正依頼' ? DEVTALK: RFD;
const checkedCnt = $('.ptc-request-checkbox:checked').length;
// Show error and return if no checkbox is checked
if (checkedCnt === 0) return alert('チェックされた項目がありません');
// Collect redirect names
const redirPagenames = [];
$('.ptc-request-checkbox:checked').siblings('.ptc-request-target').each(function() {
redirPagenames.push($(this).text());
});
// Generate request text
const tlRFD = '{{RFD|PAGE1|PAGE2}}', vote = redirPagenames.length > 1 ? '{{AFD|全削除}}' : '{{AFD|削除}}';
var reportText = '';
for (const pg of redirPagenames) {
reportText += '* ' + tlRFD.replace('PAGE1', pg).replace('PAGE2', pg.replace(/ {1}\(.+\)$/, '')) + '\n';
}
if (reqType === '削除依頼') {
reportText += '** ' + vote + ' リダイレクト元以外に括弧付きのページが存在しないため、不要な曖昧さ回避として削除を依頼します。--~~~~';
} else {
reportText += ': {{コ|依頼}} (PTCによる自動依頼) --~~~~';
}
// Get the name of the section to edit
const sectionRFD = getSectionRFD();
const sectionToEdit = pageToEdit === RFD ? sectionRFD : 'リンク修正依頼';
// Generate edit summary
const summary = generateSummary(sectionToEdit, redirPagenames);
// Hide parts on dialog
$('#ptc-editmessage')
.prop('innerHTML', '依頼中<img src="https://upload.wikimedia.org/wikipedia/commons/4/42/Loading.gif" style="vertical-align: middle; max-height: 100%; border: 0;">')
.css('display', 'inline-block');
if (checkedCnt === pagelist.length) {
$('#ptc-dialog-pagelist').remove();
} else {
$('.ptc-request-checkbox').each(function() {
if ($(this).is(':checked')) $(this).parent('li').remove();
});
}
$('#ptc-dialog').dialog({'buttons': [] });
// Update pagelist (remove requested pages)
for (let i = pagelist.length - 1; i >= 0; i--) {
if ($.inArray(pagelist[i], redirPagenames) !== -1) pagelist.splice(i, 1);
}
// Return values
return {
'pageToEdit': debuggingMode.pageToEdit ? (pageToEdit === DEVTALK ? TESTTALK : TEST) : pageToEdit,
'sectionToEdit': sectionToEdit,
'redirPagenames': redirPagenames,
'reportText': reportText,
'summary': summary
};
}
function getSectionRFD() {
const d = new Date();
const lastDay = function(y, m){
return new Date(y, m + 1, 0).getDate();
}
var sectionName;
switch(true) {
case (1 <= d.getDate() && d.getDate() <= 5):
sectionName = `${d.getFullYear()}年${d.getMonth() + 1}月1日 - 5日新規依頼`;
break;
case (6 <= d.getDate() && d.getDate() <= 10):
sectionName = `${d.getFullYear()}年${d.getMonth() + 1}月6日 - 10日新規依頼`;
break;
case (11 <= d.getDate() && d.getDate() <= 15):
sectionName = `${d.getFullYear()}年${d.getMonth() + 1}月11日 - 15日新規依頼`;
break;
case (16 <= d.getDate() && d.getDate() <= 20):
sectionName = `${d.getFullYear()}年${d.getMonth() + 1}月16日 - 20日新規依頼`;
break;
case (21 <= d.getDate() && d.getDate() <= 25):
sectionName = `${d.getFullYear()}年${d.getMonth() + 1}月21日 - 25日新規依頼`;
break;
case (26 <= d.getDate() && d.getDate() <= lastDay(d.getFullYear(), d.getMonth())):
sectionName = `${d.getFullYear()}年${d.getMonth() + 1}月26日 - ${lastDay(d.getFullYear(), d.getMonth())}日新規依頼`;
break;
default:
}
return sectionName;
}
/**
* @param {string} section
* @param {Array} pagesArr
* @returns {string}
*/
function generateSummary(section, pagesArr) {
return `/* ${section} */ +[[` + pagesArr.slice(0, 5).join(']], [[') + ']]' + (pagesArr.length > 5 ? ' ほか' : '') + scriptAd;
}
// Function to check duplicate requests already present on the target page
async function checkDuplicates(ep) {
// Get the content of the page to which the request will be submitted
const wikitext = await parsePage(ep);
if (!wikitext) return ep;
// Extract RFD templates
const templates = findTemplates(wikitext, 'rfd');
if (templates.length === 0) return ep;
// Get duplicate RFDs
const duplicateRequests = [];
const pagesEscaped = ep.redirPagenames.join('|').replace(/_/g, ' ').replaceAllPTC('(', '\\(', ')', '\\)', '.', '\\.', '^', '\\^', '$', '\\$', '*', '\\*', '+', '\\+', '?', '\\?');
const pageRegExp = new RegExp(`(?:${pagesEscaped})`);
for (const tl of templates) { // Loop through all the extracted RFD templates and check if the 1st parameter contains the page(s) to be RFD-ed
let mtch;
if (mtch = tl.split('|')[1].match(pageRegExp)) {
mtch = mtch[0].replace(/_/g, ' ');
if ($.inArray(mtch, duplicateRequests) === -1) duplicateRequests.push(mtch);
}
}
// Update ep
const drEscaped = duplicateRequests.join('|').replaceAllPTC('(', '\\(', ')', '\\)', '.', '\\.', '^', '\\^', '$', '\\$', '*', '\\*', '+', '\\+', '?', '\\?');
const rqTxtRegExp = new RegExp('\\* \\{{2}RFD\\|(?:' + drEscaped + ')\\|.+\\}{2}\\n', 'g');
if (ep.reportText.match(rqTxtRegExp)) {
ep.reportText = ep.reportText.replace(rqTxtRegExp, ''); // Remove all duplicates from the report text
for (let i = ep.redirPagenames.length; i >= 0; i--) { // Remove all duplicates from the page list
if ($.inArray(ep.redirPagenames[i], duplicateRequests) !== -1) ep.redirPagenames.splice(i, 1);
}
ep.summary = generateSummary(ep.sectionToEdit, ep.redirPagenames); // Re-generate edit summary
ep.updated = true; // Create a new property in ep which signals that the report text has been updated
}
return ep; // Return the updated ep
}
function parsePage(ep) {
return new Promise(function(resolve) {
new mw.Api().get({
'action': 'parse',
'page': ep.pageToEdit,
'prop': 'wikitext',
'formatversion': 2
}).then(function(res) {
if (res && res.parse) return resolve(res.parse.wikitext);
resolve();
}).catch(function() {
resolve();
});
});
}
/**
* Function to extract templates from wikitext
* @param {string} text The text in which to search for templates
* @param {string} templateName [Optional] Specify the template name (case-insensitive)
* @returns {Array} An array of the extracted templates
*/
function findTemplates(text, templateName) {
// Split the text with '{{', the head delimiter of templates
const tempInnerContent = text.split('{{'); // Note: tempInnerContent[0] is always an empty string or a string that has nothing to do with templates
const templates = []; // The array of extracted templates to return
// Extract templates from the text
if (tempInnerContent.length === 0) { // If the text has no tempalte in it
return templates; // Return an empty array
} else { // If the text has some templates in it
const nest = []; // Stores the element number of tempInnerContent if the element involves nested templates
for (let i = 1; i < tempInnerContent.length; i++) { // Loop through all elements in tempInnerContent (except tempInnerContent[0])
let tempTailCnt = (tempInnerContent[i].match(/\}\}/g) || []).length; // The number of '}}' in the split segment
let temp = ''; // Temporary escape hatch for templates
if (tempTailCnt === 0) { // The split segment not having any '}}' means that it nests another template
nest.push(i); // Push the element number into the array
} else if (tempTailCnt === 1) { // The split segment itself is the whole inner content of one template
temp = '{{' + tempInnerContent[i].split('}}')[0] + '}}';
if ($.inArray(temp, templates) === -1) templates.push(temp);
} else if (tempTailCnt > 1) { // The split segment is part of more than one template (e.g. TL2|...}}...}} )
for (let j = 0; j < tempTailCnt; j++) { // Loop through all the nests
if (j === 0) { // The innermost template
temp = '{{' + tempInnerContent[i].split('}}')[j] + '}}'; // Same as when tempTailCnt === 1
if ($.inArray(temp, templates) === -1) templates.push(temp);
} else { // Nesting templates
const elNum = nest[nest.length -1]; // The start of the nesting template
nest.pop();
const nestedTempInnerContent = tempInnerContent[i].split('}}');
temp = '{{' + tempInnerContent.slice(elNum, i).join('{{') + '{{' + nestedTempInnerContent.slice(0, j + 1).join('}}') + '}}';
if ($.inArray(temp, templates) === -1) templates.push(temp);
}
}
}
}
// Check if the optional parameter is specified
if (templateName && templates.length !== 0) {
const templateRegExp = new RegExp(templateName, 'i');
for (let i = templates.length -1; i >= 0; i--) {
// Remove the template from the array if it's not an instance of the specified template
if (templates[i].split('|')[0].search(templateRegExp) === -1) templates.splice(i, 1);
}
}
return templates;
}
}
// Function to get the timestamps of the latest revision and the current time
function getTimestamps(ep) {
return new Promise(function(resolve) {
new mw.Api().get({
'action': 'query',
'titles': ep.pageToEdit,
'prop': 'revisions',
'curtimestamp': true,
'formatversion': 2
}).then(function(res){
var resPages;
if (res && res.query && (resPages = res.query.pages)) {
return resolve({
'baseTS': resPages[0].revisions[0].timestamp,
'curTS': res.curtimestamp
});
}
resolve();
}).catch(function() {
resolve();
});
});
}
// Function to get the section number from the section title
function getSectionNumber(ep) {
return new Promise(function(resolve) {
new mw.Api().get({
'action': 'parse',
'page': ep.pageToEdit,
'prop': 'sections',
'formatversion': 2
}).then(function(res) {
var resSect;
if (res && res.parse && (resSect = res.parse.sections)) {
for (let i = 0; i < resSect.length; i++) {
if (resSect[i].line === ep.sectionToEdit) {
return resolve(resSect[i].index);
}
}
}
resolve();
}).catch(function() {
resolve();
});
});
}
/**
* @returns true when edit succeeded, false when unexpected error occurred, errcode when known error occurred
*/
function edit(ep, sectionNum, baseTS, curTS) {
return new Promise(function(resolve) {
new mw.Api().post({
'action': 'edit',
'title': ep.pageToEdit,
'section': sectionNum,
'appendtext': '\n\n' + ep.reportText,
'summary': ep.summary,
'basetimestamp': baseTS,
'starttimestamp': curTS,
'token': mw.user.tokens.get('csrfToken'),
'format': 'json'
}).then(function(res) {
if (res && res.edit) {
if (res.edit.result === 'Success') return resolve(true);
}
resolve(false);
}).catch(function(code, err) {
resolve(err.error.info);
});
});
}
/**
* @param {*} ep
* @param {*} type 'dr' when request is cancelled because of duplicates, 'ts' when timestamps failed to be fetched, 'sect' when section number
* failed to be fetcehd, true when edit succeeded, false when unexpected error occurred on edit, errcode when edit failed
*/
function editDone(ep, type) {
const drText = ep.updated ? ' (重複依頼分は除去されました)' : '';
const $msg = $('#ptc-editmessage');
switch(type) {
case 'dr':
$msg.prop('innerHTML', '<span style="color: MediumVioletRed;">中止: 選択分は既に全て依頼されています</span>');
break;
case 'ts':
$msg.prop('innerHTML', '<span style="color: MediumVioletRed;">失敗: 報告先の最新版が取得できませんでした</span>');
break;
case 'sect':
$msg.prop('innerHTML', '<span style="color: MediumVioletRed;">失敗: 報告先のセクション番号が取得できませんでした</span>');
break;
case true:
$msg.prop('innerHTML', `<span style="color: MediumSeaGreen;">成功: 依頼が完了しました${drText}</span>`);
break;
case false:
$msg.prop('innerHTML', '<span style="color: MediumSeaGreen;">失敗: ページの編集段階で不明なエラーが発生しました</span>');
break;
default:
$msg.prop('innerHTML', `<span style="color: MediumVioletRed;">失敗: ${type}</span>`);
break;
}
if (pagelist.length === 0) {
$('#ptc-dialog').dialog({
'buttons': [{
'text': '閉じる',
'click': function() {
$(this).dialog('close');
}
}]
});
} else {
$('#ptc-dialog').dialog({
'buttons': [{
'text': '修正依頼',
'click': submitRequest
}, {
'text': '削除依頼',
'click': submitRequest
}, {
'text': '閉じる',
'click': function() {
$(this).dialog('close');
}
}]
});
}
}
// ********************** EVENT HANDLERS **********************
$(document).off('dialogclose', '#ptc-dialog').on('dialogclose', '#ptc-dialog', function() {
$(this).remove();
if (pagelist.length === 0) $('#ca-ptc').remove();
});
$(document).off('click', '#ptc-checkall-btn').on('click', '#ptc-checkall-btn', function() {
$('.ptc-request-checkbox').prop('checked', true);
});
// ********************** AUXILIARY FUNCTIONS **********************
/**
* String method (alternative) to replace all occurences of a string with another
* (takes a replacer and a replacee as arguments)
* @returns {string}
*/
String.prototype.replaceAllPTC = function() {
var replaced = '';
if (arguments.length %2 !== 0) {
return new Error('SyntaxError: replaceAllPTC takes an even number of arguments.');
} else {
for (let i = 0; i < arguments.length; i = i + 2) {
if (i === 0) {
replaced = this.split(arguments[i]).join(arguments[i + 1]);
} else {
replaced = replaced.split(arguments[i]).join(arguments[i + 1]);
}
}
return replaced;
}
}
})(mediaWiki, jQuery);
//</nowiki>