No edit summary |
No edit summary |
||
(134 intermediate revisions by 3 users not shown) | |||
Line 64: | Line 64: | ||
' width: 100%;', | ' width: 100%;', | ||
' margin-top: 5px;', | ' margin-top: 5px;', | ||
' background-color: #fff;', | ' background-color: #fff;', | ||
' z-index: 1000;', | ' z-index: 1000;', | ||
Line 83: | Line 82: | ||
var query = $(this).val(); | var query = $(this).val(); | ||
if (query.length > 0) { | if (query.length > 0) { | ||
var apiUrl = "https:// | var apiUrl = "https://wiki.mdriven.net/api.php"; | ||
var requestData = { | var requestData = { | ||
action: "bs-extendedsearch-autocomplete", | action: "bs-extendedsearch-autocomplete", | ||
Line 154: | Line 153: | ||
} | } | ||
// Function to open the | // Function to open the submenu containing the current page link and scroll to it | ||
function | function openCurrentPageSubmenuAndScroll() { | ||
var | var currentPageLink = $('#navMenu .current-page'); | ||
if (currentPageLink.length) { | |||
// Open the parent submenu(s) of the current page link | |||
currentPageLink.parents('.submenu').show(); | |||
// Delay the scrolling to allow for any dynamic layout changes | |||
setTimeout(function() { | |||
// Calculate the position of the current page link | |||
var position = currentPageLink.offset().top - $('#navMenu').offset().top + $('#navMenu').scrollTop(); | |||
// Scroll the menu to the active item | |||
$('#navMenu').animate({ | |||
scrollTop: position | |||
}, 500); | |||
}, 100); // Delay of 100 milliseconds | |||
} | } | ||
} | } | ||
// Event | // Event delegation for dynamically loaded content | ||
$('.menu-header' | $('#navMenu').on('click', '.menu-header', function() { | ||
toggleSection(this); | toggleSection(this); | ||
}); | }); | ||
// Open the | // Open the submenu containing the current page link and scroll to it | ||
openCurrentPageSubmenuAndScroll(); | |||
}); | |||
document.getElementById('menu-toggle').addEventListener('click', function() { | |||
var navMenu = document.getElementById('navMenu'); | |||
var bodyContent = document.getElementById('bodyContent'); | |||
if (navMenu.style.display === 'none' || navMenu.style.display === '') { | |||
navMenu.style.display = 'block'; | |||
bodyContent.style.display = 'none'; // Hide body content when nav menu is displayed | |||
} else { | |||
navMenu.style.display = 'none'; | |||
bodyContent.style.display = 'block'; // Show body content when nav menu is hidden | |||
} | |||
}); | |||
$(document).ready(function() { | |||
$('.video__navigation .navigation-item').click(function() { | |||
var videoID = $(this).data('video'); | |||
var startTime = $(this).data('start'); | |||
var newSrc = 'https://www.youtube.com/embed/' + videoID + '?start=' + startTime + '&autoplay=1'; | |||
$('.video__wrapper iframe').attr('src', newSrc); | |||
}); | |||
}); | |||
$(document).ready(function() { | |||
$('.bs-extendedsearch-filter-button-button').each(function() { | |||
$(this).append('<span class="fa fa-chevron-down"></span>'); | |||
}); | |||
}); | |||
document.addEventListener("scroll", function() { | |||
var sidebar = document.getElementById("navMenu"); | |||
var footerHeight = 100; | |||
var windowHeight = window.innerHeight; | |||
var scrollBottomPosition = window.scrollY + windowHeight; | |||
var footerTopPosition = document.documentElement.offsetHeight - footerHeight; | |||
if (scrollBottomPosition <= footerTopPosition) { | |||
sidebar.style.height = "100vh"; | |||
} else { | |||
sidebar.style.height = "calc(100vh - 110px)"; | |||
} | |||
}); | |||
mw.loader.using('jquery', function() { | |||
$(document).ready(function() { | |||
var $toc = $('#toc').clone(); | |||
$('#toc').remove(); | |||
$('#tocContainer').html($toc); | |||
$('#tocContainer').css({ | |||
position: '-webkit-sticky', | |||
position: 'sticky', | |||
top: '0', | |||
padding: '15px', | |||
margin: '0 auto', | |||
borderRadius: '5px', | |||
maxWidth: '280px', | |||
maxHeight: 'max-content', | |||
overflowY: 'auto', | |||
height: '90vh', | |||
zIndex: 1000 | |||
}); | |||
$('#tocContainer .toctitle').css({ | |||
fontSize: '16px', | |||
fontWeight: '600', | |||
color: '#555', | |||
borderBottom: '1px solid #ccc', | |||
paddingBottom: '10px', | |||
marginBottom: '10px' | |||
}); | |||
$('#tocContainer ul').css({ | |||
margin: 0, | |||
padding: '0 0 0 20px', | |||
listStyleType: 'none', | |||
fontSize: '14px', | |||
lineHeight: '1.6' | |||
}); | |||
$('#tocContainer li').css({ | |||
marginBottom: '5px', | |||
}); | |||
$('#tocContainer a').css({ | |||
color: '#555', | |||
textDecoration: 'none', | |||
}).hover( | |||
function() { $(this).css({textDecoration: 'underline', color: '#000'}); }, | |||
function() { $(this).css({textDecoration: 'none', color: '#555'}); } | |||
); | |||
}); | |||
}); | |||
$(document).ready(function() { | |||
var $inputElement = $('.oo-ui-textInputWidget-type-search .oo-ui-inputWidget-input'); | |||
if ($inputElement.length) { | |||
$inputElement.on('keydown', function(event) { | |||
if (event.key === 'Enter') { | |||
event.preventDefault(); | |||
$inputElement.addClass('search-input'); | |||
} | |||
}); | |||
} | |||
}); | |||
$(document).ready(function() { | |||
var $inputElement = $('.oo-ui-textInputWidget-type-search .oo-ui-inputWidget-input'); | |||
if ($inputElement.length) { | |||
$inputElement.addClass('search-input'); | |||
console.log('Class "search-input" added to the input element.'); | |||
} else { | |||
console.log('Input element not found.'); | |||
} | |||
}); | |||
$(document).ready(function() { | |||
var signInLink = $('#user-info a'); | |||
var currentUrl = encodeURIComponent(window.location.pathname + window.location.search + window.location.hash); | |||
signInLink.attr('href', signInLink.attr('href').replace('<CURRENT_URL>', currentUrl)); | |||
}); | |||
document.addEventListener('DOMContentLoaded', function() { | |||
var images = document.querySelectorAll('.thumbimage'); | |||
var overlay = document.createElement('div'); | |||
overlay.className = 'image-overlay'; | |||
document.body.appendChild(overlay); | |||
var overlayImage = document.createElement('img'); | |||
overlay.appendChild(overlayImage); | |||
images.forEach(function(image) { | |||
image.addEventListener('click', function(event) { | |||
event.preventDefault(); | |||
event.stopPropagation(); | |||
overlayImage.src = image.src; | |||
overlay.classList.add('show'); | |||
}); | |||
}); | |||
overlay.addEventListener('click', function() { | |||
overlay.classList.remove('show'); | |||
}); | |||
}); | |||
// ==UserScript== | |||
// @name MediaWiki Clean Delete | |||
// @namespace MediaWikiScripts | |||
// @description Adds a 'Clean Delete' action link to pages for admins to delete pages and clean up incoming links and redirects. | |||
// ==/UserScript== | |||
mw.loader.using(['mediawiki.api', 'mediawiki.util', 'jquery'], function () { | |||
function addCleanDeleteLink() { | |||
if (mw.config.get('wgUserGroups').indexOf('sysop') !== -1) { | |||
if ($('#ca-cleandelete').length === 0) { | |||
var $link = $('<div>').attr('id', 'ca-cleandelete').attr('class', 'mw-list-item').append( | |||
$('<a>').attr('href', '#').attr('class', 'ca-cleandelete').text('Clean Delete').click(function (e) { | |||
e.preventDefault(); | |||
gatherAllDecisions(mw.config.get('wgPageName')); | |||
}) | |||
); | |||
$('#p-actions .tab-group').append($link); | |||
} | |||
} | |||
} | |||
function gatherAllDecisions(pageTitle) { | |||
var decisions = {}; | |||
showModal('Handle Links and Redirects', '<div class="form-group">' + | |||
'<label>Specify how you would like to handle all incoming links and redirects:</label>' + | |||
'<select id="link-handling-select" class="form-control">' + | |||
'<option value="delete">Delete Links and Redirects</option>' + | |||
'<option value="change">Change Target of Links and Redirects</option>' + | |||
'</select>' + | |||
'</div>', function () { | |||
var choice = $('#link-handling-select').val(); | |||
if (choice === 'change') { | |||
showModal('Specify New Target', '<div class="form-group">' + | |||
'<label>Enter the new target page name to update all links and redirects:</label>' + | |||
'<input type="text" id="new-target-input" class="form-control" placeholder="Enter new target">' + | |||
'</div>', function () { | |||
decisions.links = $('#new-target-input').val(); | |||
confirmDeletion(pageTitle, decisions); | |||
}); | |||
} else { | |||
decisions.links = ''; | |||
confirmDeletion(pageTitle, decisions); | |||
} | |||
}); | |||
} | |||
function confirmDeletion(pageTitle, decisions) { | |||
showModal('Confirm Page Deletion', '<p>Are you sure you want to delete "' + pageTitle + '" after handling all links and redirects?</p>', function () { | |||
decisions.deletion = true; | |||
showLoadingDialog('Performing Cleanup', function (loadingDialog, updateLoadingText, logDetail) { | |||
executeAllActions(pageTitle, decisions, function () { | |||
loadingDialog.close().closed.then(function() { | |||
location.reload(); | |||
}); | |||
}, updateLoadingText, logDetail); | |||
}); | |||
}); | |||
} | |||
function showModal(title, body, onConfirm) { | |||
var modal = $( | |||
'<div class="modal fade" tabindex="-1" role="dialog">' + | |||
'<div class="modal-dialog" role="document">' + | |||
'<div class="modal-content">' + | |||
'<div class="modal-header">' + | |||
'<h5 class="modal-title">' + title + '</h5>' + | |||
'<button type="button" class="close" data-dismiss="modal" aria-label="Close">' + | |||
'<span aria-hidden="true">×</span>' + | |||
'</button>' + | |||
'</div>' + | |||
'<div class="modal-body">' + body + '</div>' + | |||
'<div class="modal-footer">' + | |||
'<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>' + | |||
'<button type="button" class="btn btn-primary">Confirm</button>' + | |||
'</div>' + | |||
'</div>' + | |||
'</div>' + | |||
'</div>' | |||
); | |||
modal.find('.btn-primary').click(function () { | |||
onConfirm(); | |||
modal.modal('hide'); | |||
}); | |||
modal.on('hidden.bs.modal', function () { | |||
modal.remove(); | |||
}); | |||
$('body').append(modal); | |||
modal.modal('show'); | |||
} | |||
function showLoadingDialog(message, callback) { | |||
var modal = $( | |||
'<div class="modal fade" tabindex="-1" role="dialog">' + | |||
'<div class="modal-dialog" role="document">' + | |||
'<div class="modal-content">' + | |||
'<div class="modal-header">' + | |||
'<h5 class="modal-title">Performing Cleanup</h5>' + | |||
'</div>' + | |||
'<div class="modal-body">' + | |||
'<p id="loading-text">' + message + '</p>' + | |||
'<ul id="loading-log"></ul>' + | |||
'</div>' + | |||
'</div>' + | |||
'</div>' + | |||
'</div>' | |||
); | |||
$('body').append(modal); | |||
modal.modal('show'); | |||
callback(modal, function (text) { | |||
$('#loading-text').text(text); | |||
$('#loading-log').append('<li>' + text + '</li>'); | |||
}, function (detail) { | |||
$('#loading-log').append('<li>' + detail + '</li>'); | |||
}); | |||
} | |||
function executeAllActions(pageTitle, decisions, callback, updateLoadingText, logDetail) { | |||
var api = new mw.Api(); | |||
function handleLinksAndRedirects(action, newTarget, next) { | |||
updateLoadingText('Fetching backlinks...'); | |||
api.get({ | |||
action: 'query', | |||
list: 'backlinks', | |||
bltitle: pageTitle, | |||
bllimit: 'max', | |||
blfilterredir: 'all' // Include both redirects and non-redirects | |||
}).done(function (data) { | |||
logDetail('Backlinks fetched.'); | |||
if (data.query.backlinks) { | |||
var promises = $.map(data.query.backlinks, function (link) { | |||
return new $.Deferred(function (defer) { | |||
api.get({ | |||
action: 'parse', | |||
page: link.title, | |||
prop: 'wikitext' | |||
}).done(function (linkData) { | |||
var isRedirect = linkData.parse.wikitext['*'].trim().startsWith('#REDIRECT'); | |||
if (isRedirect) { | |||
if (action === 'update') { | |||
updateRedirectTarget(link.title, newTarget, api, defer.resolve, logDetail); | |||
} else { | |||
logDetail('Backlink ' + link.title + ' is a redirect. Deleting...'); | |||
performDeletion(link.title, defer.resolve, logDetail); | |||
} | |||
} else { | |||
if (action === 'update') { | |||
updateLinkInPage(link.title, pageTitle, newTarget, api, defer.resolve, logDetail); | |||
} else { | |||
removeLinkFromPage(link.title, pageTitle, api, defer.resolve, logDetail); | |||
} | |||
} | |||
}).fail(function (error) { | |||
logDetail('Error checking if backlink ' + link.title + ' is a redirect: ' + error); | |||
defer.resolve(); | |||
}); | |||
}).promise(); | |||
}); | |||
$.when.apply($, promises).then(function () { | |||
updateLoadingText(action === 'update' ? 'All links updated.' : 'All links removed.'); | |||
next(); | |||
}); | |||
} else { | |||
next(); | |||
} | |||
}).fail(function (error) { | |||
updateLoadingText('Error fetching backlinks: ' + error); | |||
next(); | |||
}); | |||
} | |||
function updateLinkInPage(linkedPageTitle, originalPageTitle, newTarget, api, resolve, logDetail) { | |||
api.get({ | |||
action: 'parse', | |||
page: linkedPageTitle, | |||
prop: 'wikitext' | |||
}).then(function (data) { | |||
var wikitext = data.parse.wikitext['*']; | |||
var regex = new RegExp('\\[\\[' + originalPageTitle.replace(/[\[\]]/g, '\\$&') + '(\\|[^\\]]+)?\\]\\]', 'g'); | |||
var newWikitext = wikitext.replace(regex, '[[' + newTarget + '$1]]'); | |||
if (wikitext !== newWikitext) { | |||
logDetail('Updating link in ' + linkedPageTitle); | |||
} else { | |||
logDetail('No link found in ' + linkedPageTitle); | |||
} | |||
return api.postWithToken('csrf', { | |||
action: 'edit', | |||
title: linkedPageTitle, | |||
text: newWikitext, | |||
summary: 'Updated link to [[' + newTarget + ']]' | |||
}).then(function (response) { | |||
console.log('API response from updating link: ', response); | |||
if (response.edit && response.edit.result === 'Success' && !response.edit.nochange) { | |||
logDetail('Successfully updated link in ' + linkedPageTitle); | |||
} else { | |||
logDetail('No changes made to link in ' + linkedPageTitle); | |||
} | |||
resolve(); | |||
}).fail(function (error) { | |||
logDetail('Error updating link in ' + linkedPageTitle + ': ' + error); | |||
resolve(); | |||
}); | |||
}).fail(function (error) { | |||
logDetail('Error fetching page content for ' + linkedPageTitle + ': ' + error); | |||
resolve(); | |||
}); | |||
} | |||
function updateRedirectTarget(redirectPageTitle, newTarget, api, resolve, logDetail) { | |||
logDetail('Updating redirect target in ' + redirectPageTitle); | |||
return api.postWithToken('csrf', { | |||
action: 'edit', | |||
title: redirectPageTitle, | |||
text: '#REDIRECT [[' + newTarget + ']]', | |||
summary: 'Updated redirect to [[' + newTarget + ']]' | |||
}).then(function (response) { | |||
console.log('API response from updating redirect: ', response); | |||
if (response.edit && response.edit.result === 'Success' && !response.edit.nochange) { | |||
logDetail('Successfully updated redirect in ' + redirectPageTitle); | |||
} else { | |||
logDetail('No changes made to redirect in ' + redirectPageTitle); | |||
} | |||
resolve(); | |||
}).fail(function (error) { | |||
logDetail('Error updating redirect in ' + redirectPageTitle + ': ' + error); | |||
resolve(); | |||
}); | |||
} | |||
function removeLinkFromPage(linkedPageTitle, originalPageTitle, api, resolve, logDetail) { | |||
api.get({ | |||
action: 'parse', | |||
page: linkedPageTitle, | |||
prop: 'wikitext' | |||
}).then(function (data) { | |||
var wikitext = data.parse.wikitext['*']; | |||
var regex = new RegExp('\\[\\[' + originalPageTitle.replace(/[\[\]]/g, '\\$&') + '(\\|[^\\]]+)?\\]\\]', 'g'); | |||
var newWikitext = wikitext.replace(regex, function(match, p1) { | |||
return p1 ? p1.substring(1) : originalPageTitle; | |||
}); | |||
if (wikitext !== newWikitext) { | |||
logDetail('Removing link from ' + linkedPageTitle); | |||
} else { | |||
logDetail('No link found in ' + linkedPageTitle); | |||
} | |||
return api.postWithToken('csrf', { | |||
action: 'edit', | |||
title: linkedPageTitle, | |||
text: newWikitext, | |||
summary: 'Removed link to [[' + originalPageTitle + ']]' | |||
}).then(function (response) { | |||
console.log('API response from removing link: ', response); | |||
if (response.edit && response.edit.result === 'Success' && !response.edit.nochange) { | |||
logDetail('Successfully removed link from ' + linkedPageTitle); | |||
} else { | |||
logDetail('No changes made to link in ' + linkedPageTitle); | |||
} | |||
resolve(); | |||
}).fail(function (error) { | |||
logDetail('Error removing link from ' + linkedPageTitle + ': ' + error); | |||
resolve(); | |||
}); | |||
}).fail(function (error) { | |||
logDetail('Error fetching page content for ' + linkedPageTitle + ': ' + error); | |||
resolve(); | |||
}); | |||
} | |||
function handleRedirects(next) { | |||
updateLoadingText('Fetching redirects...'); | |||
api.get({ | |||
action: 'query', | |||
titles: pageTitle, | |||
redirects: true | |||
}).done(function (data) { | |||
logDetail('Redirects fetched.'); | |||
var redirects = data.query.pages[Object.keys(data.query.pages)[0]].redirects; | |||
if (redirects) { | |||
var promises = $.map(redirects, function (redirect) { | |||
return new $.Deferred(function (defer) { | |||
logDetail('Found redirect: ' + redirect.title); | |||
performDeletion(redirect.title, defer.resolve, logDetail); | |||
}).promise(); | |||
}); | |||
$.when.apply($, promises).then(function () { | |||
next(); | |||
}); | |||
} else { | |||
next(); | |||
} | |||
}).fail(function (error) { | |||
updateLoadingText('Error fetching redirects: ' + error); | |||
next(); | |||
}); | |||
} | |||
function performDeletion(pageTitle, resolve, logDetail) { | |||
updateLoadingText('Deleting the page: ' + pageTitle); | |||
api.postWithToken('csrf', { | |||
action: 'delete', | |||
title: pageTitle, | |||
reason: 'Automated clean delete by admin' | |||
}).done(function (response) { | |||
console.log('API response from deleting page: ', response); | |||
if (response.delete && response.delete.title) { | |||
logDetail('Successfully deleted page: ' + response.delete.title); | |||
} else { | |||
logDetail('No deletion performed for ' + pageTitle); | |||
} | |||
resolve(); | |||
}).fail(function (error) { | |||
logDetail('Error during clean deletion of ' + pageTitle + ': ' + error); | |||
resolve(); | |||
}); | |||
} | |||
var tasks = [ | |||
function (resolve) { | |||
if (decisions.links === '') { | |||
handleLinksAndRedirects('remove', '', resolve); | |||
} else { | |||
handleLinksAndRedirects('update', decisions.links, resolve); | |||
} | |||
}, | |||
function (resolve) { | |||
if (decisions.deletion) { | |||
handleRedirects(resolve); | |||
} else { | |||
resolve(); | |||
} | |||
}, | |||
function (resolve) { | |||
if (decisions.deletion) { | |||
performDeletion(pageTitle, resolve, logDetail); | |||
} else { | |||
resolve(); | |||
} | |||
} | |||
]; | |||
(function executeTasks(i) { | |||
if (i < tasks.length) { | |||
tasks[i](function () { | |||
executeTasks(i + 1); | |||
}); | |||
} else { | |||
callback(); | |||
} | |||
})(0); | |||
} | |||
mw.hook('wikipage.content').add(addCleanDeleteLink); | |||
}); | |||
function isLoggedOut() { | |||
return mw.config.get('wgUserName') === null; | |||
} | |||
jQuery(document).ready(function ($) { | |||
if (isLoggedOut()) { | |||
$('body').append('<div class="darken-overlay"></div>'); | |||
$('img').each(function () { | |||
var imgSrc = $(this).attr('src'); | |||
if (imgSrc !== '/images/MDrivenLogo.png') { | |||
$(this).addClass('enlargeable'); | |||
} | |||
}); | |||
$('img.enlargeable').click(function (event) { | |||
event.preventDefault(); | |||
event.stopPropagation(); | |||
if ($(this).hasClass('enlarged')) { | |||
$(this).removeClass('enlarged'); | |||
$('.darken-overlay').hide(); | |||
} else { | |||
$('img.enlargeable').removeClass('enlarged'); | |||
$(this).addClass('enlarged'); | |||
$('.darken-overlay').show(); | |||
var fullSizeSrc = $(this).attr('src').replace('/thumb', '').replace(/\/\d+px-.+$/, ''); | |||
$(this).attr('src', fullSizeSrc); | |||
} | |||
}); | |||
$('.darken-overlay').click(function () { | |||
$('img.enlargeable').removeClass('enlarged'); | |||
$(this).hide(); | |||
}); | |||
} | |||
}); | }); |
Latest revision as of 10:31, 17 February 2025
/* Any JavaScript here will be loaded for all users on every page load. */
$(document).ready(function () {
$.get(mw.util.wikiScript('api'), {
action: 'query',
meta: 'userinfo',
format: 'json'
}).done(function (data) {
if (data.query.userinfo.id !== 0) {
var username = data.query.userinfo.name;
var userLink = mw.util.getUrl('User:' + username);
var logoutLink = mw.util.getUrl('Special:Logout');
$('#user-info').html('<a href="' + userLink + '" class="text-white">' + username + '</a>' +
' | <a href="' + logoutLink + '" class="text-white">Logout</a>');
}
});
});
document.getElementById('offcanvas-toggler').addEventListener('click', function() {
var sidebar = document.getElementById('offcanvas-menu');
if (sidebar.classList.contains('show')) {
sidebar.classList.remove('show');
} else {
sidebar.classList.add('show');
}
});
$(document).ready(function() {
$('#offcanvas-close').on('click', function() {
$('#offcanvas-menu').removeClass('show');
});
});
document.addEventListener('DOMContentLoaded', function() {
var form = document.querySelector('.namespace-search-form');
if (form) {
form.addEventListener('submit', function(e) {
var input = form.querySelector('#bs-extendedsearch-input');
if (input) {
var namespace = mw.config.get('wgCanonicalNamespace');
if (namespace && namespace.length > 0) {
input.value = namespace + ": " + input.value;
}
}
});
}
});
(function($) {
'use strict';
var css = [
'#suggestion-container {',
' position: relative;',
' width: 100%;',
'}',
'#suggestion-box {',
' position: absolute;',
' top: 100%;',
' left: 0;',
' width: 100%;',
' margin-top: 5px;',
' background-color: #fff;',
' z-index: 1000;',
'}',
'.suggestion-item {',
' padding: 8px;',
' cursor: pointer;',
'}',
'.suggestion-item:hover {',
' background-color: #e0e0e0;',
'}'
].join('\n');
$('head').append('<style type="text/css">' + css + '</style>');
$('#suggestion-container').append('<div id="suggestion-box"></div>');
function showSuggestions() {
var query = $(this).val();
if (query.length > 0) {
var apiUrl = "https://wiki.mdriven.net/api.php";
var requestData = {
action: "bs-extendedsearch-autocomplete",
format: "json",
q: JSON.stringify({
query: {
bool: {
must: {
match: {
ac_ngram: {
query: query
}
}
}
}
},
size: 8
}),
searchData: JSON.stringify({
namespace: 0,
value: query,
mainpage: ""
})
};
$.ajax({
url: apiUrl,
data: requestData,
dataType: "json",
method: "GET",
success: function(data) {
var suggestions = data.suggestions || [];
$('#suggestion-box').empty();
$.each(suggestions, function(index, suggestion) {
var item = $('<div class="suggestion-item"></div>').text(suggestion.basename);
$('#suggestion-box').append(item);
});
},
error: function(jqxhr, textStatus, error) {
console.error('Error fetching suggestions:', error);
}
});
}
}
function hideSuggestions(event) {
if (!$(event.target).closest('#suggestion-container').length) {
$('#suggestion-box').empty();
}
}
function selectSuggestion(event) {
event.preventDefault(); // Prevent the mousedown event from triggering blur on the search input
var selectedText = $(this).text();
window.location.href = '/index.php?title=' + encodeURIComponent(selectedText);
}
$('.search-input').on('input', showSuggestions);
$(document).on('click', hideSuggestions);
$('#suggestion-box').on('mousedown', '.suggestion-item', selectSuggestion);
})(jQuery);
$(document).ready(function() {
// Function to toggle a section open or closed
function toggleSection(element) {
var submenu = $(element).next('.submenu');
submenu.toggle();
}
// Function to open the submenu containing the current page link and scroll to it
function openCurrentPageSubmenuAndScroll() {
var currentPageLink = $('#navMenu .current-page');
if (currentPageLink.length) {
// Open the parent submenu(s) of the current page link
currentPageLink.parents('.submenu').show();
// Delay the scrolling to allow for any dynamic layout changes
setTimeout(function() {
// Calculate the position of the current page link
var position = currentPageLink.offset().top - $('#navMenu').offset().top + $('#navMenu').scrollTop();
// Scroll the menu to the active item
$('#navMenu').animate({
scrollTop: position
}, 500);
}, 100); // Delay of 100 milliseconds
}
}
// Event delegation for dynamically loaded content
$('#navMenu').on('click', '.menu-header', function() {
toggleSection(this);
});
// Open the submenu containing the current page link and scroll to it
openCurrentPageSubmenuAndScroll();
});
document.getElementById('menu-toggle').addEventListener('click', function() {
var navMenu = document.getElementById('navMenu');
var bodyContent = document.getElementById('bodyContent');
if (navMenu.style.display === 'none' || navMenu.style.display === '') {
navMenu.style.display = 'block';
bodyContent.style.display = 'none'; // Hide body content when nav menu is displayed
} else {
navMenu.style.display = 'none';
bodyContent.style.display = 'block'; // Show body content when nav menu is hidden
}
});
$(document).ready(function() {
$('.video__navigation .navigation-item').click(function() {
var videoID = $(this).data('video');
var startTime = $(this).data('start');
var newSrc = 'https://www.youtube.com/embed/' + videoID + '?start=' + startTime + '&autoplay=1';
$('.video__wrapper iframe').attr('src', newSrc);
});
});
$(document).ready(function() {
$('.bs-extendedsearch-filter-button-button').each(function() {
$(this).append('<span class="fa fa-chevron-down"></span>');
});
});
document.addEventListener("scroll", function() {
var sidebar = document.getElementById("navMenu");
var footerHeight = 100;
var windowHeight = window.innerHeight;
var scrollBottomPosition = window.scrollY + windowHeight;
var footerTopPosition = document.documentElement.offsetHeight - footerHeight;
if (scrollBottomPosition <= footerTopPosition) {
sidebar.style.height = "100vh";
} else {
sidebar.style.height = "calc(100vh - 110px)";
}
});
mw.loader.using('jquery', function() {
$(document).ready(function() {
var $toc = $('#toc').clone();
$('#toc').remove();
$('#tocContainer').html($toc);
$('#tocContainer').css({
position: '-webkit-sticky',
position: 'sticky',
top: '0',
padding: '15px',
margin: '0 auto',
borderRadius: '5px',
maxWidth: '280px',
maxHeight: 'max-content',
overflowY: 'auto',
height: '90vh',
zIndex: 1000
});
$('#tocContainer .toctitle').css({
fontSize: '16px',
fontWeight: '600',
color: '#555',
borderBottom: '1px solid #ccc',
paddingBottom: '10px',
marginBottom: '10px'
});
$('#tocContainer ul').css({
margin: 0,
padding: '0 0 0 20px',
listStyleType: 'none',
fontSize: '14px',
lineHeight: '1.6'
});
$('#tocContainer li').css({
marginBottom: '5px',
});
$('#tocContainer a').css({
color: '#555',
textDecoration: 'none',
}).hover(
function() { $(this).css({textDecoration: 'underline', color: '#000'}); },
function() { $(this).css({textDecoration: 'none', color: '#555'}); }
);
});
});
$(document).ready(function() {
var $inputElement = $('.oo-ui-textInputWidget-type-search .oo-ui-inputWidget-input');
if ($inputElement.length) {
$inputElement.on('keydown', function(event) {
if (event.key === 'Enter') {
event.preventDefault();
$inputElement.addClass('search-input');
}
});
}
});
$(document).ready(function() {
var $inputElement = $('.oo-ui-textInputWidget-type-search .oo-ui-inputWidget-input');
if ($inputElement.length) {
$inputElement.addClass('search-input');
console.log('Class "search-input" added to the input element.');
} else {
console.log('Input element not found.');
}
});
$(document).ready(function() {
var signInLink = $('#user-info a');
var currentUrl = encodeURIComponent(window.location.pathname + window.location.search + window.location.hash);
signInLink.attr('href', signInLink.attr('href').replace('<CURRENT_URL>', currentUrl));
});
document.addEventListener('DOMContentLoaded', function() {
var images = document.querySelectorAll('.thumbimage');
var overlay = document.createElement('div');
overlay.className = 'image-overlay';
document.body.appendChild(overlay);
var overlayImage = document.createElement('img');
overlay.appendChild(overlayImage);
images.forEach(function(image) {
image.addEventListener('click', function(event) {
event.preventDefault();
event.stopPropagation();
overlayImage.src = image.src;
overlay.classList.add('show');
});
});
overlay.addEventListener('click', function() {
overlay.classList.remove('show');
});
});
// ==UserScript==
// @name MediaWiki Clean Delete
// @namespace MediaWikiScripts
// @description Adds a 'Clean Delete' action link to pages for admins to delete pages and clean up incoming links and redirects.
// ==/UserScript==
mw.loader.using(['mediawiki.api', 'mediawiki.util', 'jquery'], function () {
function addCleanDeleteLink() {
if (mw.config.get('wgUserGroups').indexOf('sysop') !== -1) {
if ($('#ca-cleandelete').length === 0) {
var $link = $('<div>').attr('id', 'ca-cleandelete').attr('class', 'mw-list-item').append(
$('<a>').attr('href', '#').attr('class', 'ca-cleandelete').text('Clean Delete').click(function (e) {
e.preventDefault();
gatherAllDecisions(mw.config.get('wgPageName'));
})
);
$('#p-actions .tab-group').append($link);
}
}
}
function gatherAllDecisions(pageTitle) {
var decisions = {};
showModal('Handle Links and Redirects', '<div class="form-group">' +
'<label>Specify how you would like to handle all incoming links and redirects:</label>' +
'<select id="link-handling-select" class="form-control">' +
'<option value="delete">Delete Links and Redirects</option>' +
'<option value="change">Change Target of Links and Redirects</option>' +
'</select>' +
'</div>', function () {
var choice = $('#link-handling-select').val();
if (choice === 'change') {
showModal('Specify New Target', '<div class="form-group">' +
'<label>Enter the new target page name to update all links and redirects:</label>' +
'<input type="text" id="new-target-input" class="form-control" placeholder="Enter new target">' +
'</div>', function () {
decisions.links = $('#new-target-input').val();
confirmDeletion(pageTitle, decisions);
});
} else {
decisions.links = '';
confirmDeletion(pageTitle, decisions);
}
});
}
function confirmDeletion(pageTitle, decisions) {
showModal('Confirm Page Deletion', '<p>Are you sure you want to delete "' + pageTitle + '" after handling all links and redirects?</p>', function () {
decisions.deletion = true;
showLoadingDialog('Performing Cleanup', function (loadingDialog, updateLoadingText, logDetail) {
executeAllActions(pageTitle, decisions, function () {
loadingDialog.close().closed.then(function() {
location.reload();
});
}, updateLoadingText, logDetail);
});
});
}
function showModal(title, body, onConfirm) {
var modal = $(
'<div class="modal fade" tabindex="-1" role="dialog">' +
'<div class="modal-dialog" role="document">' +
'<div class="modal-content">' +
'<div class="modal-header">' +
'<h5 class="modal-title">' + title + '</h5>' +
'<button type="button" class="close" data-dismiss="modal" aria-label="Close">' +
'<span aria-hidden="true">×</span>' +
'</button>' +
'</div>' +
'<div class="modal-body">' + body + '</div>' +
'<div class="modal-footer">' +
'<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>' +
'<button type="button" class="btn btn-primary">Confirm</button>' +
'</div>' +
'</div>' +
'</div>' +
'</div>'
);
modal.find('.btn-primary').click(function () {
onConfirm();
modal.modal('hide');
});
modal.on('hidden.bs.modal', function () {
modal.remove();
});
$('body').append(modal);
modal.modal('show');
}
function showLoadingDialog(message, callback) {
var modal = $(
'<div class="modal fade" tabindex="-1" role="dialog">' +
'<div class="modal-dialog" role="document">' +
'<div class="modal-content">' +
'<div class="modal-header">' +
'<h5 class="modal-title">Performing Cleanup</h5>' +
'</div>' +
'<div class="modal-body">' +
'<p id="loading-text">' + message + '</p>' +
'<ul id="loading-log"></ul>' +
'</div>' +
'</div>' +
'</div>' +
'</div>'
);
$('body').append(modal);
modal.modal('show');
callback(modal, function (text) {
$('#loading-text').text(text);
$('#loading-log').append('<li>' + text + '</li>');
}, function (detail) {
$('#loading-log').append('<li>' + detail + '</li>');
});
}
function executeAllActions(pageTitle, decisions, callback, updateLoadingText, logDetail) {
var api = new mw.Api();
function handleLinksAndRedirects(action, newTarget, next) {
updateLoadingText('Fetching backlinks...');
api.get({
action: 'query',
list: 'backlinks',
bltitle: pageTitle,
bllimit: 'max',
blfilterredir: 'all' // Include both redirects and non-redirects
}).done(function (data) {
logDetail('Backlinks fetched.');
if (data.query.backlinks) {
var promises = $.map(data.query.backlinks, function (link) {
return new $.Deferred(function (defer) {
api.get({
action: 'parse',
page: link.title,
prop: 'wikitext'
}).done(function (linkData) {
var isRedirect = linkData.parse.wikitext['*'].trim().startsWith('#REDIRECT');
if (isRedirect) {
if (action === 'update') {
updateRedirectTarget(link.title, newTarget, api, defer.resolve, logDetail);
} else {
logDetail('Backlink ' + link.title + ' is a redirect. Deleting...');
performDeletion(link.title, defer.resolve, logDetail);
}
} else {
if (action === 'update') {
updateLinkInPage(link.title, pageTitle, newTarget, api, defer.resolve, logDetail);
} else {
removeLinkFromPage(link.title, pageTitle, api, defer.resolve, logDetail);
}
}
}).fail(function (error) {
logDetail('Error checking if backlink ' + link.title + ' is a redirect: ' + error);
defer.resolve();
});
}).promise();
});
$.when.apply($, promises).then(function () {
updateLoadingText(action === 'update' ? 'All links updated.' : 'All links removed.');
next();
});
} else {
next();
}
}).fail(function (error) {
updateLoadingText('Error fetching backlinks: ' + error);
next();
});
}
function updateLinkInPage(linkedPageTitle, originalPageTitle, newTarget, api, resolve, logDetail) {
api.get({
action: 'parse',
page: linkedPageTitle,
prop: 'wikitext'
}).then(function (data) {
var wikitext = data.parse.wikitext['*'];
var regex = new RegExp('\\[\\[' + originalPageTitle.replace(/[\[\]]/g, '\\$&') + '(\\|[^\\]]+)?\\]\\]', 'g');
var newWikitext = wikitext.replace(regex, '[[' + newTarget + '$1]]');
if (wikitext !== newWikitext) {
logDetail('Updating link in ' + linkedPageTitle);
} else {
logDetail('No link found in ' + linkedPageTitle);
}
return api.postWithToken('csrf', {
action: 'edit',
title: linkedPageTitle,
text: newWikitext,
summary: 'Updated link to [[' + newTarget + ']]'
}).then(function (response) {
console.log('API response from updating link: ', response);
if (response.edit && response.edit.result === 'Success' && !response.edit.nochange) {
logDetail('Successfully updated link in ' + linkedPageTitle);
} else {
logDetail('No changes made to link in ' + linkedPageTitle);
}
resolve();
}).fail(function (error) {
logDetail('Error updating link in ' + linkedPageTitle + ': ' + error);
resolve();
});
}).fail(function (error) {
logDetail('Error fetching page content for ' + linkedPageTitle + ': ' + error);
resolve();
});
}
function updateRedirectTarget(redirectPageTitle, newTarget, api, resolve, logDetail) {
logDetail('Updating redirect target in ' + redirectPageTitle);
return api.postWithToken('csrf', {
action: 'edit',
title: redirectPageTitle,
text: '#REDIRECT [[' + newTarget + ']]',
summary: 'Updated redirect to [[' + newTarget + ']]'
}).then(function (response) {
console.log('API response from updating redirect: ', response);
if (response.edit && response.edit.result === 'Success' && !response.edit.nochange) {
logDetail('Successfully updated redirect in ' + redirectPageTitle);
} else {
logDetail('No changes made to redirect in ' + redirectPageTitle);
}
resolve();
}).fail(function (error) {
logDetail('Error updating redirect in ' + redirectPageTitle + ': ' + error);
resolve();
});
}
function removeLinkFromPage(linkedPageTitle, originalPageTitle, api, resolve, logDetail) {
api.get({
action: 'parse',
page: linkedPageTitle,
prop: 'wikitext'
}).then(function (data) {
var wikitext = data.parse.wikitext['*'];
var regex = new RegExp('\\[\\[' + originalPageTitle.replace(/[\[\]]/g, '\\$&') + '(\\|[^\\]]+)?\\]\\]', 'g');
var newWikitext = wikitext.replace(regex, function(match, p1) {
return p1 ? p1.substring(1) : originalPageTitle;
});
if (wikitext !== newWikitext) {
logDetail('Removing link from ' + linkedPageTitle);
} else {
logDetail('No link found in ' + linkedPageTitle);
}
return api.postWithToken('csrf', {
action: 'edit',
title: linkedPageTitle,
text: newWikitext,
summary: 'Removed link to [[' + originalPageTitle + ']]'
}).then(function (response) {
console.log('API response from removing link: ', response);
if (response.edit && response.edit.result === 'Success' && !response.edit.nochange) {
logDetail('Successfully removed link from ' + linkedPageTitle);
} else {
logDetail('No changes made to link in ' + linkedPageTitle);
}
resolve();
}).fail(function (error) {
logDetail('Error removing link from ' + linkedPageTitle + ': ' + error);
resolve();
});
}).fail(function (error) {
logDetail('Error fetching page content for ' + linkedPageTitle + ': ' + error);
resolve();
});
}
function handleRedirects(next) {
updateLoadingText('Fetching redirects...');
api.get({
action: 'query',
titles: pageTitle,
redirects: true
}).done(function (data) {
logDetail('Redirects fetched.');
var redirects = data.query.pages[Object.keys(data.query.pages)[0]].redirects;
if (redirects) {
var promises = $.map(redirects, function (redirect) {
return new $.Deferred(function (defer) {
logDetail('Found redirect: ' + redirect.title);
performDeletion(redirect.title, defer.resolve, logDetail);
}).promise();
});
$.when.apply($, promises).then(function () {
next();
});
} else {
next();
}
}).fail(function (error) {
updateLoadingText('Error fetching redirects: ' + error);
next();
});
}
function performDeletion(pageTitle, resolve, logDetail) {
updateLoadingText('Deleting the page: ' + pageTitle);
api.postWithToken('csrf', {
action: 'delete',
title: pageTitle,
reason: 'Automated clean delete by admin'
}).done(function (response) {
console.log('API response from deleting page: ', response);
if (response.delete && response.delete.title) {
logDetail('Successfully deleted page: ' + response.delete.title);
} else {
logDetail('No deletion performed for ' + pageTitle);
}
resolve();
}).fail(function (error) {
logDetail('Error during clean deletion of ' + pageTitle + ': ' + error);
resolve();
});
}
var tasks = [
function (resolve) {
if (decisions.links === '') {
handleLinksAndRedirects('remove', '', resolve);
} else {
handleLinksAndRedirects('update', decisions.links, resolve);
}
},
function (resolve) {
if (decisions.deletion) {
handleRedirects(resolve);
} else {
resolve();
}
},
function (resolve) {
if (decisions.deletion) {
performDeletion(pageTitle, resolve, logDetail);
} else {
resolve();
}
}
];
(function executeTasks(i) {
if (i < tasks.length) {
tasks[i](function () {
executeTasks(i + 1);
});
} else {
callback();
}
})(0);
}
mw.hook('wikipage.content').add(addCleanDeleteLink);
});
function isLoggedOut() {
return mw.config.get('wgUserName') === null;
}
jQuery(document).ready(function ($) {
if (isLoggedOut()) {
$('body').append('<div class="darken-overlay"></div>');
$('img').each(function () {
var imgSrc = $(this).attr('src');
if (imgSrc !== '/images/MDrivenLogo.png') {
$(this).addClass('enlargeable');
}
});
$('img.enlargeable').click(function (event) {
event.preventDefault();
event.stopPropagation();
if ($(this).hasClass('enlarged')) {
$(this).removeClass('enlarged');
$('.darken-overlay').hide();
} else {
$('img.enlargeable').removeClass('enlarged');
$(this).addClass('enlarged');
$('.darken-overlay').show();
var fullSizeSrc = $(this).attr('src').replace('/thumb', '').replace(/\/\d+px-.+$/, '');
$(this).attr('src', fullSizeSrc);
}
});
$('.darken-overlay').click(function () {
$('img.enlargeable').removeClass('enlarged');
$(this).hide();
});
}
});
This page was edited 27 days ago on 02/17/2025. What links here