MediaWiki:Common.js: Difference between revisions
From Taylor Wiki
No edit summary |
No edit summary |
||
| (17 intermediate revisions by the same user not shown) | |||
| Line 10: | Line 10: | ||
'wgCategories' | 'wgCategories' | ||
]); | ]); | ||
// Only run on standard page views (skip edit forms, history, special pages) | // Only run on standard page views (skip edit forms, history, special pages) | ||
if ( !conf || conf.wgAction !== 'view' || conf.wgNamespaceNumber < 0 ) { | if ( !conf || conf.wgAction !== 'view' || conf.wgNamespaceNumber < 0 ) { | ||
return; | return; | ||
} | } | ||
var mainPageTitle = conf.wgMainPageTitle || 'Main Page'; | var mainPageTitle = conf.wgMainPageTitle || 'Main Page'; | ||
var homeUrl = mw.util.getUrl( mainPageTitle ); | var homeUrl = mw.util.getUrl( mainPageTitle ); | ||
var isHome = conf.wgIsMainPage || ( conf.wgPageName === mainPageTitle.replace( / /g, '_' ) ); | var isHome = conf.wgIsMainPage || ( conf.wgPageName === mainPageTitle.replace( / /g, '_' ) ); | ||
if ( isHome ) { | if ( isHome ) { | ||
return; | return; | ||
} | } | ||
var currentTitle = conf.wgTitle.replace( /_/g, ' ' ); | var currentTitle = conf.wgTitle.replace( /_/g, ' ' ); | ||
var categories = conf.wgCategories || []; | var categories = conf.wgCategories || []; | ||
// Top-level hub categories | // Top-level hub categories | ||
var TOP_SECTIONS = [ | var TOP_SECTIONS = [ | ||
| Line 36: | Line 31: | ||
'Family' | 'Family' | ||
]; | ]; | ||
var topSection = null; | var topSection = null; | ||
var subSection = null; | var subSection = null; | ||
// 1. Find the top-level section if present | // 1. Find the top-level section if present | ||
for ( var i = 0; i < TOP_SECTIONS.length; i++ ) { | for ( var i = 0; i < TOP_SECTIONS.length; i++ ) { | ||
| Line 53: | Line 46: | ||
} | } | ||
} | } | ||
// 2. Find any secondary category (like "Lamson") that isn't the top section | // 2. Find any secondary category (like "Lamson") that isn't the top section | ||
for ( var k = 0; k < categories.length; k++ ) { | for ( var k = 0; k < categories.length; k++ ) { | ||
| Line 62: | Line 54: | ||
} | } | ||
} | } | ||
// Prevent duplicates if viewing the section or collection page itself | // Prevent duplicates if viewing the section or collection page itself | ||
if ( topSection && currentTitle.toLowerCase() === topSection.toLowerCase() ) { | if ( topSection && currentTitle.toLowerCase() === topSection.toLowerCase() ) { | ||
| Line 70: | Line 61: | ||
subSection = null; | subSection = null; | ||
} | } | ||
// Build the breadcrumb bar | // Build the breadcrumb bar | ||
var $nav = $( '<div class="mw-dynamic-breadcrumbs" aria-label="Breadcrumb navigation"></div>' ); | var $nav = $( '<div class="mw-dynamic-breadcrumbs" aria-label="Breadcrumb navigation"></div>' ); | ||
// 1. Home / Main Page | // 1. Home / Main Page | ||
$nav.append( $( '<a>' ).addClass( 'crumb-link' ).attr( 'href', homeUrl ).text( 'Main Page' ) ); | $nav.append( $( '<a>' ).addClass( 'crumb-link' ).attr( 'href', homeUrl ).text( 'Main Page' ) ); | ||
// 2. Top-level Section (e.g. Letters) | // 2. Top-level Section (e.g. Letters) | ||
if ( topSection ) { | if ( topSection ) { | ||
| Line 82: | Line 70: | ||
$nav.append( $( '<a>' ).addClass( 'crumb-link' ).attr( 'href', mw.util.getUrl( topSection ) ).text( topSection ) ); | $nav.append( $( '<a>' ).addClass( 'crumb-link' ).attr( 'href', mw.util.getUrl( topSection ) ).text( topSection ) ); | ||
} | } | ||
// 3. Sub-level Collection / Person (e.g. Lamson) | // 3. Sub-level Collection / Person (e.g. Lamson) | ||
if ( subSection ) { | if ( subSection ) { | ||
| Line 88: | Line 75: | ||
$nav.append( $( '<a>' ).addClass( 'crumb-link' ).attr( 'href', mw.util.getUrl( subSection ) ).text( subSection ) ); | $nav.append( $( '<a>' ).addClass( 'crumb-link' ).attr( 'href', mw.util.getUrl( subSection ) ).text( subSection ) ); | ||
} | } | ||
// 4. Current File or Article Title | // 4. Current File or Article Title | ||
$nav.append( $( '<span>' ).addClass( 'crumb-sep' ).text( '›' ) ); | $nav.append( $( '<span>' ).addClass( 'crumb-sep' ).text( '›' ) ); | ||
$nav.append( $( '<span>' ).addClass( 'crumb-current' ).text( currentTitle ) ); | $nav.append( $( '<span>' ).addClass( 'crumb-current' ).text( currentTitle ) ); | ||
// Inject above title in Timeless skin | // Inject above title in Timeless skin | ||
$( function () { | $( function () { | ||
| Line 103: | Line 88: | ||
} ); | } ); | ||
}() ); | }() ); | ||
/* Open | |||
/* Open optimal reading resolution preview on the main photo instead of tiny thumb or massive scan */ | |||
$( function() { | $( function() { | ||
if ( mw.config.get( 'wgNamespaceNumber' ) === 6 ) { // File namespace | if ( mw.config.get( 'wgNamespaceNumber' ) === 6 ) { // File namespace | ||
var $previewLink = $( '.fullImageLink a' ); | // Use direct child selector '>' so we ONLY target the photo itself, not the resolution links below it | ||
var $ | var $previewLink = $( '.fullImageLink > a' ); | ||
if ( $previewLink.length && $ | var $resLinks = $( '.mw-filepage-resolutioninfo a' ); | ||
$previewLink.attr( 'href', $ | if ( $previewLink.length && $resLinks.length ) { | ||
var bestHref = null; | |||
var bestWidth = 0; | |||
$resLinks.each( function() { | |||
var text = $( this ).text(); // e.g. "2,048 × 1,153 pixels" | |||
var match = text.replace(/,/g, '').match(/(\d+)\s*×/); | |||
if ( match ) { | |||
var w = parseInt( match[1], 10 ); | |||
// Pick the crispest preview up to 2560px wide (great for desktop reading) | |||
if ( w > bestWidth && w <= 2560 ) { | |||
bestWidth = w; | |||
bestHref = $( this ).attr( 'href' ); | |||
} | |||
} | |||
} ); | |||
if ( bestHref ) { | |||
$previewLink.attr( 'href', bestHref ); | |||
} | |||
} | |||
} | |||
} ); | |||
/* Inject Universal GEWAME Umbrella Header */ | |||
$( function () { | |||
if ( $( '#gewame-universal-bar' ).length ) { | |||
return; | |||
} | |||
var isLoggedIn = document.cookie.indexOf( 'gewame_logged_in=1' ) !== -1; | |||
var currentUrl = encodeURIComponent( window.location.href ); | |||
var authLink = isLoggedIn | |||
? '<a href="https://gewame.com/sso-logout.php?redirect_to=' + currentUrl + '" class="gw-nav-link gw-btn-auth">LOG OUT</a>' | |||
: '<a href="https://gewame.com/wp-login.php?action=register" class="gw-nav-link gw-btn-auth">REGISTER</a>' + | |||
'<a href="https://gewame.com/wp-login.php?redirect_to=' + currentUrl + '" class="gw-nav-link gw-btn-auth">LOG IN</a>'; | |||
var headerHtml = | |||
'<div id="gewame-universal-bar">' + | |||
'<div class="gw-bar-inner">' + | |||
'<a href="https://gewame.com/" class="gw-brand" title="GEWAME — The Taylor Archive">' + | |||
'<span class="gw-brand-title">GEWAME</span>' + | |||
'<span class="gw-brand-sep">|</span>' + | |||
'<span class="gw-brand-sub">The Taylor Archive</span>' + | |||
'</a>' + | |||
'<nav class="gw-nav">' + | |||
'<a href="https://gewame.com/wiki/" class="gw-nav-link gw-active">WIKI</a>' + | |||
'<a href="https://gewame.com/tree/" class="gw-nav-link">TREE</a>' + | |||
'<a href="https://gewame.com/forum/" class="gw-nav-link">FORUM</a>' + | |||
'<a href="https://gewame.com/contact/" class="gw-nav-link"><span class="gw-contact-text">CONTACT</span><svg class="gw-contact-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:middle;display:none;"><rect width="20" height="16" x="2" y="4" rx="2"></rect><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"></path></svg></a>' + | |||
authLink + | |||
'</nav>' + | |||
'</div>' + | |||
'</div>'; | |||
$( 'body' ).prepend( headerHtml ); | |||
} ); | |||
/* Random Featured Video on the Videos page */ | |||
$(function() { | |||
// Only run on the main Videos page | |||
if (mw.config.get('wgPageName') !== 'Videos') return; | |||
var videoList = [ | |||
{ | |||
id: 'f9WcK-Peclk', | |||
caption: 'Taylor Instrument Companies — Rochester Business Hall of Fame Induction (2012).' | |||
}, | |||
{ | |||
id: 'tLAQtuhGc0Q', | |||
caption: 'Starky: Training at Taylor Instrument Company — Oral History.' | |||
} | |||
/* Add new videos here as you upload them: | |||
,{ id: 'YOUTUBE_ID', caption: 'Short description here.' } | |||
*/ | |||
]; | |||
var randomVideo = videoList[Math.floor(Math.random() * videoList.length)]; | |||
// Update the iframe and caption | |||
var $iframe = $('#gw-featured-player iframe'); | |||
if ($iframe.length) { | |||
$iframe.attr('src', 'https://www.youtube-nocookie.com/embed/' + randomVideo.id); | |||
$('#gw-featured-caption').text(randomVideo.caption); | |||
} | |||
}); | |||
/* =================================================== | |||
GEWAME Archival Booklet Reader (Captions + Zoom & Pan) | |||
=================================================== */ | |||
$(function() { | |||
var $readers = $('.gw-book-reader'); | |||
if (!$readers.length) return; | |||
$readers.each(function() { | |||
var $reader = $(this); | |||
var $fallback = $reader.find('.gw-book-fallback'); | |||
var $images = $fallback.find('img'); | |||
if (!$images.length) return; | |||
// Parse page items (URL + caption) | |||
var pages = []; | |||
$images.each(function() { | |||
var $img = $(this); | |||
var src = $img.attr('src'); | |||
var caption = $img.attr('alt') || $img.attr('title') || ''; | |||
pages.push({ src: src, caption: caption }); | |||
}); | |||
$fallback.hide(); | |||
var currentIndex = 0; | |||
var isZoomed = false; | |||
var zoomScale = 2.4; | |||
var panX = 0; | |||
var panY = 0; | |||
var isDragging = false; | |||
var dragStartX = 0; | |||
var dragStartY = 0; | |||
// Stage markup | |||
var $stage = $('<div class="gw-book-stage">' + | |||
'<div class="gw-book-click-left" title="Previous page"></div>' + | |||
'<div class="gw-book-page-wrapper">' + | |||
'<img class="gw-book-page-img" src="' + pages[0].src + '" alt="Page 1" draggable="false" />' + | |||
'</div>' + | |||
'<div class="gw-book-click-right" title="Next page"></div>' + | |||
'</div>'); | |||
// Toolbar markup with zoom controls and caption | |||
var $toolbar = $('<div class="gw-book-toolbar">' + | |||
'<div class="gw-book-nav-group">' + | |||
'<button class="gw-book-btn gw-btn-prev">‹ Prev</button>' + | |||
'<button class="gw-book-btn gw-btn-next">Next ›</button>' + | |||
'</div>' + | |||
'<div class="gw-book-center-info">' + | |||
'<span class="gw-book-counter">Page 1 of ' + pages.length + '</span>' + | |||
'<span class="gw-book-caption"></span>' + | |||
'</div>' + | |||
'<div class="gw-book-zoom-group">' + | |||
'<button class="gw-book-btn gw-btn-zoom">🔍 Zoom In</button>' + | |||
'</div>' + | |||
'</div>' + | |||
'<div class="gw-book-hint">Tip: Click page or 🔍 Zoom to enlarge, then drag to pan. Use arrow keys or buttons to flip.</div>'); | |||
$reader.append($stage).append($toolbar); | |||
var $wrapper = $stage.find('.gw-book-page-wrapper'); | |||
var $img = $stage.find('.gw-book-page-img'); | |||
var $counter = $reader.find('.gw-book-counter'); | |||
var $caption = $reader.find('.gw-book-caption'); | |||
var $btnPrev = $reader.find('.gw-btn-prev'); | |||
var $btnNext = $reader.find('.gw-btn-next'); | |||
var $btnZoom = $reader.find('.gw-btn-zoom'); | |||
function resetZoom() { | |||
isZoomed = false; | |||
panX = 0; | |||
panY = 0; | |||
$reader.removeClass('is-zoomed is-dragging'); | |||
$img.css({ | |||
transform: 'none', | |||
transition: 'transform 0.2s ease-out' | |||
}); | |||
$btnZoom.removeClass('active').text('🔍 Zoom In'); | |||
$wrapper.css('cursor', 'zoom-in'); | |||
} | } | ||
function setZoom(zoomed) { | |||
if (zoomed) { | |||
isZoomed = true; | |||
panX = 0; | |||
panY = 0; | |||
$reader.addClass('is-zoomed'); | |||
$img.css({ | |||
transform: 'scale(' + zoomScale + ') translate(0px, 0px)', | |||
transition: 'transform 0.2s ease-out' | |||
}); | |||
$btnZoom.addClass('active').text('✖ Reset Zoom'); | |||
$wrapper.css('cursor', 'grab'); | |||
} else { | |||
resetZoom(); | |||
} | |||
} | |||
function updatePage(index) { | |||
if (index < 0 || index >= pages.length) return; | |||
resetZoom(); | |||
currentIndex = index; | |||
$img.css('opacity', '0.35'); | |||
var nextData = pages[currentIndex]; | |||
var temp = new Image(); | |||
temp.onload = function() { | |||
$img.attr('src', nextData.src).css('opacity', '1'); | |||
}; | |||
temp.src = nextData.src; | |||
$counter.text('Page ' + (currentIndex + 1) + ' of ' + pages.length); | |||
// Clean up caption text if it repeats "Page X" | |||
var captionText = nextData.caption || ''; | |||
if (captionText) { | |||
$caption.text('— ' + captionText); | |||
} else { | |||
$caption.text(''); | |||
} | |||
$btnPrev.prop('disabled', currentIndex === 0); | |||
$btnNext.prop('disabled', currentIndex === pages.length - 1); | |||
} | |||
// Initialize page 1 | |||
updatePage(0); | |||
// Navigation clicks | |||
$btnPrev.on('click', function() { updatePage(currentIndex - 1); }); | |||
$btnNext.on('click', function() { updatePage(currentIndex + 1); }); | |||
$stage.find('.gw-book-click-left').on('click', function() { | |||
if (!isZoomed) updatePage(currentIndex - 1); | |||
}); | |||
$stage.find('.gw-book-click-right').on('click', function() { | |||
if (!isZoomed) updatePage(currentIndex + 1); | |||
}); | |||
// Zoom toggle | |||
$btnZoom.on('click', function() { | |||
setZoom(!isZoomed); | |||
}); | |||
$wrapper.on('click', function(e) { | |||
if (!isZoomed) { | |||
setZoom(true); | |||
} | |||
}); | |||
// Drag to pan when zoomed | |||
$wrapper.on('mousedown touchstart', function(e) { | |||
if (!isZoomed) return; | |||
isDragging = true; | |||
$reader.addClass('is-dragging'); | |||
var clientX = e.type === 'touchstart' ? e.originalEvent.touches[0].clientX : e.clientX; | |||
var clientY = e.type === 'touchstart' ? e.originalEvent.touches[0].clientY : e.clientY; | |||
dragStartX = clientX - panX; | |||
dragStartY = clientY - panY; | |||
$img.css('transition', 'none'); // Instant drag response | |||
e.preventDefault(); | |||
}); | |||
$(document).on('mousemove touchmove', function(e) { | |||
if (!isDragging || !isZoomed) return; | |||
var clientX = e.type === 'touchmove' ? e.originalEvent.touches[0].clientX : e.clientX; | |||
var clientY = e.type === 'touchmove' ? e.originalEvent.touches[0].clientY : e.clientY; | |||
panX = clientX - dragStartX; | |||
panY = clientY - dragStartY; | |||
// Restrict bounds based on zoom level | |||
var limitX = ($stage.width() * (zoomScale - 1)) / (2 * zoomScale); | |||
var limitY = ($stage.height() * (zoomScale - 1)) / (2 * zoomScale); | |||
panX = Math.max(-limitX, Math.min(limitX, panX)); | |||
panY = Math.max(-limitY, Math.min(limitY, panY)); | |||
$img.css('transform', 'scale(' + zoomScale + ') translate(' + panX + 'px, ' + panY + 'px)'); | |||
}); | |||
$(document).on('mouseup touchend', function() { | |||
if (isDragging) { | |||
isDragging = false; | |||
$reader.removeClass('is-dragging'); | |||
} | |||
}); | |||
// Keyboard navigation & Escape to reset zoom | |||
$(document).on('keydown', function(e) { | |||
if ($(e.target).is('input, textarea')) return; | |||
if (e.which === 27) { // Escape key | |||
resetZoom(); | |||
} else if (!isZoomed) { | |||
if (e.which === 37) { // Left arrow | |||
updatePage(currentIndex - 1); | |||
} else if (e.which === 39) { // Right arrow | |||
updatePage(currentIndex + 1); | |||
} | |||
} | |||
}); | |||
// Mobile swipe between pages (when NOT zoomed in) | |||
var swipeStartX = 0; | |||
$stage.on('touchstart', function(e) { | |||
if (!isZoomed && e.originalEvent.touches.length === 1) { | |||
swipeStartX = e.originalEvent.touches[0].clientX; | |||
} | |||
}); | |||
$stage.on('touchend', function(e) { | |||
if (!isZoomed && swipeStartX !== 0) { | |||
var diff = swipeStartX - e.originalEvent.changedTouches[0].clientX; | |||
if (Math.abs(diff) > 40) { | |||
if (diff > 0) updatePage(currentIndex + 1); | |||
else updatePage(currentIndex - 1); | |||
} | |||
swipeStartX = 0; | |||
} | |||
}); | |||
}); | |||
}); | |||
/* =================================================== | |||
Internet Archive BookReader Embed Engine | |||
=================================================== */ | |||
$(function() { | |||
$('.gw-archive-embed').each(function() { | |||
var $el = $(this); | |||
var id = $el.data('id'); | |||
if (!id) return; | |||
var embedUrl = 'https://archive.org/embed/' + encodeURIComponent(id); | |||
var directUrl = 'https://archive.org/details/' + encodeURIComponent(id) + '/mode/2up'; | |||
var html = '<div class="gw-ia-container">' + | |||
'<div class="gw-ia-frame-wrap">' + | |||
'<iframe src="' + embedUrl + '" width="100%" height="100%" frameborder="0" webkitallowfullscreen="true" mozallowfullscreen="true" allowfullscreen style="border:0; display:block;"></iframe>' + | |||
'</div>' + | |||
'<div class="gw-ia-toolbar">' + | |||
'<span style="color:#94a3b8;">📖 Internet Archive BookReader</span>' + | |||
'<a href="' + directUrl + '" target="_blank" rel="noopener">Open in Fullscreen / Download PDF ↗</a>' + | |||
'</div>' + | |||
'</div>'; | |||
$el.html(html); | |||
}); | |||
}); | |||
/* ======================================================== | |||
Social Share Bar at the bottom of articles | |||
======================================================== */ | |||
$(function() { | |||
// Only show on regular article pages in read view | |||
if (mw.config.get('wgAction') !== 'view' || mw.config.get('wgNamespaceNumber') < 0) { | |||
return; | |||
} | |||
var pageUrl = encodeURIComponent(window.location.href); | |||
var pageTitle = encodeURIComponent(mw.config.get('wgTitle') + ' - GEWAME Archive'); | |||
var fbUrl = 'https://www.facebook.com/sharer/sharer.php?u=' + pageUrl; | |||
var xUrl = 'https://twitter.com/intent/tweet?url=' + pageUrl + '&text=' + pageTitle; | |||
var liUrl = 'https://www.linkedin.com/sharing/share-offsite/?url=' + pageUrl; | |||
var mailUrl = 'mailto:?subject=' + pageTitle + '&body=Check%20out%20this%20page%3A%20' + pageUrl; | |||
var shareHtml = $( | |||
'<div class="gw-share-bar">' + | |||
'<span class="gw-share-label">Share this page:</span>' + | |||
'<div class="gw-share-buttons">' + | |||
'<a class="gw-share-btn gw-share-fb" href="' + fbUrl + '" target="_blank" rel="noopener noreferrer" title="Share on Facebook">Facebook</a>' + | |||
'<a class="gw-share-btn gw-share-x" href="' + xUrl + '" target="_blank" rel="noopener noreferrer" title="Share on X">X (Twitter)</a>' + | |||
'<a class="gw-share-btn gw-share-li" href="' + liUrl + '" target="_blank" rel="noopener noreferrer" title="Share on LinkedIn">LinkedIn</a>' + | |||
'<a class="gw-share-btn gw-share-email" href="' + mailUrl + '" title="Share via Email">Email</a>' + | |||
'<button type="button" class="gw-share-btn gw-share-copy" title="Copy page link">Copy Link</button>' + | |||
'</div>' + | |||
'</div>' | |||
); | |||
// Copy link click handler | |||
shareHtml.find('.gw-share-copy').on('click', function(e) { | |||
e.preventDefault(); | |||
var btn = $(this); | |||
navigator.clipboard.writeText(window.location.href).then(function() { | |||
var origText = btn.text(); | |||
btn.text('Copied!').addClass('gw-copied'); | |||
setTimeout(function() { | |||
btn.text(origText).removeClass('gw-copied'); | |||
}, 2000); | |||
}); | |||
}); | |||
// Append to the bottom of the article content (just before categories) | |||
$('#mw-content-text').append(shareHtml); | |||
}); | |||
/* ======================================================== | |||
Help Identify Overlays and Banners | |||
======================================================== */ | |||
$(function() { | |||
// 1. Look for marker in gallery captions and overlay matching badge onto thumbnail | |||
$('.gallerybox').each(function() { | |||
var $thumb = $(this).find('.thumb').css('position', 'relative'); | |||
if ($(this).find('.gw-unidentified-marker').length > 0) { | |||
$thumb.append('<div class="gw-photo-overlay-tag gw-tag-unidentified">Help Identify</div>'); | |||
} else if ($(this).find('.gw-partial-marker').length > 0) { | |||
$thumb.append('<div class="gw-photo-overlay-tag gw-tag-partial">Partially Identified</div>'); | |||
} else if ($(this).find('.gw-identified-marker').length > 0) { | |||
$thumb.append('<div class="gw-photo-overlay-tag gw-tag-identified">Identified</div>'); | |||
} | |||
}); | |||
// 2. On File pages, relocate the Identification Needed banner above the image | |||
if (mw.config.get('wgNamespaceNumber') === 6) { // File namespace | |||
var $banner = $('.gw-needs-id-banner'); | |||
var $fileTarget = $('.fullImageLink').first(); | |||
if ($banner.length && $fileTarget.length) { | |||
$banner.insertBefore($fileTarget); | |||
} | |||
} | |||
}); | |||
/* Smooth scroll from top banner down to comment section */ | |||
$(document).on('click', '.gw-needs-id-btn', function(e) { | |||
e.preventDefault(); | |||
// Look for the Add Comment button or the comment container | |||
var target = $('button:contains("Add comment")').first(); | |||
if (!target.length) { | |||
target = $('.cs-comments, #comments, .ext-commentstreams').first(); | |||
} | |||
if (target.length) { | |||
$('html, body').animate({ | |||
scrollTop: target.offset().top - 80 | |||
}, 600); | |||
} else { | |||
// Fallback: scroll to bottom of content | |||
$('html, body').animate({ | |||
scrollTop: $('#mw-content-text').offset().top + $('#mw-content-text').height() | |||
}, 600); | |||
} | |||
}); | |||
/* Hide guest callout on Main Page when user is logged in */ | |||
$( function () { | |||
var isLoggedIn = ( typeof mw !== 'undefined' && mw.user && !mw.user.isAnon() ) || | |||
( document.cookie.indexOf( 'gewame_logged_in=1' ) !== -1 ) || | |||
( $( '#pt-logout' ).length > 0 ); | |||
if ( isLoggedIn ) { | |||
$( '.gw-guest-only-box' ).hide(); | |||
} | } | ||
} ); | } ); | ||
Latest revision as of 13:50, 25 October 2026
/* Multi-Tier Category Breadcrumbs (Home › Section › Collection/Topic › Page/File) */
( function () {
var conf = mw.config.get([
'wgAction',
'wgNamespaceNumber',
'wgPageName',
'wgTitle',
'wgIsMainPage',
'wgMainPageTitle',
'wgCategories'
]);
// Only run on standard page views (skip edit forms, history, special pages)
if ( !conf || conf.wgAction !== 'view' || conf.wgNamespaceNumber < 0 ) {
return;
}
var mainPageTitle = conf.wgMainPageTitle || 'Main Page';
var homeUrl = mw.util.getUrl( mainPageTitle );
var isHome = conf.wgIsMainPage || ( conf.wgPageName === mainPageTitle.replace( / /g, '_' ) );
if ( isHome ) {
return;
}
var currentTitle = conf.wgTitle.replace( /_/g, ' ' );
var categories = conf.wgCategories || [];
// Top-level hub categories
var TOP_SECTIONS = [
'Letters',
'Instruments',
'Photographs',
'Documents',
'Biographies',
'Family'
];
var topSection = null;
var subSection = null;
// 1. Find the top-level section if present
for ( var i = 0; i < TOP_SECTIONS.length; i++ ) {
var sec = TOP_SECTIONS[i];
for ( var c = 0; c < categories.length; c++ ) {
if ( categories[c].toLowerCase() === sec.toLowerCase() ) {
topSection = sec;
break;
}
}
if ( topSection ) {
break;
}
}
// 2. Find any secondary category (like "Lamson") that isn't the top section
for ( var k = 0; k < categories.length; k++ ) {
var catName = categories[k].replace( /_/g, ' ' );
if ( !topSection || catName.toLowerCase() !== topSection.toLowerCase() ) {
subSection = catName;
break;
}
}
// Prevent duplicates if viewing the section or collection page itself
if ( topSection && currentTitle.toLowerCase() === topSection.toLowerCase() ) {
topSection = null;
}
if ( subSection && currentTitle.toLowerCase() === subSection.toLowerCase() ) {
subSection = null;
}
// Build the breadcrumb bar
var $nav = $( '<div class="mw-dynamic-breadcrumbs" aria-label="Breadcrumb navigation"></div>' );
// 1. Home / Main Page
$nav.append( $( '<a>' ).addClass( 'crumb-link' ).attr( 'href', homeUrl ).text( 'Main Page' ) );
// 2. Top-level Section (e.g. Letters)
if ( topSection ) {
$nav.append( $( '<span>' ).addClass( 'crumb-sep' ).text( '›' ) );
$nav.append( $( '<a>' ).addClass( 'crumb-link' ).attr( 'href', mw.util.getUrl( topSection ) ).text( topSection ) );
}
// 3. Sub-level Collection / Person (e.g. Lamson)
if ( subSection ) {
$nav.append( $( '<span>' ).addClass( 'crumb-sep' ).text( '›' ) );
$nav.append( $( '<a>' ).addClass( 'crumb-link' ).attr( 'href', mw.util.getUrl( subSection ) ).text( subSection ) );
}
// 4. Current File or Article Title
$nav.append( $( '<span>' ).addClass( 'crumb-sep' ).text( '›' ) );
$nav.append( $( '<span>' ).addClass( 'crumb-current' ).text( currentTitle ) );
// Inject above title in Timeless skin
$( function () {
var $heading = $( '#firstHeading' );
if ( $heading.length ) {
$nav.insertBefore( $heading );
} else {
$( '#mw-content-text' ).prepend( $nav );
}
} );
}() );
/* Open optimal reading resolution preview on the main photo instead of tiny thumb or massive scan */
$( function() {
if ( mw.config.get( 'wgNamespaceNumber' ) === 6 ) { // File namespace
// Use direct child selector '>' so we ONLY target the photo itself, not the resolution links below it
var $previewLink = $( '.fullImageLink > a' );
var $resLinks = $( '.mw-filepage-resolutioninfo a' );
if ( $previewLink.length && $resLinks.length ) {
var bestHref = null;
var bestWidth = 0;
$resLinks.each( function() {
var text = $( this ).text(); // e.g. "2,048 × 1,153 pixels"
var match = text.replace(/,/g, '').match(/(\d+)\s*×/);
if ( match ) {
var w = parseInt( match[1], 10 );
// Pick the crispest preview up to 2560px wide (great for desktop reading)
if ( w > bestWidth && w <= 2560 ) {
bestWidth = w;
bestHref = $( this ).attr( 'href' );
}
}
} );
if ( bestHref ) {
$previewLink.attr( 'href', bestHref );
}
}
}
} );
/* Inject Universal GEWAME Umbrella Header */
$( function () {
if ( $( '#gewame-universal-bar' ).length ) {
return;
}
var isLoggedIn = document.cookie.indexOf( 'gewame_logged_in=1' ) !== -1;
var currentUrl = encodeURIComponent( window.location.href );
var authLink = isLoggedIn
? '<a href="https://gewame.com/sso-logout.php?redirect_to=' + currentUrl + '" class="gw-nav-link gw-btn-auth">LOG OUT</a>'
: '<a href="https://gewame.com/wp-login.php?action=register" class="gw-nav-link gw-btn-auth">REGISTER</a>' +
'<a href="https://gewame.com/wp-login.php?redirect_to=' + currentUrl + '" class="gw-nav-link gw-btn-auth">LOG IN</a>';
var headerHtml =
'<div id="gewame-universal-bar">' +
'<div class="gw-bar-inner">' +
'<a href="https://gewame.com/" class="gw-brand" title="GEWAME — The Taylor Archive">' +
'<span class="gw-brand-title">GEWAME</span>' +
'<span class="gw-brand-sep">|</span>' +
'<span class="gw-brand-sub">The Taylor Archive</span>' +
'</a>' +
'<nav class="gw-nav">' +
'<a href="https://gewame.com/wiki/" class="gw-nav-link gw-active">WIKI</a>' +
'<a href="https://gewame.com/tree/" class="gw-nav-link">TREE</a>' +
'<a href="https://gewame.com/forum/" class="gw-nav-link">FORUM</a>' +
'<a href="https://gewame.com/contact/" class="gw-nav-link"><span class="gw-contact-text">CONTACT</span><svg class="gw-contact-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:middle;display:none;"><rect width="20" height="16" x="2" y="4" rx="2"></rect><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"></path></svg></a>' +
authLink +
'</nav>' +
'</div>' +
'</div>';
$( 'body' ).prepend( headerHtml );
} );
/* Random Featured Video on the Videos page */
$(function() {
// Only run on the main Videos page
if (mw.config.get('wgPageName') !== 'Videos') return;
var videoList = [
{
id: 'f9WcK-Peclk',
caption: 'Taylor Instrument Companies — Rochester Business Hall of Fame Induction (2012).'
},
{
id: 'tLAQtuhGc0Q',
caption: 'Starky: Training at Taylor Instrument Company — Oral History.'
}
/* Add new videos here as you upload them:
,{ id: 'YOUTUBE_ID', caption: 'Short description here.' }
*/
];
var randomVideo = videoList[Math.floor(Math.random() * videoList.length)];
// Update the iframe and caption
var $iframe = $('#gw-featured-player iframe');
if ($iframe.length) {
$iframe.attr('src', 'https://www.youtube-nocookie.com/embed/' + randomVideo.id);
$('#gw-featured-caption').text(randomVideo.caption);
}
});
/* ===================================================
GEWAME Archival Booklet Reader (Captions + Zoom & Pan)
=================================================== */
$(function() {
var $readers = $('.gw-book-reader');
if (!$readers.length) return;
$readers.each(function() {
var $reader = $(this);
var $fallback = $reader.find('.gw-book-fallback');
var $images = $fallback.find('img');
if (!$images.length) return;
// Parse page items (URL + caption)
var pages = [];
$images.each(function() {
var $img = $(this);
var src = $img.attr('src');
var caption = $img.attr('alt') || $img.attr('title') || '';
pages.push({ src: src, caption: caption });
});
$fallback.hide();
var currentIndex = 0;
var isZoomed = false;
var zoomScale = 2.4;
var panX = 0;
var panY = 0;
var isDragging = false;
var dragStartX = 0;
var dragStartY = 0;
// Stage markup
var $stage = $('<div class="gw-book-stage">' +
'<div class="gw-book-click-left" title="Previous page"></div>' +
'<div class="gw-book-page-wrapper">' +
'<img class="gw-book-page-img" src="' + pages[0].src + '" alt="Page 1" draggable="false" />' +
'</div>' +
'<div class="gw-book-click-right" title="Next page"></div>' +
'</div>');
// Toolbar markup with zoom controls and caption
var $toolbar = $('<div class="gw-book-toolbar">' +
'<div class="gw-book-nav-group">' +
'<button class="gw-book-btn gw-btn-prev">‹ Prev</button>' +
'<button class="gw-book-btn gw-btn-next">Next ›</button>' +
'</div>' +
'<div class="gw-book-center-info">' +
'<span class="gw-book-counter">Page 1 of ' + pages.length + '</span>' +
'<span class="gw-book-caption"></span>' +
'</div>' +
'<div class="gw-book-zoom-group">' +
'<button class="gw-book-btn gw-btn-zoom">🔍 Zoom In</button>' +
'</div>' +
'</div>' +
'<div class="gw-book-hint">Tip: Click page or 🔍 Zoom to enlarge, then drag to pan. Use arrow keys or buttons to flip.</div>');
$reader.append($stage).append($toolbar);
var $wrapper = $stage.find('.gw-book-page-wrapper');
var $img = $stage.find('.gw-book-page-img');
var $counter = $reader.find('.gw-book-counter');
var $caption = $reader.find('.gw-book-caption');
var $btnPrev = $reader.find('.gw-btn-prev');
var $btnNext = $reader.find('.gw-btn-next');
var $btnZoom = $reader.find('.gw-btn-zoom');
function resetZoom() {
isZoomed = false;
panX = 0;
panY = 0;
$reader.removeClass('is-zoomed is-dragging');
$img.css({
transform: 'none',
transition: 'transform 0.2s ease-out'
});
$btnZoom.removeClass('active').text('🔍 Zoom In');
$wrapper.css('cursor', 'zoom-in');
}
function setZoom(zoomed) {
if (zoomed) {
isZoomed = true;
panX = 0;
panY = 0;
$reader.addClass('is-zoomed');
$img.css({
transform: 'scale(' + zoomScale + ') translate(0px, 0px)',
transition: 'transform 0.2s ease-out'
});
$btnZoom.addClass('active').text('✖ Reset Zoom');
$wrapper.css('cursor', 'grab');
} else {
resetZoom();
}
}
function updatePage(index) {
if (index < 0 || index >= pages.length) return;
resetZoom();
currentIndex = index;
$img.css('opacity', '0.35');
var nextData = pages[currentIndex];
var temp = new Image();
temp.onload = function() {
$img.attr('src', nextData.src).css('opacity', '1');
};
temp.src = nextData.src;
$counter.text('Page ' + (currentIndex + 1) + ' of ' + pages.length);
// Clean up caption text if it repeats "Page X"
var captionText = nextData.caption || '';
if (captionText) {
$caption.text('— ' + captionText);
} else {
$caption.text('');
}
$btnPrev.prop('disabled', currentIndex === 0);
$btnNext.prop('disabled', currentIndex === pages.length - 1);
}
// Initialize page 1
updatePage(0);
// Navigation clicks
$btnPrev.on('click', function() { updatePage(currentIndex - 1); });
$btnNext.on('click', function() { updatePage(currentIndex + 1); });
$stage.find('.gw-book-click-left').on('click', function() {
if (!isZoomed) updatePage(currentIndex - 1);
});
$stage.find('.gw-book-click-right').on('click', function() {
if (!isZoomed) updatePage(currentIndex + 1);
});
// Zoom toggle
$btnZoom.on('click', function() {
setZoom(!isZoomed);
});
$wrapper.on('click', function(e) {
if (!isZoomed) {
setZoom(true);
}
});
// Drag to pan when zoomed
$wrapper.on('mousedown touchstart', function(e) {
if (!isZoomed) return;
isDragging = true;
$reader.addClass('is-dragging');
var clientX = e.type === 'touchstart' ? e.originalEvent.touches[0].clientX : e.clientX;
var clientY = e.type === 'touchstart' ? e.originalEvent.touches[0].clientY : e.clientY;
dragStartX = clientX - panX;
dragStartY = clientY - panY;
$img.css('transition', 'none'); // Instant drag response
e.preventDefault();
});
$(document).on('mousemove touchmove', function(e) {
if (!isDragging || !isZoomed) return;
var clientX = e.type === 'touchmove' ? e.originalEvent.touches[0].clientX : e.clientX;
var clientY = e.type === 'touchmove' ? e.originalEvent.touches[0].clientY : e.clientY;
panX = clientX - dragStartX;
panY = clientY - dragStartY;
// Restrict bounds based on zoom level
var limitX = ($stage.width() * (zoomScale - 1)) / (2 * zoomScale);
var limitY = ($stage.height() * (zoomScale - 1)) / (2 * zoomScale);
panX = Math.max(-limitX, Math.min(limitX, panX));
panY = Math.max(-limitY, Math.min(limitY, panY));
$img.css('transform', 'scale(' + zoomScale + ') translate(' + panX + 'px, ' + panY + 'px)');
});
$(document).on('mouseup touchend', function() {
if (isDragging) {
isDragging = false;
$reader.removeClass('is-dragging');
}
});
// Keyboard navigation & Escape to reset zoom
$(document).on('keydown', function(e) {
if ($(e.target).is('input, textarea')) return;
if (e.which === 27) { // Escape key
resetZoom();
} else if (!isZoomed) {
if (e.which === 37) { // Left arrow
updatePage(currentIndex - 1);
} else if (e.which === 39) { // Right arrow
updatePage(currentIndex + 1);
}
}
});
// Mobile swipe between pages (when NOT zoomed in)
var swipeStartX = 0;
$stage.on('touchstart', function(e) {
if (!isZoomed && e.originalEvent.touches.length === 1) {
swipeStartX = e.originalEvent.touches[0].clientX;
}
});
$stage.on('touchend', function(e) {
if (!isZoomed && swipeStartX !== 0) {
var diff = swipeStartX - e.originalEvent.changedTouches[0].clientX;
if (Math.abs(diff) > 40) {
if (diff > 0) updatePage(currentIndex + 1);
else updatePage(currentIndex - 1);
}
swipeStartX = 0;
}
});
});
});
/* ===================================================
Internet Archive BookReader Embed Engine
=================================================== */
$(function() {
$('.gw-archive-embed').each(function() {
var $el = $(this);
var id = $el.data('id');
if (!id) return;
var embedUrl = 'https://archive.org/embed/' + encodeURIComponent(id);
var directUrl = 'https://archive.org/details/' + encodeURIComponent(id) + '/mode/2up';
var html = '<div class="gw-ia-container">' +
'<div class="gw-ia-frame-wrap">' +
'<iframe src="' + embedUrl + '" width="100%" height="100%" frameborder="0" webkitallowfullscreen="true" mozallowfullscreen="true" allowfullscreen style="border:0; display:block;"></iframe>' +
'</div>' +
'<div class="gw-ia-toolbar">' +
'<span style="color:#94a3b8;">📖 Internet Archive BookReader</span>' +
'<a href="' + directUrl + '" target="_blank" rel="noopener">Open in Fullscreen / Download PDF ↗</a>' +
'</div>' +
'</div>';
$el.html(html);
});
});
/* ========================================================
Social Share Bar at the bottom of articles
======================================================== */
$(function() {
// Only show on regular article pages in read view
if (mw.config.get('wgAction') !== 'view' || mw.config.get('wgNamespaceNumber') < 0) {
return;
}
var pageUrl = encodeURIComponent(window.location.href);
var pageTitle = encodeURIComponent(mw.config.get('wgTitle') + ' - GEWAME Archive');
var fbUrl = 'https://www.facebook.com/sharer/sharer.php?u=' + pageUrl;
var xUrl = 'https://twitter.com/intent/tweet?url=' + pageUrl + '&text=' + pageTitle;
var liUrl = 'https://www.linkedin.com/sharing/share-offsite/?url=' + pageUrl;
var mailUrl = 'mailto:?subject=' + pageTitle + '&body=Check%20out%20this%20page%3A%20' + pageUrl;
var shareHtml = $(
'<div class="gw-share-bar">' +
'<span class="gw-share-label">Share this page:</span>' +
'<div class="gw-share-buttons">' +
'<a class="gw-share-btn gw-share-fb" href="' + fbUrl + '" target="_blank" rel="noopener noreferrer" title="Share on Facebook">Facebook</a>' +
'<a class="gw-share-btn gw-share-x" href="' + xUrl + '" target="_blank" rel="noopener noreferrer" title="Share on X">X (Twitter)</a>' +
'<a class="gw-share-btn gw-share-li" href="' + liUrl + '" target="_blank" rel="noopener noreferrer" title="Share on LinkedIn">LinkedIn</a>' +
'<a class="gw-share-btn gw-share-email" href="' + mailUrl + '" title="Share via Email">Email</a>' +
'<button type="button" class="gw-share-btn gw-share-copy" title="Copy page link">Copy Link</button>' +
'</div>' +
'</div>'
);
// Copy link click handler
shareHtml.find('.gw-share-copy').on('click', function(e) {
e.preventDefault();
var btn = $(this);
navigator.clipboard.writeText(window.location.href).then(function() {
var origText = btn.text();
btn.text('Copied!').addClass('gw-copied');
setTimeout(function() {
btn.text(origText).removeClass('gw-copied');
}, 2000);
});
});
// Append to the bottom of the article content (just before categories)
$('#mw-content-text').append(shareHtml);
});
/* ========================================================
Help Identify Overlays and Banners
======================================================== */
$(function() {
// 1. Look for marker in gallery captions and overlay matching badge onto thumbnail
$('.gallerybox').each(function() {
var $thumb = $(this).find('.thumb').css('position', 'relative');
if ($(this).find('.gw-unidentified-marker').length > 0) {
$thumb.append('<div class="gw-photo-overlay-tag gw-tag-unidentified">Help Identify</div>');
} else if ($(this).find('.gw-partial-marker').length > 0) {
$thumb.append('<div class="gw-photo-overlay-tag gw-tag-partial">Partially Identified</div>');
} else if ($(this).find('.gw-identified-marker').length > 0) {
$thumb.append('<div class="gw-photo-overlay-tag gw-tag-identified">Identified</div>');
}
});
// 2. On File pages, relocate the Identification Needed banner above the image
if (mw.config.get('wgNamespaceNumber') === 6) { // File namespace
var $banner = $('.gw-needs-id-banner');
var $fileTarget = $('.fullImageLink').first();
if ($banner.length && $fileTarget.length) {
$banner.insertBefore($fileTarget);
}
}
});
/* Smooth scroll from top banner down to comment section */
$(document).on('click', '.gw-needs-id-btn', function(e) {
e.preventDefault();
// Look for the Add Comment button or the comment container
var target = $('button:contains("Add comment")').first();
if (!target.length) {
target = $('.cs-comments, #comments, .ext-commentstreams').first();
}
if (target.length) {
$('html, body').animate({
scrollTop: target.offset().top - 80
}, 600);
} else {
// Fallback: scroll to bottom of content
$('html, body').animate({
scrollTop: $('#mw-content-text').offset().top + $('#mw-content-text').height()
}, 600);
}
});
/* Hide guest callout on Main Page when user is logged in */
$( function () {
var isLoggedIn = ( typeof mw !== 'undefined' && mw.user && !mw.user.isAnon() ) ||
( document.cookie.indexOf( 'gewame_logged_in=1' ) !== -1 ) ||
( $( '#pt-logout' ).length > 0 );
if ( isLoggedIn ) {
$( '.gw-guest-only-box' ).hide();
}
} );