MediaWiki:Common.js: Difference between revisions
From PickiPedia: A knowledge base of bluegrass, old time psychedelic jams, and other public domain music
Jump to navigationJump to search
No edit summary |
No edit summary |
||
| (One intermediate revision by the same user not shown) | |||
| Line 1: | Line 1: | ||
/** | /** | ||
* | * What used to be here now ships with the PickiPediaReleases extension. | ||
* | * | ||
* | * the HLS video player -> ext.pickipediaReleases.videoPlayer.js (#124) | ||
* Blue Railroad date picker -> ext.pickipediaReleases.blueRailroadDate.js (#131) | |||
* "X blocks ago" -> ext.pickipediaReleases.blocksAgo.js (#131) | |||
* Instrument form checks -> ext.pickipediaReleases.instrumentForm.js (#131) | |||
* | * | ||
* | * All four load on every page from the extension's BeforePageDisplay hook, | ||
* | * exactly as they did from here, and each does nothing unless the form or | ||
* element it cares about is on the page being shown. Changing any of them is | |||
* a pull request now: reviewed, syntax-checked by CI, deployed by Jenkins — | |||
* rather than several hundred lines pasted into this box, which is how the | |||
* whole of this file went down for 23 minutes on 15 September 2026. | |||
* | * | ||
* | * What remains below is the user-subpage zine styling. It stays because it is | ||
* with the | * bound to classes defined in MediaWiki:Common.css, and moving the script | ||
* without its stylesheet would split one feature across two homes. It goes | |||
* next, with the CSS, after which this page can be empty. | |||
* | * | ||
* | * See cryptograss/pickipedia#124 and #131. | ||
*/ | */ | ||
/* ============================================================ | /* ============================================================ | ||
| Line 490: | Line 47: | ||
var action = mw.config.get('wgAction') || 'view'; | var action = mw.config.get('wgAction') || 'view'; | ||
if (nsNumber | if (nsNumber !== 2) return; | ||
if (action | if (action !== 'view') return; | ||
if (title.indexOf('/') === -1) return; | if (title.indexOf('/') === -1) return; | ||
| Line 509: | Line 66: | ||
} | } | ||
var cats = mw.config.get('wgCategories') || []; | var cats = mw.config.get('wgCategories') || []; | ||
if (cats.indexOf('Masthead style') | if (cats.indexOf('Masthead style') !== -1) variant = 'masthead'; | ||
if (cats.indexOf('Letter style') | if (cats.indexOf('Letter style') !== -1) variant = 'letter'; | ||
body.classList.add('pickipedia-variant-' + variant); | body.classList.add('pickipedia-variant-' + variant); | ||
| Line 568: | Line 125: | ||
'<div class="pp-kicker">' + kickerHtml + '</div>' + | '<div class="pp-kicker">' + kickerHtml + '</div>' + | ||
'<div class="pp-topbar-rule"></div>' + | '<div class="pp-topbar-rule"></div>' + | ||
(lastMod | (lastMod ? '<div class="pp-topbar-vol">' + escapeHtml(lastMod) + '</div>' : '') + | ||
'</div>' + | '</div>' + | ||
'<div class="pp-titlewrap">' + | '<div class="pp-titlewrap">' + | ||
'<h1 class="pp-title">' + escapeHtml(subpage) + '</h1>' + | '<h1 class="pp-title">' + escapeHtml(subpage) + '</h1>' + | ||
(dek | (dek ? '<p class="pp-dek">' + dek + '</p>' : '') + | ||
'</div>'; | '</div>'; | ||
} else { | } else { | ||
| Line 579: | Line 136: | ||
'<h1 class="pp-title">' + escapeHtml(subpage) + '</h1>' + | '<h1 class="pp-title">' + escapeHtml(subpage) + '</h1>' + | ||
'<div class="pp-kicker">' + kickerHtml + '</div>' + | '<div class="pp-kicker">' + kickerHtml + '</div>' + | ||
(dek | (dek ? '<p class="pp-dek">' + dek + '</p>' : '') + | ||
(lastMod | (lastMod ? '<div class="pp-meta">Last edited ' + escapeHtml(lastMod) + '</div>' : ''); | ||
} | } | ||
content.parentNode.insertBefore(hero, content); | content.parentNode.insertBefore(hero, content); | ||
| Line 589: | Line 146: | ||
toggle.className = 'pickipedia-mode'; | toggle.className = 'pickipedia-mode'; | ||
toggle.type = 'button'; | toggle.type = 'button'; | ||
toggle.textContent = body.classList.contains('pickipedia-dark') | toggle.textContent = body.classList.contains('pickipedia-dark') ? '☼ Light' : '☾ Dark'; | ||
toggle.addEventListener('click', function () { | toggle.addEventListener('click', function () { | ||
var dark = body.classList.toggle('pickipedia-dark'); | var dark = body.classList.toggle('pickipedia-dark'); | ||
toggle.textContent = dark | toggle.textContent = dark ? '☼ Light' : '☾ Dark'; | ||
try { localStorage.setItem(STORAGE_KEY, dark | try { localStorage.setItem(STORAGE_KEY, dark ? 'dark' : 'light'); } catch (e) {} | ||
}); | }); | ||
document.body.appendChild(toggle); | document.body.appendChild(toggle); | ||
function escapeHtml(s) { | function escapeHtml(s) { | ||
return String(s == null | return String(s == null ? '' : s) | ||
.replace(/&/g, '& | .replace(/&/g, '&') | ||
.replace(/</g, '& | .replace(/</g, '<') | ||
.replace(/>/g, '& | .replace(/>/g, '>') | ||
.replace(/"/g, '& | .replace(/"/g, '"'); | ||
} | } | ||
}()); | }()); | ||
Latest revision as of 18:55, 9 October 2026
/**
* What used to be here now ships with the PickiPediaReleases extension.
*
* the HLS video player -> ext.pickipediaReleases.videoPlayer.js (#124)
* Blue Railroad date picker -> ext.pickipediaReleases.blueRailroadDate.js (#131)
* "X blocks ago" -> ext.pickipediaReleases.blocksAgo.js (#131)
* Instrument form checks -> ext.pickipediaReleases.instrumentForm.js (#131)
*
* All four load on every page from the extension's BeforePageDisplay hook,
* exactly as they did from here, and each does nothing unless the form or
* element it cares about is on the page being shown. Changing any of them is
* a pull request now: reviewed, syntax-checked by CI, deployed by Jenkins —
* rather than several hundred lines pasted into this box, which is how the
* whole of this file went down for 23 minutes on 15 September 2026.
*
* What remains below is the user-subpage zine styling. It stays because it is
* bound to classes defined in MediaWiki:Common.css, and moving the script
* without its stylesheet would split one feature across two homes. It goes
* next, with the CSS, after which this page can be empty.
*
* See cryptograss/pickipedia#124 and #131.
*/
/* ============================================================
* Pickipedia — User-subpage zine/Substack styling
*
* Layout:
* - corner logo (absolute-positioned upper-left of viewport,
* OUTSIDE all wiki wrappers — does not push content down)
* - non-sticky topbar (just nav) at top of body
* - hero block with title (top), then USER:Username kicker below,
* optional dek + meta
* - light/dark mode toggle (persisted in localStorage)
*
* Variant from HTML comment marker `pickipedia:variant=letter|masthead`
* or category membership; default letter.
* ============================================================ */
(function () {
'use strict';
if (typeof mw === 'undefined' || !mw.config) return;
var nsNumber = mw.config.get('wgNamespaceNumber');
var pageName = mw.config.get('wgPageName') || '';
var title = mw.config.get('wgTitle') || '';
var action = mw.config.get('wgAction') || 'view';
if (nsNumber !== 2) return;
if (action !== 'view') return;
if (title.indexOf('/') === -1) return;
var slash = title.indexOf('/');
var username = title.slice(0, slash).replace(/_/g, ' ');
var subpage = title.slice(slash + 1).replace(/_/g, ' ');
var body = document.body;
body.classList.add('pickipedia-userpost');
var variant = 'letter';
var content = document.querySelector('.mw-parser-output');
if (content) {
var html = content.innerHTML || '';
var m = html.match(/pickipedia:variant\s*=\s*(letter|masthead)/i);
if (m) variant = m[1].toLowerCase();
}
var cats = mw.config.get('wgCategories') || [];
if (cats.indexOf('Masthead style') !== -1) variant = 'masthead';
if (cats.indexOf('Letter style') !== -1) variant = 'letter';
body.classList.add('pickipedia-variant-' + variant);
var STORAGE_KEY = 'pickipedia-mode';
var saved = null;
try { saved = localStorage.getItem(STORAGE_KEY); } catch (e) {}
if (saved === 'dark') body.classList.add('pickipedia-dark');
var LOGO_URL = '/images/thumb/8/80/Pickipedia-quarter-transparent.png/400px-Pickipedia-quarter-transparent.png';
// ---------- Corner logo: stand-alone body child, absolute-positioned. ----------
var cornerLogo = document.createElement('a');
cornerLogo.className = 'pp-corner-logo';
cornerLogo.href = '/wiki/Main_Page';
cornerLogo.title = 'PickiPedia home';
cornerLogo.innerHTML = '<img src="' + LOGO_URL + '" alt="PickiPedia">';
document.body.insertBefore(cornerLogo, document.body.firstChild);
// ---------- Topbar (nav only) ----------
var topbar = document.createElement('header');
topbar.className = 'pickipedia-topbar';
topbar.innerHTML =
'<nav class="pickipedia-topbar-nav">' +
'<a href="' + mw.util.getUrl(pageName, { action: 'edit' }) + '">edit</a>' +
'<a href="' + mw.util.getUrl(pageName, { action: 'history' }) + '">history</a>' +
'<a href="' + mw.util.getUrl('Talk:' + pageName) + '">talk</a>' +
'</nav>';
document.body.insertBefore(topbar, cornerLogo.nextSibling);
// ---------- Hero ----------
if (content) {
var dek = '';
var dekEl = content.querySelector('.pp-dek-source');
if (dekEl) {
dek = dekEl.innerHTML;
dekEl.remove();
}
var kickerHtml = '<a href="' + mw.util.getUrl('User:' + username.replace(/ /g, '_')) +
'">User:' + escapeHtml(username) + '</a>';
var kickerEl = content.querySelector('.pp-kicker-source');
if (kickerEl) {
kickerHtml = escapeHtml(kickerEl.textContent.trim());
kickerEl.remove();
}
var lastMod = '';
var lastModEl = document.getElementById('footer-info-lastmod');
if (lastModEl) lastMod = lastModEl.textContent.replace(/^\s*This page was last (edited|modified) on\s*/i, '').trim();
var hero = document.createElement('header');
hero.className = 'pickipedia-hero';
if (variant === 'masthead') {
hero.innerHTML =
'<div class="pp-topbar">' +
'<div class="pp-kicker">' + kickerHtml + '</div>' +
'<div class="pp-topbar-rule"></div>' +
(lastMod ? '<div class="pp-topbar-vol">' + escapeHtml(lastMod) + '</div>' : '') +
'</div>' +
'<div class="pp-titlewrap">' +
'<h1 class="pp-title">' + escapeHtml(subpage) + '</h1>' +
(dek ? '<p class="pp-dek">' + dek + '</p>' : '') +
'</div>';
} else {
// Letter variant: title first, then kicker, then optional dek/meta.
hero.innerHTML =
'<h1 class="pp-title">' + escapeHtml(subpage) + '</h1>' +
'<div class="pp-kicker">' + kickerHtml + '</div>' +
(dek ? '<p class="pp-dek">' + dek + '</p>' : '') +
(lastMod ? '<div class="pp-meta">Last edited ' + escapeHtml(lastMod) + '</div>' : '');
}
content.parentNode.insertBefore(hero, content);
}
// ---------- Light/dark toggle ----------
var toggle = document.createElement('button');
toggle.className = 'pickipedia-mode';
toggle.type = 'button';
toggle.textContent = body.classList.contains('pickipedia-dark') ? '☼ Light' : '☾ Dark';
toggle.addEventListener('click', function () {
var dark = body.classList.toggle('pickipedia-dark');
toggle.textContent = dark ? '☼ Light' : '☾ Dark';
try { localStorage.setItem(STORAGE_KEY, dark ? 'dark' : 'light'); } catch (e) {}
});
document.body.appendChild(toggle);
function escapeHtml(s) {
return String(s == null ? '' : s)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"');
}
}());