User:Magent/Common.js after 131

From PickiPedia: A knowledge base of bluegrass, old time psychedelic jams, and other public domain music
Jump to navigationJump to search

Common.js after 131

/**

* 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 =

'

' + '
' + kickerHtml + '
' + '
' + (lastMod ? '
' + escapeHtml(lastMod) + '
' : ) + '

' + '

' + '

' + escapeHtml(subpage) + '

' + (dek ? '

' + dek + '

' : ) + '

';

   } else {
     // Letter variant: title first, then kicker, then optional dek/meta.
     hero.innerHTML =

'

' + escapeHtml(subpage) + '

' + '

' + kickerHtml + '

' + (dek ? '

' + dek + '

' : ) + (lastMod ? '

Last edited ' + escapeHtml(lastMod) + '

' : );

   }
   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, '"');
   }

}());