MediaWiki:Common.js: Difference between revisions

From Mona Mahall / Asli Serbest
Jump to navigation Jump to search
Tag: Replaced
No edit summary
Line 1: Line 1:
/* Any JavaScript here will be loaded for all users on every page load. */
/* Any JavaScript here will be loaded for all users on every page load. */
/* =========================================================================
  aslimona.xyz — inline lightbox for gallery / thumbnail images
  Paste this ENTIRE file into: Special:MyLanguage/MediaWiki:Common.js
  (as an admin: go to https://aslimona.xyz/index.php/MediaWiki:Common.js
  click "Edit", paste, save.)
  Fixes the "click image -> File page -> back -> click next" problem:
  clicking any gallery or thumbnail image now opens a big in-page viewer
  with Prev/Next arrows and keyboard navigation, on every article,
  automatically. No per-page changes needed.
  ========================================================================= */
( function () {
'use strict';
function onReady( fn ) {
if ( document.readyState !== 'loading' ) {
fn();
} else {
document.addEventListener( 'DOMContentLoaded', fn );
}
}
// Convert a MediaWiki thumbnail URL to the full-resolution original URL.
// e.g. .../images/a/a1/Foo.jpg/800px-Foo.jpg          -> .../images/a/a1/Foo.jpg
//      .../images/thumb/a/a1/Foo.jpg/800px-Foo.jpg    -> .../images/a/a1/Foo.jpg
function originalFromThumb( src ) {
var m = src.match( /^(.*\/thumb\/([0-9a-f])\/([0-9a-f]{2})\/([^\/]+))\/\d+px-[^\/]+$/i );
if ( m ) {
return src.replace( '/thumb/', '/' ).replace( /\/\d+px-[^\/]+$/, '' );
}
var m2 = src.match( /^(.*\/[0-9a-f]\/[0-9a-f]{2}\/[^\/]+)\/\d+px-[^\/]+$/i );
if ( m2 ) {
return m2[ 1 ];
}
return src;
}
function injectStyles() {
var css = [
'.aslimona-lb-overlay{position:fixed;inset:0;background:rgba(6,6,7,0.94);',
'z-index:100000;display:flex;flex-direction:column;align-items:center;',
'justify-content:center;padding:4vh 4vw;box-sizing:border-box;}',
'.aslimona-lb-overlay[hidden]{display:none;}',
'.aslimona-lb-img{max-width:92vw;max-height:80vh;object-fit:contain;',
'border:1px solid #3a372f;background:#111;}',
'.aslimona-lb-caption{color:#a89f8c;font-family:"IBM Plex Mono","Courier New",monospace;',
'font-size:0.8rem;margin-top:14px;text-align:center;max-width:80vw;}',
'.aslimona-lb-counter{color:#6e6858;font-family:"IBM Plex Mono","Courier New",monospace;',
'font-size:0.7rem;margin-top:4px;letter-spacing:0.08em;}',
'.aslimona-lb-close,.aslimona-lb-prev,.aslimona-lb-next{position:fixed;',
'background:transparent;border:1px solid #3a372f;color:#e9e4d8;',
'font-family:Georgia,serif;cursor:pointer;transition:background .2s,color .2s;}',
'.aslimona-lb-close:hover,.aslimona-lb-prev:hover,.aslimona-lb-next:hover{',
'background:#c9a15a;color:#0c0c0d;}',
'.aslimona-lb-close{top:24px;right:24px;width:40px;height:40px;font-size:20px;',
'line-height:38px;text-align:center;}',
'.aslimona-lb-prev,.aslimona-lb-next{top:50%;transform:translateY(-50%);',
'width:48px;height:64px;font-size:22px;}',
'.aslimona-lb-prev{left:16px;}',
'.aslimona-lb-next{right:16px;}',
'@media (max-width:600px){',
'.aslimona-lb-prev,.aslimona-lb-next{width:36px;height:52px;font-size:18px;}',
'.aslimona-lb-close{width:34px;height:34px;font-size:17px;line-height:32px;}',
'}'
].join( '' );
var style = document.createElement( 'style' );
style.textContent = css;
document.head.appendChild( style );
}
function buildOverlay() {
var overlay = document.createElement( 'div' );
overlay.className = 'aslimona-lb-overlay';
overlay.hidden = true;
var img = document.createElement( 'img' );
img.className = 'aslimona-lb-img';
overlay.appendChild( img );
var caption = document.createElement( 'div' );
caption.className = 'aslimona-lb-caption';
overlay.appendChild( caption );
var counter = document.createElement( 'div' );
counter.className = 'aslimona-lb-counter';
overlay.appendChild( counter );
var closeBtn = document.createElement( 'button' );
closeBtn.className = 'aslimona-lb-close';
closeBtn.setAttribute( 'aria-label', 'Close' );
closeBtn.textContent = '×';
overlay.appendChild( closeBtn );
var prevBtn = document.createElement( 'button' );
prevBtn.className = 'aslimona-lb-prev';
prevBtn.setAttribute( 'aria-label', 'Previous image' );
prevBtn.textContent = '‹';
overlay.appendChild( prevBtn );
var nextBtn = document.createElement( 'button' );
nextBtn.className = 'aslimona-lb-next';
nextBtn.setAttribute( 'aria-label', 'Next image' );
nextBtn.textContent = '›';
overlay.appendChild( nextBtn );
document.body.appendChild( overlay );
return {
overlay: overlay,
img: img,
caption: caption,
counter: counter,
closeBtn: closeBtn,
prevBtn: prevBtn,
nextBtn: nextBtn
};
}
onReady( function () {
var content = document.querySelector( '.mw-parser-output' );
if ( !content ) {
return;
}
// Collect every lightbox-able image link on the page, in document order:
// - <gallery> thumbnails: li.gallerybox a.image
// - inline [[File:x|thumb]]: div.thumb a.image
var links = Array.prototype.slice.call(
content.querySelectorAll( 'li.gallerybox a.image, div.thumb a.image, a.image' )
);
if ( !links.length ) {
return;
}
// de-duplicate while preserving order
var seen = {};
links = links.filter( function ( a ) {
if ( seen[ a.href ] ) {
return false;
}
seen[ a.href ] = true;
return true;
} );
var items = links.map( function ( a ) {
var thumbImg = a.querySelector( 'img' );
var full = thumbImg ? originalFromThumb( thumbImg.src ) : a.href;
var captionEl = null;
var gallerytext = a.closest( 'li.gallerybox' );
if ( gallerytext ) {
captionEl = gallerytext.querySelector( '.gallerytext' );
} else {
var thumbinner = a.closest( '.thumbinner' );
if ( thumbinner ) {
captionEl = thumbinner.querySelector( '.thumbcaption' );
}
}
return {
full: full,
caption: captionEl ? captionEl.textContent.trim() : ( thumbImg ? thumbImg.alt : '' ),
link: a
};
} );
injectStyles();
var ui = buildOverlay();
var currentIndex = 0;
function show( index ) {
currentIndex = ( index + items.length ) % items.length;
var item = items[ currentIndex ];
ui.img.src = item.full;
ui.caption.textContent = item.caption || '';
ui.counter.textContent = ( currentIndex + 1 ) + ' / ' + items.length;
}
function open( index ) {
show( index );
ui.overlay.hidden = false;
document.body.style.overflow = 'hidden';
}
function close() {
ui.overlay.hidden = true;
document.body.style.overflow = '';
}
items.forEach( function ( item, index ) {
item.link.addEventListener( 'click', function ( ev ) {
// let ctrl/cmd/shift/middle-clicks behave normally (open in new tab etc.)
if ( ev.ctrlKey || ev.metaKey || ev.shiftKey || ev.button === 1 ) {
return;
}
ev.preventDefault();
open( index );
} );
} );
ui.closeBtn.addEventListener( 'click', close );
ui.prevBtn.addEventListener( 'click', function () {
show( currentIndex - 1 );
} );
ui.nextBtn.addEventListener( 'click', function () {
show( currentIndex + 1 );
} );
ui.overlay.addEventListener( 'click', function ( ev ) {
if ( ev.target === ui.overlay ) {
close();
}
} );
document.addEventListener( 'keydown', function ( ev ) {
if ( ui.overlay.hidden ) {
return;
}
if ( ev.key === 'Escape' ) {
close();
} else if ( ev.key === 'ArrowLeft' ) {
show( currentIndex - 1 );
} else if ( ev.key === 'ArrowRight' ) {
show( currentIndex + 1 );
}
} );
} );
}() );
/* =========================================================================
  CRAZY VERSION — per-page color scheme picker.
  Works together with the CRAZY VERSION block in MediaWiki:Common.css.
  Reads the current page name and picks ONE of 10 schemes
  (.crazy-scheme-0 … .crazy-scheme-9). Deterministic: the same page
  ALWAYS gets the same look, but different pages (Digital Twin, Homes of
  the Internet, Köçek Pisti …) look completely different from each other.
  To turn the crazy version off: delete this block AND the CRAZY VERSION
  block in MediaWiki:Common.css. The lightbox code above is unaffected.
  ========================================================================= */
