MediaWiki:Common.js
From Hidden Mickey Wiki
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
- Opera: Press Ctrl-F5.
/* Any JavaScript here will be loaded for all users on every page load. */
// JavaScript code to save checkbox state and restore it when the page loads
$(document).ready(function() {
// Function to save the state of checkboxes to localStorage
function saveCheckboxState() {
$('input[type="checkbox"]').each(function() {
localStorage.setItem($(this).attr('id'), $(this).prop('checked'));
});
}
// Function to load the state of checkboxes from localStorage
function loadCheckboxState() {
$('input[type="checkbox"]').each(function() {
const savedState = localStorage.getItem($(this).attr('id'));
if (savedState !== null) {
$(this).prop('checked', savedState === 'true');
}
});
}
// Load the saved checkbox state when the page is loaded
loadCheckboxState();
// Save the checkbox state whenever a checkbox is changed
$('input[type="checkbox"]').change(function() {
saveCheckboxState();
});
});
// Adjust the search box width
$(document).ready(function () {
$('#searchInput').css('width', '600px'); // Adjust width as needed
});
// Add Edit Source to user dropdown
mw.loader.using('mediawiki.util', function () {
mw.util.addPortletLink( 'p-personal', mw.util.getUrl( mw.config.get('wgPageName'), { action: 'edit' } ), 'Edit Source', 'pt-editsource' );
mw.util.addPortletLink( 'p-personal', mw.util.getUrl( mw.config.get('wgPageName'), { action: 'history' } ), 'View History', 'pt-history' );
mw.util.addPortletLink( 'p-personal', mw.util.getUrl( mw.config.get('wgPageName'), { action: 'delete' } ), 'Delete', 'pt-delete' );
var moveLink = document.getElementById('ca-move');
if (moveLink) {
var a = moveLink.querySelector('a');
mw.util.addPortletLink( 'p-personal', a.href, a.textContent.trim(), 'pt-move', a.title || 'Move this page' );
moveLink.remove();
}
mw.util.addPortletLink( 'p-personal', mw.util.getUrl( mw.config.get('wgPageName'), { action: 'protect' } ), 'Protect', 'pt-protect' );
mw.util.addPortletLink( 'p-personal', mw.util.getUrl( mw.config.get('wgPageName'), { action: 'unwatch' } ), 'Unwatch', 'pt-unwatch' );
var talkLink = document.getElementById('pt-mytalk');
talkLink.remove();
var whatLinksHereLink = document.getElementById('t-whatlinkshere');
if (whatLinksHereLink) {
var a = whatLinksHereLink.querySelector('a');
mw.util.addPortletLink( 'p-personal', a.href, a.textContent.trim(), 'pt-whatlinkshere', a.title || 'What Links Here' );
whatLinksHereLink.remove();
}
var relatedChangesLink = document.getElementById('t-recentchangeslinked');
if (relatedChangesLink) {
var a = relatedChangesLink.querySelector('a');
mw.util.addPortletLink( 'p-personal', a.href, a.textContent.trim(), 'pt-recentchanges', a.title || 'Recent Changes' );
relatedChangesLink.remove();
}
var uploadLink = document.getElementById('t-upload');
if (uploadLink) {
var a = uploadLink.querySelector('a');
mw.util.addPortletLink( 'p-personal', a.href, a.textContent.trim(), 'pt-upload', a.title || 'Upload File' );
uploadLink.remove();
}
var specialPagesLink = document.getElementById('t-specialpages');
if (specialPagesLink) {
var a = specialPagesLink.querySelector('a');
mw.util.addPortletLink( 'p-personal', a.href, a.textContent.trim(), 'pt-specialpages', a.title || 'Special Pages' );
specialPagesLink.remove();
}
var permanentLink = document.getElementById('t-permalink');
if (permanentLink) {
var a = permanentLink.querySelector('a');
mw.util.addPortletLink( 'p-personal', a.href, a.textContent.trim(), 'pt-permalink', a.title || 'Permanent Link' );
permanentLink.remove();
}
var pageInfoLink = document.getElementById('t-info');
if (pageInfoLink) {
var a = pageInfoLink.querySelector('a');
mw.util.addPortletLink( 'p-personal', a.href, a.textContent.trim(), 'pt-info', a.title || 'Page Info' );
pageInfoLink.remove();
}
var printLink = document.getElementById('t-print');
if (printLink) {
var a = printLink.querySelector('a');
printLink.remove();
}
});
/* Test code to make checkboxes and timestamps work */
(function () {
'use strict';
// Debug flag (set false to silence logs)
window.mwTimestamp = window.mwTimestamp || {};
window.mwTimestamp.DEBUG = window.mwTimestamp.DEBUG !== undefined ? window.mwTimestamp.DEBUG : true;
function dbg() { if (!window.mwTimestamp.DEBUG) return; var args = Array.prototype.slice.call(arguments); console.log.apply(console, args); }
var PREFIX = 'mw-checkbox-ts:';
function formatTime(d) {
try {
return d.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', second: '2-digit' });
} catch (e) {
dbg('formatTime fallback to ISO', e);
return d.toISOString();
}
}
// Robust ensureTsBox: many fallbacks to work across different DOM shapes
function ensureTsBox(cb) {
if (!cb) return null;
// 1) If there's already one in the row / cell, use it
try {
var tr = cb.closest && cb.closest('tr');
if (tr) {
var existing = tr.querySelector && tr.querySelector('.mw-ts-box');
if (existing) return existing;
var lastCell = tr.querySelector('td:last-child, th:last-child') || tr.lastElementChild;
if (lastCell) {
var ts = lastCell.querySelector && lastCell.querySelector('.mw-ts-box');
if (ts) return ts;
ts = document.createElement('span');
ts.className = 'mw-ts-box';
lastCell.appendChild(ts);
return ts;
}
}
} catch (e) {
dbg('ensureTsBox: row/cell method failed', e);
}
// 2) Try next sibling cell (common fallback)
try {
var td = (cb.closest && cb.closest('td')) || cb.parentElement;
if (td && td.nextElementSibling) {
var next = td.nextElementSibling;
var ts2 = next.querySelector && next.querySelector('.mw-ts-box');
if (ts2) return ts2;
ts2 = document.createElement('span');
ts2.className = 'mw-ts-box';
next.appendChild(ts2);
return ts2;
}
} catch (e) {
dbg('ensureTsBox: sibling-cell method failed', e);
}
// 3) Fallback: insert immediately after checkbox (most robust)
try {
// Avoid duplicate creation if parent already has one
var parentExisting = cb.parentNode && cb.parentNode.querySelector && cb.parentNode.querySelector('.mw-ts-box');
if (parentExisting) return parentExisting;
var span = document.createElement('span');
span.className = 'mw-ts-box';
span.style.marginLeft = '0.4em';
if (cb.insertAdjacentElement) {
cb.insertAdjacentElement('afterend', span);
} else if (cb.parentNode) {
cb.parentNode.insertBefore(span, cb.nextSibling);
} else {
// give up gracefully
dbg('ensureTsBox: could not insert after checkbox (no parent)');
return null;
}
return span;
} catch (e) {
dbg('ensureTsBox: final insert failed', e);
return null;
}
}
function saveState(cb, tsBox) {
if (!cb || !cb.id) {
dbg('saveState: missing cb or id', cb && cb.id);
return;
}
var data = {
checked: !!cb.checked,
timestamp: tsBox ? tsBox.textContent : ''
};
try {
localStorage.setItem(PREFIX + cb.id, JSON.stringify(data));
dbg('saveState: saved', PREFIX + cb.id, data);
} catch (e) {
dbg('saveState localStorage error', e);
}
}
function restoreOne(id, data) {
var cb = document.getElementById(id);
if (!cb) return false;
try {
cb.checked = !!data.checked;
var tsBox = ensureTsBox(cb);
if (tsBox) {
tsBox.textContent = data.timestamp || '';
} else {
dbg('restoreOne: could not create tsBox for', id);
}
return true;
} catch (e) {
dbg('restoreOne error', e);
return false;
}
}
function restoreAllOnce() {
try {
var keys = Object.keys(localStorage);
keys.forEach(function (k) {
if (k.indexOf(PREFIX) !== 0) return;
var id = k.slice(PREFIX.length);
var json = localStorage.getItem(k);
if (!json) return;
try {
var data = JSON.parse(json);
restoreOne(id, data);
} catch (e) {
dbg('restoreAllOnce parse error for', k, e);
}
});
} catch (e) {
dbg('restoreAllOnce outer error', e);
}
}
function initRestore() {
dbg('initRestore start (userAgent:', navigator.userAgent, ')');
restoreAllOnce();
if (window.mw && mw.hook) {
try {
mw.hook('wikipage.content').add(function () {
restoreAllOnce();
});
} catch (e) {
dbg('mw.hook attach failed', e);
}
}
setTimeout(restoreAllOnce, 200);
setTimeout(restoreAllOnce, 1200);
if (window.MutationObserver) {
try {
var observer = new MutationObserver(function (mutations) {
var want = false;
for (var i = 0; i < mutations.length && !want; i++) {
var added = mutations[i].addedNodes;
for (var j = 0; j < added.length && !want; j++) {
var node = added[j];
if (node.nodeType !== 1) continue;
if (node.matches && node.matches('.mw-checkbox-ts')) want = true;
if (node.querySelector && (node.querySelector('.mw-checkbox-ts') || node.querySelector('.mw-ts-box'))) want = true;
}
}
if (want) {
restoreAllOnce();
}
});
observer.observe(document.body, { childList: true, subtree: true });
} catch (e) {
dbg('MutationObserver failed', e);
}
}
dbg('initRestore done');
}
// Helper: robustly find checkbox from click/change target
function getCheckboxFromEventTarget(target) {
if (!target) return null;
try {
if (target.matches && target.matches('input[type="checkbox"].mw-checkbox-ts')) return target;
// if label clicked, look up associated input
if (target.tagName === 'LABEL') {
var forId = target.getAttribute('for');
if (forId) {
var el = document.getElementById(forId);
if (el && el.matches && el.matches('input[type="checkbox"].mw-checkbox-ts')) return el;
}
var inner = target.querySelector && target.querySelector('input[type="checkbox"].mw-checkbox-ts');
if (inner) return inner;
}
// fallback: closest checkbox
var cb = target.closest && target.closest('input[type="checkbox"].mw-checkbox-ts');
if (cb) return cb;
} catch (e) {
dbg('getCheckboxFromEventTarget error', e);
}
return null;
}
// change handler — writes timestamp and saves state (defensive)
document.addEventListener('change', function (ev) {
try {
var cb = getCheckboxFromEventTarget(ev.target);
if (!cb) return;
dbg('change event on', cb.id, 'checked=', cb.checked);
var tsBox = ensureTsBox(cb);
var ts = cb.checked ? formatTime(new Date()) : '';
if (tsBox) {
tsBox.textContent = ts;
} else {
dbg('change: tsBox not available, trying to create fallback for', cb.id);
tsBox = ensureTsBox(cb);
if (tsBox) tsBox.textContent = ts;
}
saveState(cb, tsBox);
} catch (e) {
dbg('change handler error', e);
}
}, false);
// click handler: quick immediate UI update if 'change' is delayed/not firing in some environments
document.addEventListener('click', function (ev) {
try {
var cb = getCheckboxFromEventTarget(ev.target);
if (!cb) return;
// update the UI immediately for better feedback; save happens on 'change'
var tsBox = ensureTsBox(cb);
if (tsBox) tsBox.textContent = cb.checked ? formatTime(new Date()) : '';
} catch (e) {
dbg('click handler error', e);
}
}, false);
// Start
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initRestore);
} else {
initRestore();
}
// Helpers for debugging in console
window.mwTimestamp.restoreAll = restoreAllOnce;
window.mwTimestamp.listSaved = function () {
return Object.keys(localStorage).filter(function (k) { return k.indexOf(PREFIX) === 0; });
};
window.mwTimestamp.getSaved = function (id) {
var j = localStorage.getItem(PREFIX + id);
try { return j ? JSON.parse(j) : null; } catch (e) { dbg('getSaved parse error', e); return null; }
};
dbg('mwTimestamp loaded; debug ON');
})();