From 81ea45e5cf91274505cbcf8e6d01a5949e5736a9 Mon Sep 17 00:00:00 2001 From: Renoir Boulanger Date: Wed, 30 Oct 2024 14:45:00 -0400 Subject: [PATCH] WIP --- static/assets/js/link-manipulation.mjs | 120 +++++++++++++++++++++++++ static/main.mjs | 13 +++ 2 files changed, 133 insertions(+) create mode 100644 static/assets/js/link-manipulation.mjs diff --git a/static/assets/js/link-manipulation.mjs b/static/assets/js/link-manipulation.mjs new file mode 100644 index 0000000000..528a9469e7 --- /dev/null +++ b/static/assets/js/link-manipulation.mjs @@ -0,0 +1,120 @@ + +/** + * @typedef {Object} RouteComponent + * @property {string} path - Route path pattern + * @property {Object} regex - Regular expression matchers + * @property {Object} components - Route components + * @property {Object} instances - Component instances + * @property {string} name - Route name + * @property {Object} meta - Route metadata + * @property {Object} props - Route properties + */ + +/** + * @typedef {Object} RouteObject + * @property {string} name - Name identifier for the route + * @property {Object} meta - Metadata associated with the route + * @property {string} path - Raw path string + * @property {string} hash - URL hash fragment + * @property {Object} query - Query parameters + * @property {Object} params - Route parameters + * @property {string} params.pathMatch - Matched path string + * @property {string} fullPath - Complete path including parameters + * @property {RouteComponent[]} matched - Array of matched route components + */ + +/** + * Something to do when Vue router navigates. + * + * I had an idea about this, but I forgotten it. + * Probably something to do with external links and white list. + * + * @param {RouteObject} _r + */ +const onNavigateVueRouteChange = (_r) => { + const { path = '' } = _r + console.log(`navigated to ${path}\n`, _r) +} + + +/** + * Things to do client-side with links. + * + * @param {WindowProxy} w + */ +const main = (w) => { + const { console, location } = w + + /** + * Handle click on anchor, but only for external links. + * That should be separate from Vue's Router events. + * + * @param {MouseEvent} _evt + */ + const onNavigateNativeAnchor = (_evt) => { + if (_evt.target.tagName !== 'A') { + return + } + if (Reflect.has(_evt.target, '__vue__')) { + // Do nothing when it's Vue, let's use onNavigateVueRouteChange + return + } + const _href = _evt.target.getAttribute('href') + // console.log(`onNavigateNativeAnchor\n`, { href: _href, target: _evt.target }) + } + + /** + * + * @param {HTMLAnchorElement} a + */ + const maybeAppendSlash = (a) => { + const href = a.getAttribute('href') + if (/\/$/.test(href) === false) { + a.setAttribute('href', href + '/') + } + } + + /** + * When not on renoirboulanger.com, show the canonical link. + * + * @param {HTMLAnchorElement} a + */ + const unHideCanonicalLinkOnNonProduction = (a) => { + if (/^renoirboulanger\.com/.test(location.hostname)) { + // Hostname is renoirboulanger.com therefore it is production + return; + } + const href = a.getAttribute('href') + if ( + href.startsWith('https://renoirboulanger.com') && + a.classList.contains('canonical-link') + ) { + a.classList.remove('hidden') + } + } + + const forEachAnchorElements = (e) => { + maybeAppendSlash(e) + unHideCanonicalLinkOnNonProduction(e) + } + [...w.document.querySelectorAll('a')].forEach((a) => forEachAnchorElements(a)) + + /** ---------------------------------------------------------------------- */ + + /** + * https://stackoverflow.com/questions/46402809/vuejs-event-on-route-change + * + * $router.history.listen((newLocation) => {console.log(newLocation);}) + */ + if (Reflect.has(w, '__nuxt') === true) { + const history = w.__nuxt.__vue__._router.history + if (history) { + history.listen(onNavigateVueRouteChange) + } + } + + w.document.addEventListener('click', onNavigateNativeAnchor); + +} + +export default main diff --git a/static/main.mjs b/static/main.mjs index 53f2f6f104..765406dfbf 100644 --- a/static/main.mjs +++ b/static/main.mjs @@ -5,6 +5,17 @@ */ const SITE_ROOT_BASE_URL = await import.meta.url?.replace('main.mjs', '') +const forEachFn = (e) => { + let href = e.getAttribute('href') + if (/\/$/.test(href) === false) { + e.setAttribute('href', href + '/') + } + href = e.getAttribute('href') + const textContent = e.textContent.trim() + console.log(textContent, { href }) +} +// [...document.querySelectorAll('a')].forEach((a) => forEachFn(a)) + const main = async () => { await Promise.resolve() try { @@ -15,6 +26,8 @@ const main = async () => { const message = `We could not load our elements from ./assets/js/register-elements.mjs, let's fail gracefully. Error message: ` + _e console.warn(message) } + const { default: linkManipulation } = await import('./assets/js/link-manipulation.mjs') + linkManipulation(window) }