( function () {
'use strict';
var SCHEMES = 10;
function pageName() {
if ( window.mw && mw.config && mw.config.get ) {
var n = mw.config.get( 'wgPageName' );
if ( n ) {
return n;
}
}
return document.title || 'Main_Page';
}
function apply() {
var name = pageName();
var h = 0;
for ( var i = 0; i < name.length; i++ ) {
h = ( h * 31 + name.charCodeAt( i ) ) >>> 0;
}
var scheme = h % SCHEMES;
if ( document.body ) {
document.body.classList.add( 'crazy-scheme-' + scheme );
}
}
if ( document.readyState !== 'loading' ) {
apply();
} else {
document.addEventListener( 'DOMContentLoaded', apply );
}
}() );

Revision as of 11:33, 20 July 2026

/* Any JavaScript here will be loaded for all users on every page load. */
/* =========================================================================
   aslimona.xyz — inline lightbox for gallery / thumbnail images
   Paste this ENTIRE file into: Special:MyLanguage/MediaWiki:Common.js
   (as an admin: go to https://aslimona.xyz/index.php/MediaWiki:Common.js
   click "Edit", paste, save.)

   Fixes the "click image -> File page -> back -> click next" problem:
   clicking any gallery or thumbnail image now opens a big in-page viewer
   with Prev/Next arrows and keyboard navigation, on every article,
   automatically. No per-page changes needed.
   ========================================================================= */
