/** * Nova Gallery Navigation Context * * Stores artwork list context in sessionStorage when a card is clicked, * so the artwork page can provide prev/next navigation without page reload. * * Context shape: * { source, key, ids: number[], index: number, page: string, ts: number } */ (function () { 'use strict'; var STORAGE_KEY = 'nav_ctx'; function getPageContext() { var path = window.location.pathname; var search = window.location.search; // /tag/{slug} var tagMatch = path.match(/^\/tag\/([^/]+)\/?$/); if (tagMatch) return { source: 'tag', key: 'tag:' + tagMatch[1] }; // /browse/{contentType}/{category...} var browseMatch = path.match(/^\/browse\/([^/]+)(?:\/(.+))?\/?$/); if (browseMatch) { var browsePart = browseMatch[1] + (browseMatch[2] ? '/' + browseMatch[2] : ''); return { source: 'browse', key: 'browse:' + browsePart }; } // /search?q=... if (path === '/search' || path.startsWith('/search?')) { var q = new URLSearchParams(search).get('q') || ''; return { source: 'search', key: 'search:' + q }; } // /@{username} var profileMatch = path.match(/^\/@([^/]+)\/?$/); if (profileMatch) return { source: 'profile', key: 'profile:' + profileMatch[1] }; // /members/... if (path.startsWith('/members')) return { source: 'members', key: 'members' }; // home if (path === '/' || path === '/home') return { source: 'home', key: 'home' }; return { source: 'page', key: 'page:' + path }; } function collectIds() { var cards = document.querySelectorAll('article[data-art-id]'); var ids = []; for (var i = 0; i < cards.length; i++) { var raw = cards[i].getAttribute('data-art-id'); var id = parseInt(raw, 10); if (id > 0 && !isNaN(id)) ids.push(id); } return ids; } function saveContext(artId, ids, context) { var index = ids.indexOf(artId); if (index === -1) index = 0; var ctx = { source: context.source, key: context.key, ids: ids, index: index, page: window.location.href, ts: Date.now(), }; try { sessionStorage.setItem(STORAGE_KEY, JSON.stringify(ctx)); } catch (_) { // quota exceeded or private mode — silently skip } } function findArticle(el) { var node = el; while (node && node !== document.body) { if (node.tagName === 'ARTICLE' && node.hasAttribute('data-art-id')) { return node; } node = node.parentElement; } return null; } function init() { // Only act on pages that have artwork cards (not the artwork detail page itself) var cards = document.querySelectorAll('article[data-art-id]'); if (cards.length === 0) return; // Don't inject on the artwork detail page (has #artwork-page mount) if (document.getElementById('artwork-page')) return; var context = getPageContext(); document.addEventListener( 'click', function (event) { var article = findArticle(event.target); if (!article) return; // Make sure click was on or inside the card's link var link = article.querySelector('a[href]'); if (!link) return; var artId = parseInt(article.getAttribute('data-art-id'), 10); if (!artId || isNaN(artId)) return; var currentIds = collectIds(); saveContext(artId, currentIds, context); }, true // capture phase: store before navigation fires ); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();