MediaWiki:Citizen.js
MediaWiki interface page
More languages
More actions
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)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/**
* OHC Network Wiki — Citizen skin site JS (core mechanism, no Gadgets ext).
* Features: copy-code, search hotkey, back-to-top.
* Guarded with window flags so the matching ohc-* gadgets (if enabled later
* via MediaWiki:Gadgets-definition) no-op instead of double-applying.
*
* Fonts are NOT loaded here any more. They are declared as @font-face in
* MediaWiki:Common.css (self-hosted variable Figtree / Geist Mono), so the
* browser discovers them while parsing CSS instead of after a script round
* trip — the old mw.loader.load() approach guaranteed a flash of fallback
* text, and in practice the webfonts were often not applied at all.
*/
( function () {
'use strict';
/* 1. Copy-code -------------------------------------------- */
function copyText( text, btn ) {
var reset = function () {
btn.textContent = 'Copy';
btn.classList.remove( 'ohc-copied' );
};
var done = function () {
btn.textContent = 'Copied';
btn.classList.add( 'ohc-copied' );
setTimeout( reset, 1600 );
};
var fail = function () {
btn.textContent = 'Failed';
setTimeout( reset, 1600 );
};
function fallbackCopy() {
var ta = document.createElement( 'textarea' );
ta.value = text;
ta.style.cssText = 'position:fixed;left:-9999px;top:0;';
document.body.appendChild( ta );
ta.select();
var ok = false;
try { ok = document.execCommand( 'copy' ); } catch ( e ) {}
document.body.removeChild( ta );
if ( ok ) { done(); } else { fail(); }
}
if ( navigator.clipboard && navigator.clipboard.writeText ) {
navigator.clipboard.writeText( text ).then( done, fallbackCopy );
} else {
fallbackCopy();
}
}
function addCopyButtons( container ) {
var pres = container.querySelectorAll( 'pre' );
// `let`, not `var`: with `var` the click handlers all closed over the
// final loop values, so every Copy button copied the last code block
// on the page.
for ( let i = 0; i < pres.length; i++ ) {
const pre = pres[ i ];
if ( pre.classList.contains( 'ohc-copy-code' ) ) {
continue;
}
const btn = document.createElement( 'button' );
btn.type = 'button';
btn.className = 'ohc-copy-btn';
btn.textContent = 'Copy';
btn.setAttribute( 'aria-label', 'Copy code to clipboard' );
btn.addEventListener( 'click', function () {
copyText( pre.textContent.replace( /\n$/, '' ), btn );
} );
pre.classList.add( 'ohc-copy-code' );
pre.appendChild( btn );
}
}
/* 2. Search hotkey ---------------------------------------- */
window.ohcSearchHotkeyLoaded = window.ohcSearchHotkeyLoaded || false;
function bindSearchHotkey() {
if ( window.ohcSearchHotkeyLoaded ) { return; }
window.ohcSearchHotkeyLoaded = true;
document.addEventListener( 'keydown', function ( e ) {
if ( e.key !== '/' && e.key !== '?' ) { return; }
var t = e.target;
if ( t && ( t.tagName === 'INPUT' || t.tagName === 'TEXTAREA' || t.isContentEditable ) ) {
return;
}
e.preventDefault();
var input =
document.querySelector( '#searchInput' ) ||
document.querySelector( '.citizen-search input[type="search"]' ) ||
document.querySelector( 'input[type="search"]' );
if ( input ) {
input.focus();
if ( input.select ) { input.select(); }
}
} );
}
/* 3. Back to top ------------------------------------------ */
window.ohcBackToTopLoaded = window.ohcBackToTopLoaded || false;
function initBackToTop() {
if ( window.ohcBackToTopLoaded || document.querySelector( '.ohc-to-top' ) ) { return; }
window.ohcBackToTopLoaded = true;
var btn = document.createElement( 'button' );
btn.type = 'button';
btn.className = 'ohc-to-top';
btn.setAttribute( 'aria-label', 'Back to top' );
btn.innerHTML = '↑';
btn.addEventListener( 'click', function () {
window.scrollTo( { top: 0, behavior: 'smooth' } );
} );
document.body.appendChild( btn );
var toggle = function () {
if ( window.scrollY > 600 ) {
btn.classList.add( 'ohc-to-top--show' );
} else {
btn.classList.remove( 'ohc-to-top--show' );
}
};
toggle();
window.addEventListener( 'scroll', toggle, { passive: true } );
}
addCopyButtons( document );
mw.hook( 'wikipage.content' ).add( addCopyButtons );
bindSearchHotkey();
initBackToTop();
}() );