( function () {
	'use strict';

	function onReady( fn ) {
		if ( document.readyState !== 'loading' ) {
			fn();
		} else {
			document.addEventListener( 'DOMContentLoaded', fn );
		}
	}

	// Convert a MediaWiki thumbnail URL to the full-resolution original URL.
	// e.g. .../images/a/a1/Foo.jpg/800px-Foo.jpg           -> .../images/a/a1/Foo.jpg
	//      .../images/thumb/a/a1/Foo.jpg/800px-Foo.jpg     -> .../images/a/a1/Foo.jpg
	function originalFromThumb( src ) {
		var m = src.match( /^(.*\/thumb\/([0-9a-f])\/([0-9a-f]{2})\/([^\/]+))\/\d+px-[^\/]+$/i );
		if ( m ) {
			return src.replace( '/thumb/', '/' ).replace( /\/\d+px-[^\/]+$/, '' );
		}
		var m2 = src.match( /^(.*\/[0-9a-f]\/[0-9a-f]{2}\/[^\/]+)\/\d+px-[^\/]+$/i );
		if ( m2 ) {
			return m2[ 1 ];
		}
		return src;
	}

	function injectStyles() {
		var css = [
			'.aslimona-lb-overlay{position:fixed;inset:0;background:rgba(6,6,7,0.94);',
			'z-index:100000;display:flex;flex-direction:column;align-items:center;',
			'justify-content:center;padding:4vh 4vw;box-sizing:border-box;}',
			'.aslimona-lb-overlay[hidden]{display:none;}',
			'.aslimona-lb-img{max-width:92vw;max-height:80vh;object-fit:contain;',
			'border:1px solid #3a372f;background:#111;}',
			'.aslimona-lb-caption{color:#a89f8c;font-family:"IBM Plex Mono","Courier New",monospace;',
			'font-size:0.8rem;margin-top:14px;text-align:center;max-width:80vw;}',
			'.aslimona-lb-counter{color:#6e6858;font-family:"IBM Plex Mono","Courier New",monospace;',
			'font-size:0.7rem;margin-top:4px;letter-spacing:0.08em;}',
			'.aslimona-lb-close,.aslimona-lb-prev,.aslimona-lb-next{position:fixed;',
			'background:transparent;border:1px solid #3a372f;color:#e9e4d8;',
			'font-family:Georgia,serif;cursor:pointer;transition:background .2s,color .2s;}',
			'.aslimona-lb-close:hover,.aslimona-lb-prev:hover,.aslimona-lb-next:hover{',
			'background:#c9a15a;color:#0c0c0d;}',
			'.aslimona-lb-close{top:24px;right:24px;width:40px;height:40px;font-size:20px;',
			'line-height:38px;text-align:center;}',
			'.aslimona-lb-prev,.aslimona-lb-next{top:50%;transform:translateY(-50%);',
			'width:48px;height:64px;font-size:22px;}',
			'.aslimona-lb-prev{left:16px;}',
			'.aslimona-lb-next{right:16px;}',
			'@media (max-width:600px){',
			'.aslimona-lb-prev,.aslimona-lb-next{width:36px;height:52px;font-size:18px;}',
			'.aslimona-lb-close{width:34px;height:34px;font-size:17px;line-height:32px;}',
			'}'
		].join( '' );
		var style = document.createElement( 'style' );
		style.textContent = css;
		document.head.appendChild( style );
	}

	function buildOverlay() {
		var overlay = document.createElement( 'div' );
		overlay.className = 'aslimona-lb-overlay';
		overlay.hidden = true;

		var img = document.createElement( 'img' );
		img.className = 'aslimona-lb-img';
		overlay.appendChild( img );

		var caption = document.createElement( 'div' );
		caption.className = 'aslimona-lb-caption';
		overlay.appendChild( caption );

		var counter = document.createElement( 'div' );
		counter.className = 'aslimona-lb-counter';
		overlay.appendChild( counter );

		var closeBtn = document.createElement( 'button' );
		closeBtn.className = 'aslimona-lb-close';
		closeBtn.setAttribute( 'aria-label', 'Close' );
		closeBtn.textContent = '×';
		overlay.appendChild( closeBtn );

		var prevBtn = document.createElement( 'button' );
		prevBtn.className = 'aslimona-lb-prev';
		prevBtn.setAttribute( 'aria-label', 'Previous image' );
		prevBtn.textContent = '‹';
		overlay.appendChild( prevBtn );

		var nextBtn = document.createElement( 'button' );
		nextBtn.className = 'aslimona-lb-next';
		nextBtn.setAttribute( 'aria-label', 'Next image' );
		nextBtn.textContent = '›';
		overlay.appendChild( nextBtn );

		document.body.appendChild( overlay );

		return {
			overlay: overlay,
			img: img,
			caption: caption,
			counter: counter,
			closeBtn: closeBtn,
			prevBtn: prevBtn,
			nextBtn: nextBtn
		};
	}

	onReady( function () {
		var content = document.querySelector( '.mw-parser-output' );
		if ( !content ) {
			return;
		}

		// Collect every lightbox-able image link on the page, in document order:
		// - <gallery> thumbnails: li.gallerybox a.image
		// - inline [[File:x|thumb]]: div.thumb a.image
		var links = Array.prototype.slice.call(
			content.querySelectorAll( 'li.gallerybox a.image, div.thumb a.image, a.image' )
		);
		if ( !links.length ) {
			return;
		}
		// de-duplicate while preserving order
		var seen = {};
		links = links.filter( function ( a ) {
			if ( seen[ a.href ] ) {
				return false;
			}
			seen[ a.href ] = true;
			return true;
		} );

		var items = links.map( function ( a ) {
			var thumbImg = a.querySelector( 'img' );
			var full = thumbImg ? originalFromThumb( thumbImg.src ) : a.href;
			var captionEl = null;
			var gallerytext = a.closest( 'li.gallerybox' );
			if ( gallerytext ) {
				captionEl = gallerytext.querySelector( '.gallerytext' );
			} else {
				var thumbinner = a.closest( '.thumbinner' );
				if ( thumbinner ) {
					captionEl = thumbinner.querySelector( '.thumbcaption' );
				}
			}
			return {
				full: full,
				caption: captionEl ? captionEl.textContent.trim() : ( thumbImg ? thumbImg.alt : '' ),
				link: a
			};
		} );

		injectStyles();
		var ui = buildOverlay();
		var currentIndex = 0;

		function show( index ) {
			currentIndex = ( index + items.length ) % items.length;
			var item = items[ currentIndex ];
			ui.img.src = item.full;
			ui.caption.textContent = item.caption || '';
			ui.counter.textContent = ( currentIndex + 1 ) + ' / ' + items.length;
		}

		function open( index ) {
			show( index );
			ui.overlay.hidden = false;
			document.body.style.overflow = 'hidden';
		}

		function close() {
			ui.overlay.hidden = true;
			document.body.style.overflow = '';
		}

		items.forEach( function ( item, index ) {
			item.link.addEventListener( 'click', function ( ev ) {
				// let ctrl/cmd/shift/middle-clicks behave normally (open in new tab etc.)
				if ( ev.ctrlKey || ev.metaKey || ev.shiftKey || ev.button === 1 ) {
					return;
				}
				ev.preventDefault();
				open( index );
			} );
		} );

		ui.closeBtn.addEventListener( 'click', close );
		ui.prevBtn.addEventListener( 'click', function () {
			show( currentIndex - 1 );
		} );
		ui.nextBtn.addEventListener( 'click', function () {
			show( currentIndex + 1 );
		} );
		ui.overlay.addEventListener( 'click', function ( ev ) {
			if ( ev.target === ui.overlay ) {
				close();
			}
		} );
		document.addEventListener( 'keydown', function ( ev ) {
			if ( ui.overlay.hidden ) {
				return;
			}
			if ( ev.key === 'Escape' ) {
				close();
			} else if ( ev.key === 'ArrowLeft' ) {
				show( currentIndex - 1 );
			} else if ( ev.key === 'ArrowRight' ) {
				show( currentIndex + 1 );
			}
		} );
	} );
}() );

