125 lines
3.6 KiB
JavaScript
125 lines
3.6 KiB
JavaScript
/**
|
|
* 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 <a> 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();
|
|
}
|
|
})();
|