// <nowiki>
(function() {
function removeExternalLinks() {
const validNamespaces = [0, 100, 2, 118];
if (!validNamespaces.includes(mw.config.get('wgNamespaceNumber'))) {
alert("This tool can only be used on article, sandbox, user, or draft pages.");
return;
}
const confirmationContainer = document.createElement('div');
confirmationContainer.innerHTML = `
<div style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: rgba(30, 30, 30, 0.9); color: white; border: 2px solid #ccc; padding: 30px; z-index: 1000; border-radius: 8px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);">
<p style="font-size: 18px; font-weight: bold;">Are you sure you want to remove external links from this article?</p>
<button id="confirm-yes" style="margin: 5px; padding: 10px 15px; cursor: pointer; background: #007bff; color: white; border: none; border-radius: 4px;">Yes</button>
<button id="confirm-no" style="margin: 5px; padding: 10px 15px; cursor: pointer; background: #dc3545; color: white; border: none; border-radius: 4px;">No</button>
</div>
`;
document.body.appendChild(confirmationContainer);
document.getElementById('confirm-yes').onclick = function() {
document.body.removeChild(confirmationContainer);
promptForComment();
};
document.getElementById('confirm-no').onclick = function() {
document.body.removeChild(confirmationContainer);
};
}
function promptForComment() {
const commentContainer = document.createElement('div');
commentContainer.innerHTML = `
<div style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: rgba(30, 30, 30, 0.9); color: white; border: 2px solid #ccc; padding: 30px; z-index: 1000; border-radius: 8px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);">
<p style="font-size: 18px; font-weight: bold;">Would you like to add additional edit summaries? If yes, please enter below:</p>
<textarea id="edit-summary" rows="6" cols="50" placeholder="Enter your comments here..." style="width: 100%; padding: 10px; border-radius: 4px; border: 1px solid #ccc;"></textarea>
<br><br>
<button id="submit-comment" style="margin: 5px; padding: 10px 15px; cursor: pointer; background: #007bff; color: white; border: none; border-radius: 4px;">Submit</button>
<button id="skip-comment" style="margin: 5px; padding: 10px 15px; cursor: pointer; background: #007bff; color: white; border: none; border-radius: 4px;">Skip</button>
<button id="cancel" style="margin: 5px; padding: 10px 15px; cursor: pointer; background: #dc3545; color: white; border: none; border-radius: 4px;">Cancel</button>
</div>
`;
document.body.appendChild(commentContainer);
document.getElementById('submit-comment').onclick = function() {
const additionalSummaries = document.getElementById('edit-summary').value.trim();
let editSummary = 'Removed external links, Using [[User:GrabUp/External_Links_Remover| External Links Remover]]';
if (additionalSummaries) {
editSummary += ' | ' + additionalSummaries.split('|').map(summary => summary.trim()).join(' | ');
}
processEdit(editSummary);
document.body.removeChild(commentContainer);
};
document.getElementById('skip-comment').onclick = function() {
const editSummary = 'Removed external links, Using [[User:GrabUp/External_Links_Remover| External Links Remover]]';
processEdit(editSummary);
document.body.removeChild(commentContainer);
};
document.getElementById('cancel').onclick = function() {
document.body.removeChild(commentContainer);
};
}
function processEdit(editSummary) {
const api = new mw.Api();
api.get({
action: 'query',
prop: 'revisions',
rvprop: 'content',
titles: mw.config.get('wgPageName'),
formatversion: 2
}).done(function(data) {
const page = data.query.pages[0];
if (!page || !page.revisions) {
alert("Failed to fetch page content.");
return;
}
let text = page.revisions[0].content;
const externalLinkPattern = /(?:\[(http[s]?:\/\/[^\s]+)\s*([^\]]+)?\]|(http[s]?:\/\/[^\s]+))/g;
const refPattern = /<ref[^>]*>[\s\S]*?<\/ref>/g;
const citeWebPattern = /{{\s*(Cite\s+web|Cite\s+news|Cite\s+book|Cite\s+journal).*?}}/g;
const urlTemplatePattern = /{{\s*(URL|url)\s*\|\s*[^\}]+\s*}}/g;
const sectionHeadingPattern = /(==\s*(References|External links)\s*==\n?)/gi;
const refPlaceholders = [];
const citePlaceholders = [];
const urlPlaceholders = [];
text = text.replace(refPattern, match => {
refPlaceholders.push(match);
return `REF_PLACEHOLDER_${refPlaceholders.length - 1}`;
});
text = text.replace(citeWebPattern, match => {
citePlaceholders.push(match);
return `CITE_PLACEHOLDER_${citePlaceholders.length - 1}`;
});
text = text.replace(urlTemplatePattern, match => {
urlPlaceholders.push(match);
return `URL_PLACEHOLDER_${urlPlaceholders.length - 1}`;
});
let linkRemoved = false;
const externalLinksSectionIndex = text.search(/==\s*External links\s*==/i);
if (externalLinksSectionIndex !== -1) {
let beforeExternalLinks = text.slice(0, externalLinksSectionIndex);
const afterExternalLinks = text.slice(externalLinksSectionIndex);
beforeExternalLinks = beforeExternalLinks.replace(externalLinkPattern, (match, p1, p2) => {
linkRemoved = true;
return `<span style="background-color: yellow;">${p2 ? p2.trim() : ''}</span>`;
});
text = beforeExternalLinks + afterExternalLinks;
} else {
text = text.replace(externalLinkPattern, (match, p1, p2) => {
linkRemoved = true;
return `<span style="background-color: yellow;">${p2 ? p2.trim() : ''}</span>`;
});
}
refPlaceholders.forEach((ref, index) => {
text = text.replace(`REF_PLACEHOLDER_${index}`, ref);
});
citePlaceholders.forEach((cite, index) => {
text = text.replace(`CITE_PLACEHOLDER_${index}`, cite);
});
urlPlaceholders.forEach((url, index) => {
text = text.replace(`URL_PLACEHOLDER_${index}`, url);
});
text = text.replace(sectionHeadingPattern, (match, heading) => heading.trim() + '\n');
if (linkRemoved) {
showPreview(text.trim(), editSummary);
} else {
const noLinksContainer = document.createElement('div');
noLinksContainer.innerHTML = `
<div style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: rgba(30, 30, 30, 0.9); color: white; border: 2px solid #ccc; padding: 30px; z-index: 1000; border-radius: 8px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);">
<p style="font-size: 18px; font-weight: bold;">No external links found to remove</p>
<button id="close-no-links" style="padding: 10px 15px; cursor: pointer; background: #007bff; color: white; border: none; border-radius: 4px;">OK</button>
</div>
`;
document.body.appendChild(noLinksContainer);
document.getElementById('close-no-links').onclick = function() {
document.body.removeChild(noLinksContainer);
};
}
});
}
function showPreview(previewContent, editSummary) {
// Create a preview container with a black background and high-contrast text.
const previewContainer = document.createElement('div');
previewContainer.innerHTML = `
<div style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: rgba(0, 0, 0, 0.95); color: white; border: 2px solid #ccc; padding: 30px; z-index: 1000; border-radius: 8px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5); width: 80%; max-height: 80%; display: flex; flex-direction: column;">
<h3 style="font-size: 18px; font-weight: bold;">Preview Changes</h3>
<pre style="background: #000; color: #ffffff; padding: 15px; border-radius: 4px; flex-grow: 1; overflow-y: auto; white-space: pre-wrap;">
${previewContent.replace(/background-color: yellow;/g, 'background-color: blue;')}
</pre>
<div style="text-align: center; margin-top: 10px;">
<button id="confirm-save" style="margin: 5px; padding: 10px 15px; cursor: pointer; background: #007bff; color: white; border: none; border-radius: 4px;">Save</button>
<button id="cancel-preview" style="margin: 5px; padding: 10px 15px; cursor: pointer; background: #dc3545; color: white; border: none; border-radius: 4px;">Cancel</button>
</div>
</div>
`;
document.body.appendChild(previewContainer);
// Confirm and cancel buttons functionality
document.getElementById('confirm-save').onclick = function() {
const finalContent = previewContent.replace(/<span style="background-color: yellow;">(.*?)<\/span>/g, '$1');
const api = new mw.Api();
api.postWithEditToken({
action: 'edit',
title: mw.config.get('wgPageName'),
text: finalContent, // Save without any highlighting
summary: editSummary
}).done(function(data) {
const newRevId = data.edit.newrevid;
window.location.href = mw.util.getUrl(mw.config.get('wgPageName'), { diff: newRevId });
}).fail(function() {
alert("Failed to save changes.");
});
document.body.removeChild(previewContainer);
};
document.getElementById('cancel-preview').onclick = function() {
document.body.removeChild(previewContainer);
};
}
mw.loader.using('mediawiki.api', function() {
mw.util.addPortletLink(
'p-cactions',
'#',
'Remove External Links',
'ca-remove-external-links',
'Removes all external links from the article'
);
document.getElementById('ca-remove-external-links').onclick = removeExternalLinks;
});
})();
// </nowiki>