/* =========================================================================
   CRAZY VERSION — per-page color scheme picker.
   Works together with the CRAZY VERSION block in MediaWiki:Common.css.

   Reads the current page name and picks ONE of 10 schemes
   (.crazy-scheme-0 … .crazy-scheme-9). Deterministic: the same page
   ALWAYS gets the same look, but different pages (Digital Twin, Homes of
   the Internet, Köçek Pisti …) look completely different from each other.

   To turn the crazy version off: delete this block AND the CRAZY VERSION
   block in MediaWiki:Common.css. The lightbox code above is unaffected.
   ========================================================================= */
( function () {
	'use strict';
	var SCHEMES = 10;

	function pageName() {
		if ( window.mw && mw.config && mw.config.get ) {
			var n = mw.config.get( 'wgPageName' );
			if ( n ) {
				return n;
			}
		}
		return document.title || 'Main_Page';
	}

	function apply() {
		var name = pageName();
		var h = 0;
		for ( var i = 0; i < name.length; i++ ) {
			h = ( h * 31 + name.charCodeAt( i ) ) >>> 0;
		}
		var scheme = h % SCHEMES;
		if ( document.body ) {
			document.body.classList.add( 'crazy-scheme-' + scheme );
		}
	}

	if ( document.readyState !== 'loading' ) {
		apply();
	} else {
		document.addEventListener( 'DOMContentLoaded', apply );
	}
}() );