User:GrabUp/test.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
Documentation for this user script can be added at User:GrabUp/test. |
// Ensure MediaWiki modules are loaded before running the script
mw.loader.using(['mediawiki.util', 'mediawiki.api']).then(function() {
const api = new mw.Api();
// List of unreliable sources and specific subsections to highlight
const unreliableSources = [
"imdb.com",
"example.com",
"youtube.com",
"medium.com",
"reddit.com",
"republicworld.com",
"opindia.com",
"bollywoodlife.com",
{ domain: "khaleejtimes.com", path: "/kt-network/" }, // Example of a specific subsection to treat as unreliable
{ domain: "abplive.com", path: "/brand-wire/" },
{ domain: "charlotteobserver.com", path: "/contributor-content/" },
{ domain: "dailyrecord.co.uk", path: "/special-features/" },
{ domain: "deccanherald.com", path: "/brandspot/" },
{ domain: "digitaljournal.com", path: "/pr/" },
{ domain: "hindustantimes.com", path: "/brand-stories/" },
{ domain: "hindustantimes.com", path: "/brand-post/" },
{ domain: "indiatoday.in", path: "/impact-feature/" },
{ domain: "jpost.com", path: "/brandblend/" },
{ domain: "laprogressive.com", path: "/sponsored/" },
{ domain: "liverpoolecho.co.uk", path: "/special-features/" },
{ domain: "manchestereveningnews.co.uk", path: "/special-features/" },
{ domain: "maxim.com", path: "/partner/" },
{ domain: "livemint.com", path: "/brand-stories/" },
{ domain: "miamiherald.com", path: "/contributor-content/" },
{ domain: "mid-day.com", path: "/brand-media/" },
{ domain: "nytimes.com", path: "/paidpost/" },
{ domain: "timesofindia.indiatimes.com", path: "/spotlight/" },
{ domain: "timesofindia.indiatimes.com", path: "/entertainment/spotlight/" },
{ domain: "thequint.com", path: "/brandstudio/" },
{ domain: "tribuneindia.com", path: "/news/brand-connect/" },
{ domain: "usatoday.com", path: "/sponsor-story/" },
{ domain: "usatoday.com", path: "/special/contributor-content/" }
];
// Add the "Citation Remover" button to the "Actions" section in the toolbar
var citationRemoverButton = mw.util.addPortletLink(
'p-cactions', // Add to the "Actions" section
'#',
'Citation Remover',
'ca-manage-citations',
'List and manage article citations'
);
// Function to force the position of the button in the "Actions" section
function fixButtonPosition() {
var toolbar = document.getElementById('p-cactions').getElementsByTagName('ul')[0];
var button = document.getElementById('ca-manage-citations');
// Specify 'prepend' to place at the top, or 'append' to place at the bottom
toolbar.appendChild(button); // Replace with toolbar.insertBefore(button, toolbar.firstChild) to place it at the top
}
// Run fixButtonPosition once the page is fully loaded
$(document).ready(function() {
fixButtonPosition();
});
document.getElementById('ca-manage-citations').addEventListener('click', function(event) {
event.preventDefault();
loadCitations();
});
function parseCitation(content) {
const titleMatch = content.match(/\|title\s*=\s*([^|]+)/);
const siteMatch = content.match(/\|website\s*=\s*([^|]+)/);
const dateMatch = content.match(/\|date\s*=\s*([^|]+)/);
// Match both <ref>[https://example.com Example]</ref> and <ref>https://example.com Example</ref>
const urlMatch = content.match(/\|url\s*=\s*([^|]+)/) ||
content.match(/\[([^\s]+)(?:\s+[^\]]*)?\]/) ||
content.match(/<ref>(https?:\/\/[^\s]+)(?:\s+(.+?))?<\/ref>/);
const url = urlMatch ? urlMatch[1].trim() : "#";
const site = siteMatch ? siteMatch[1].trim() : (url !== "#" ? new URL(url).hostname : "Unknown Source");
const title = titleMatch ? titleMatch[1].trim() : (urlMatch && urlMatch[2] ? urlMatch[2].trim() : url);
const date = dateMatch ? dateMatch[1].trim() : "";
// Determine if the citation is unreliable based on domain or specific path
const isUnreliable = unreliableSources.some(source => {
if (typeof source === "string") {
// Simple domain-based check
return site.includes(source) || url.includes(source);
} else if (source.domain && source.path) {
// Check for specific domain and path within URL
const domainRegex = new RegExp(`^(https?://)?(www\.)?${source.domain}`);
const pathRegex = new RegExp(`${source.path}`);
return domainRegex.test(url) && pathRegex.test(url);
}
return false;
});
// Debug log for testing
console.log("Checked URL:", url, "| Title:", title, "| Is Unreliable:", isUnreliable);
return {
originalText: content,
title: title,
site: site,
date: date,
url: url,
isUnreliable: isUnreliable
};
}
function loadCitations() {
api.get({
action: "query",
titles: mw.config.get('wgPageName'),
prop: "revisions",
rvprop: "content",
formatversion: "2"
}).then(function(data) {
const pageContent = data.query.pages[0].revisions[0].content;
const citations = extractCitations(pageContent);
displayCitationsPopup(citations);
}).catch(console.error);
}
function extractCitations(content) {
const refTagRegex = /<ref\b[^>]*?\/>|<ref\b[^>]*?>.*?<\/ref>/gs;
const citations = [];
const citationMap = {}; // Track all citations by name to count shortcuts
let match;
while ((match = refTagRegex.exec(content)) !== null) {
const refTag = match[0];
const nameAttrMatch = refTag.match(/name=["']([^"']+)["']/);
const refName = nameAttrMatch ? nameAttrMatch[1] : null;
if (refName) {
if (/\/>$/.test(refTag)) {
citationMap[refName] = citationMap[refName] || { shortcutCount: 0, mainIndex: null };
citationMap[refName].shortcutCount += 1;
} else {
const citation = parseCitation(refTag);
citation.refName = refName;
citation.shortcutCount = citationMap[refName] ? citationMap[refName].shortcutCount : 0;
citations.push(citation);
citationMap[refName] = { shortcutCount: 0, mainIndex: citations.length - 1 };
}
} else {
citations.push(parseCitation(refTag));
}
}
return citations;
}
function displayCitationsPopup(citations) {
const popup = document.createElement("div");
popup.id = "citation-popup";
popup.style.position = "fixed";
popup.style.top = "50%";
popup.style.left = "50%";
popup.style.transform = "translate(-50%, -50%)";
popup.style.padding = "20px";
popup.style.backgroundColor = "#1e1e1e"; // Dark background
popup.style.border = "2px solid #3a3a3a"; // Darker border for subtle contrast
popup.style.borderRadius = "12px";
popup.style.zIndex = "1000";
popup.style.width = "600px";
popup.style.maxHeight = "80%";
popup.style.overflow = "hidden";
popup.style.boxShadow = "0px 8px 16px rgba(0, 0, 0, 0.7)";
// Title bar
const titleBar = document.createElement("div");
titleBar.style.textAlign = "center";
titleBar.style.fontSize = "20px";
titleBar.style.fontWeight = "bold";
titleBar.style.marginBottom = "15px";
titleBar.style.color = "#4ea8ff"; // Light blue color for title
const linkGrabUp = document.createElement("a");
linkGrabUp.href = "https://en.wikipedia.org/wiki/User:GrabUp";
linkGrabUp.textContent = "GrabUp";
linkGrabUp.style.color = "#4ea8ff"; // Ensure the link has the same color
linkGrabUp.style.textDecoration = "none"; // Optional: remove underline
const linkTalk = document.createElement("a");
linkTalk.href = "https://en.wikipedia.org/wiki/User_talk:GrabUp";
linkTalk.textContent = " (Talk)";
linkTalk.style.color = "#4ea8ff"; // Ensure the link has the same color
linkTalk.style.textDecoration = "none"; // Optional: remove underline
// Create the full title text
const titleText = document.createTextNode("Citation Remover by ");
// Append the text and links to the title bar
titleBar.appendChild(titleText);
titleBar.appendChild(linkGrabUp);
titleBar.appendChild(linkTalk);
popup.appendChild(titleBar);
// Close button in top-right corner
const closeButton = document.createElement("button");
closeButton.innerHTML = "×";
closeButton.style.position = "absolute";
closeButton.style.top = "10px";
closeButton.style.right = "10px";
closeButton.style.border = "none";
closeButton.style.background = "transparent";
closeButton.style.fontSize = "24px";
closeButton.style.cursor = "pointer";
closeButton.style.color = "#4ea8ff"; // Light blue color for close button
closeButton.addEventListener("click", () => popup.remove());
popup.appendChild(closeButton);
if (citations.length === 0) {
const message = document.createElement("p");
message.textContent = "No citations found in this article.";
message.style.fontSize = "16px";
message.style.textAlign = "center";
message.style.color = "#ffffff"; // Light text color
popup.appendChild(message);
} else {
const listContainer = document.createElement("div");
listContainer.style.maxHeight = "400px";
listContainer.style.overflowY = "auto";
listContainer.style.marginBottom = "10px";
const list = document.createElement("ol");
citations.forEach((citation, index) => {
const listItem = document.createElement("li");
listItem.style.marginBottom = "15px";
const shortcutText = citation.shortcutCount > 0 ?
`(used ${citation.shortcutCount} more time${citation.shortcutCount > 1 ? 's' : ''})` : "";
listItem.innerHTML = `
<input type="checkbox" class="citation-checkbox" data-index="${index}">
<span style="color: ${citation.isUnreliable ? "tomato" : "#e0e0e0"}; font-size: 16px;">
<a href="${citation.url}" target="_blank" style="color: ${citation.isUnreliable ? "tomato" : "#4ea8ff"}; font-weight: bold; font-size: 18px;">
${index + 1}. ${citation.title} <!-- Added numbering here -->
</a>
<br> <strong>${citation.site}</strong>, ${citation.date} ${shortcutText}
${citation.isUnreliable ? '<br><small style="color: tomato;">Unreliable source</small>' : ""}
</span>
`;
list.appendChild(listItem);
});
const selectAllButton = document.createElement("button");
selectAllButton.textContent = "Select All";
selectAllButton.style.padding = "8px 12px";
selectAllButton.style.marginBottom = "10px";
selectAllButton.style.backgroundColor = "#4ea8ff"; // Light blue color
selectAllButton.style.color = "white";
selectAllButton.style.border = "none";
selectAllButton.style.borderRadius = "6px";
selectAllButton.style.cursor = "pointer";
selectAllButton.addEventListener("click", function() {
const checkboxes = document.querySelectorAll(".citation-checkbox");
checkboxes.forEach(checkbox => checkbox.checked = true);
});
listContainer.appendChild(selectAllButton);
listContainer.appendChild(list);
popup.appendChild(listContainer);
// Fixed "Remove Citations" button
const buttonContainer = document.createElement("div");
buttonContainer.style.position = "absolute";
buttonContainer.style.bottom = "10px";
buttonContainer.style.width = "100%";
buttonContainer.style.display = "flex";
buttonContainer.style.justifyContent = "center";
const removeSelectedButton = document.createElement("button");
removeSelectedButton.textContent = "Remove Citations";
removeSelectedButton.style.padding = "10px 15px";
removeSelectedButton.style.border = "none";
removeSelectedButton.style.backgroundColor = "#d9534f"; // Red for remove button
removeSelectedButton.style.color = "white";
removeSelectedButton.style.borderRadius = "8px";
removeSelectedButton.style.cursor = "pointer";
removeSelectedButton.addEventListener("click", function() {
const selectedCitations = Array.from(document.querySelectorAll(".citation-checkbox:checked"))
.map(checkbox => checkbox.getAttribute("data-index"));
showCommentPopup(selectedCitations);
popup.remove();
});
buttonContainer.appendChild(removeSelectedButton);
popup.appendChild(buttonContainer);
}
document.body.appendChild(popup);
}
function showCommentPopup(selectedIndices) {
const commentPopup = document.createElement("div");
commentPopup.style.position = "fixed";
commentPopup.style.top = "50%";
commentPopup.style.left = "50%";
commentPopup.style.transform = "translate(-50%, -50%)";
commentPopup.style.backgroundColor = "#2b2b2b";
commentPopup.style.padding = "20px";
commentPopup.style.border = "2px solid #3a3a3a";
commentPopup.style.borderRadius = "12px";
commentPopup.style.width = "300px";
commentPopup.style.boxShadow = "0px 8px 16px rgba(0, 0, 0, 0.7)";
const commentLabel = document.createElement("label");
commentLabel.style.color = "#ffffff";
commentLabel.style.fontSize = "14px";
commentLabel.style.fontWeight = "bold";
commentLabel.textContent = "Add Comment:";
const commentInput = document.createElement("textarea");
commentInput.style.width = "100%";
commentInput.style.height = "80px";
commentInput.style.marginTop = "8px";
commentInput.style.borderRadius = "6px";
commentInput.style.padding = "8px";
commentInput.style.backgroundColor = "#404040";
commentInput.style.color = "#e0e0e0";
commentInput.style.border = "1px solid #4a4a4a";
const buttonContainer = document.createElement("div");
buttonContainer.style.display = "flex";
buttonContainer.style.justifyContent = "space-between";
buttonContainer.style.marginTop = "12px";
// Submit button
const submitButton = document.createElement("button");
submitButton.textContent = "Submit";
submitButton.style.padding = "8px 12px";
submitButton.style.backgroundColor = "#4CAF50";
submitButton.style.color = "white";
submitButton.style.borderRadius = "8px";
submitButton.style.cursor = "pointer";
submitButton.addEventListener("click", function() {
const optionalComment = commentInput.value.trim();
const defaultComment = "Removed citations (using [[User:GrabUp/Citation Remover|Citation Remover]])";
const comment = optionalComment ? `"${optionalComment}" | ${defaultComment}` : defaultComment;
removeCitations(selectedIndices, comment);
commentPopup.remove();
});
// Skip button
const skipButton = document.createElement("button");
skipButton.textContent = "Skip";
skipButton.style.padding = "8px 12px";
skipButton.style.backgroundColor = "#f44336";
skipButton.style.color = "white";
skipButton.style.borderRadius = "8px";
skipButton.style.cursor = "pointer";
skipButton.addEventListener("click", function() {
removeCitations(selectedIndices, "Removed citations (using [[User:GrabUp/Citation Remover|Citation Remover]])"); // No additional comment
commentPopup.remove();
});
// Cancel button
const cancelButton = document.createElement("button");
cancelButton.textContent = "Cancel";
cancelButton.style.padding = "8px 12px";
cancelButton.style.backgroundColor = "#6c757d";
cancelButton.style.color = "white";
cancelButton.style.borderRadius = "8px";
cancelButton.style.cursor = "pointer";
cancelButton.addEventListener("click", function() {
commentPopup.remove(); // Close popup without any action
});
buttonContainer.appendChild(submitButton);
buttonContainer.appendChild(skipButton);
buttonContainer.appendChild(cancelButton); // Adding "Cancel" button to the container
commentPopup.appendChild(commentLabel);
commentPopup.appendChild(commentInput);
commentPopup.appendChild(buttonContainer);
document.body.appendChild(commentPopup);
}
function removeCitations(indices, comment) {
api.get({
action: "query",
titles: mw.config.get('wgPageName'),
prop: "revisions",
rvprop: "content",
formatversion: "2"
}).then(function(data) {
let pageContent = data.query.pages[0].revisions[0].content;
const citations = extractCitations(pageContent);
// Collect the original texts of selected citations for deletion
const citationsToRemove = indices.map(index => citations[index].originalText);
// Remove citations by matching original text to avoid index shifting
citationsToRemove.forEach(citationText => {
pageContent = pageContent.replace(citationText, "");
});
return api.postWithToken("csrf", {
action: "edit",
title: mw.config.get('wgPageName'),
text: pageContent,
summary: comment
});
}).then(function(editData) {
const newRevisionId = editData.edit.newrevid;
if (newRevisionId) {
window.location.href = mw.util.getUrl(mw.config.get('wgPageName'), {diff: newRevisionId});
}
}).catch(console.error);
}
function deleteRefTag(content, citation) {
const refName = citation.refName;
if (refName) {
const refTagRegex = new RegExp(
`<ref\\b[^>]*?name=["']${escapeRegExp(refName)}["'][^>]*?\\/?>|<ref\\b[^>]*?name=["']${escapeRegExp(refName)}["'][^>]*?>.*?<\\/ref>`,
"gs"
);
content = content.replace(refTagRegex, "");
}
return content.replace(citation.originalText, "");
}
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
});