MediaWiki:Common.js: Difference between revisions
Appearance
No edit summary |
No edit summary |
||
| Line 1: | Line 1: | ||
/* | /* ========================= | ||
VERSE ACTIONS | |||
========================= */ | |||
( function () { | ( function () { | ||
'use strict'; | |||
/* ── Safe delegated listener ─────────────────────────────────────────── */ | |||
function onDocClick( e ) { | |||
var target = e.target; | |||
// Walk up to find a matching action button | |||
function closest( el, cls ) { | |||
while ( el && el !== document ) { | |||
if ( el.classList && el.classList.contains( cls ) ) return el; | |||
el = el.parentNode; | |||
} | |||
return null; | |||
} | |||
/* ── Commentary toggle ── */ | |||
var commentBtn = closest( target, 'verse-action-commentary' ); | |||
if ( commentBtn ) { | |||
e.preventDefault(); | |||
var verseId = commentBtn.getAttribute( 'data-verse' ); | |||
if ( !verseId ) return; | |||
var allBodies = document.querySelectorAll( '.commentary-body[data-verse="' + verseId + '"]' ); | |||
var allBtns = document.querySelectorAll( '.verse-action-commentary[data-verse="' + verseId + '"]' ); | |||
var isOpen = allBodies.length && allBodies[0].classList.contains( 'open' ); | |||
// Close every open commentary first | |||
document.querySelectorAll( '.commentary-body.open' ).forEach( function ( el ) { | |||
el.classList.remove( 'open' ); | |||
} ); | |||
document.querySelectorAll( '.verse-action-commentary.active' ).forEach( function ( el ) { | |||
el.classList.remove( 'active' ); | |||
} ); | |||
// If it was closed, open it | |||
if ( !isOpen ) { | |||
allBodies.forEach( function ( el ) { el.classList.add( 'open' ); } ); | |||
allBtns.forEach( function ( el ) { el.classList.add( 'active' ); } ); | |||
} | } | ||
} | return; | ||
} | |||
/* ── Copy verse ── */ | |||
var copyBtn = closest( target, 'verse-action-copy' ); | |||
// | if ( copyBtn ) { | ||
e.preventDefault(); | |||
} | var line1 = copyBtn.getAttribute( 'data-line1' ) || ''; | ||
var line2 = copyBtn.getAttribute( 'data-line2' ) || ''; | |||
var text = line2 ? line1 + '\n' + line2 : line1; | |||
if ( !text ) return; | |||
copyText( text, copyBtn ); | |||
return; | |||
} | |||
/* ── Copy ID ── */ | |||
var idBtn = closest( target, 'copy-id-btn' ); | |||
if ( idBtn ) { | |||
e.preventDefault(); | |||
var id = idBtn.getAttribute( 'data-copyid' ); | |||
if ( !id ) return; | |||
copyText( id, idBtn ); | |||
return; | |||
} | |||
} | } | ||
document.addEventListener( 'click', onDocClick ); | |||
/* ── Copy helper + tooltip ───────────────────────────────────────────── */ | |||
function copyText( text, btn ) { | |||
function showTooltip() { | |||
// Remove stale tooltip if double-clicked | |||
var old = btn.querySelector( '.copy-tooltip' ); | |||
showTooltip() | if ( old ) old.remove(); | ||
btn.style.position = 'relative'; | |||
var tip = document.createElement( 'span' ); | |||
tip.className = 'copy-tooltip'; | |||
tip.textContent = 'Copied ✓'; | |||
btn.appendChild( tip ); | |||
requestAnimationFrame( function () { | |||
requestAnimationFrame( function () { | |||
tip.classList.add( 'copy-tooltip-visible' ); | |||
} ); | } ); | ||
} ); | |||
setTimeout( function () { | |||
tip.classList.remove( 'copy-tooltip-visible' ); | |||
setTimeout( function () { tip.remove(); }, 400 ); | |||
}, 1400 ); | |||
} | } | ||
if ( navigator.clipboard && window.isSecureContext ) { | |||
navigator.clipboard.writeText( text ).then( showTooltip ); | |||
} else { | |||
var ta = document.createElement( 'textarea' ); | |||
ta.value = text; | |||
ta.style.cssText = 'position:fixed;opacity:0;pointer-events:none;'; | |||
document.body.appendChild( ta ); | |||
ta.select(); | |||
document.execCommand( 'copy' ); | |||
document.body.removeChild( ta ); | |||
showTooltip(); | |||
} | |||
} | |||
}() ); | }() ); | ||
Revision as of 11:27, 27 March 2026
/* =========================
VERSE ACTIONS
========================= */
( function () {
'use strict';
/* ── Safe delegated listener ─────────────────────────────────────────── */
function onDocClick( e ) {
var target = e.target;
// Walk up to find a matching action button
function closest( el, cls ) {
while ( el && el !== document ) {
if ( el.classList && el.classList.contains( cls ) ) return el;
el = el.parentNode;
}
return null;
}
/* ── Commentary toggle ── */
var commentBtn = closest( target, 'verse-action-commentary' );
if ( commentBtn ) {
e.preventDefault();
var verseId = commentBtn.getAttribute( 'data-verse' );
if ( !verseId ) return;
var allBodies = document.querySelectorAll( '.commentary-body[data-verse="' + verseId + '"]' );
var allBtns = document.querySelectorAll( '.verse-action-commentary[data-verse="' + verseId + '"]' );
var isOpen = allBodies.length && allBodies[0].classList.contains( 'open' );
// Close every open commentary first
document.querySelectorAll( '.commentary-body.open' ).forEach( function ( el ) {
el.classList.remove( 'open' );
} );
document.querySelectorAll( '.verse-action-commentary.active' ).forEach( function ( el ) {
el.classList.remove( 'active' );
} );
// If it was closed, open it
if ( !isOpen ) {
allBodies.forEach( function ( el ) { el.classList.add( 'open' ); } );
allBtns.forEach( function ( el ) { el.classList.add( 'active' ); } );
}
return;
}
/* ── Copy verse ── */
var copyBtn = closest( target, 'verse-action-copy' );
if ( copyBtn ) {
e.preventDefault();
var line1 = copyBtn.getAttribute( 'data-line1' ) || '';
var line2 = copyBtn.getAttribute( 'data-line2' ) || '';
var text = line2 ? line1 + '\n' + line2 : line1;
if ( !text ) return;
copyText( text, copyBtn );
return;
}
/* ── Copy ID ── */
var idBtn = closest( target, 'copy-id-btn' );
if ( idBtn ) {
e.preventDefault();
var id = idBtn.getAttribute( 'data-copyid' );
if ( !id ) return;
copyText( id, idBtn );
return;
}
}
document.addEventListener( 'click', onDocClick );
/* ── Copy helper + tooltip ───────────────────────────────────────────── */
function copyText( text, btn ) {
function showTooltip() {
// Remove stale tooltip if double-clicked
var old = btn.querySelector( '.copy-tooltip' );
if ( old ) old.remove();
btn.style.position = 'relative';
var tip = document.createElement( 'span' );
tip.className = 'copy-tooltip';
tip.textContent = 'Copied ✓';
btn.appendChild( tip );
requestAnimationFrame( function () {
requestAnimationFrame( function () {
tip.classList.add( 'copy-tooltip-visible' );
} );
} );
setTimeout( function () {
tip.classList.remove( 'copy-tooltip-visible' );
setTimeout( function () { tip.remove(); }, 400 );
}, 1400 );
}
if ( navigator.clipboard && window.isSecureContext ) {
navigator.clipboard.writeText( text ).then( showTooltip );
} else {
var ta = document.createElement( 'textarea' );
ta.value = text;
ta.style.cssText = 'position:fixed;opacity:0;pointer-events:none;';
document.body.appendChild( ta );
ta.select();
document.execCommand( 'copy' );
document.body.removeChild( ta );
showTooltip();
}
}
}() );