refactor: split out logic to determine ajaxification into exported method

There was some internal logic in ajaxify that handled special links that
should explicitly not be ajaxified (either it is a null href or should be
loaded as a direct page load, etc.) - this was moved out to an exported
method so it can be consumed by the service worker onmessage listener.

Also since this logic evolved over many years, there were some
duplications and so those have been amended (though I will not guarantee
that it was done bug/regression free!!)
This commit is contained in:
Julian Lam
2024-09-11 10:46:57 -04:00
parent 176f4d0d09
commit fc4f6a4c56

View File

@@ -23,6 +23,60 @@ ajaxify.widgets = { render: render };
if ('scrollRestoration' in history) {
history.scrollRestoration = 'manual';
}
ajaxify.check = (item) => {
/**
* returns:
* true (ajaxify OK)
* false (browser default)
* null (no action)
*/
let urlObj;
let pathname;
try {
urlObj = new URL(item, `${document.location.origin}${config.relative_path}`);
({ pathname } = urlObj);
} catch (e) {
return false;
}
const internalLink = utils.isInternalURI(urlObj, window.location, config.relative_path);
// eslint-disable-next-line no-script-url
const hrefEmpty = href => href === undefined || href === '' || href === 'javascript:;';
if (item instanceof Element && item.getAttribute('data-ajaxify') === 'false') {
if (!internalLink) {
return;
}
return null;
}
// Default behaviour for rss feeds
if (internalLink && pathname.endsWith('.rss')) {
return false;
}
// Default behaviour for sitemap
if (internalLink && String(pathname).startsWith(config.relative_path + '/sitemap') && pathname.endsWith('.xml')) {
return false;
}
// Default behaviour for uploads and direct links to API urls
if (internalLink && ['/uploads', '/assets/', '/api/'].some(function (prefix) {
return String(pathname).startsWith(config.relative_path + prefix);
})) {
return false;
}
// eslint-disable-next-line no-script-url
if (hrefEmpty(urlObj.href) || urlObj.protocol === 'javascript:' || pathname === '#' || pathname === '') {
return null;
}
return true;
};
ajaxify.go = function (url, callback, quiet) {
// Automatically reconnect to socket and re-ajaxify on success
if (!socket.connected && parseInt(app.user.uid, 10) >= 0) {
@@ -512,10 +566,6 @@ $(document).ready(function () {
});
function ajaxifyAnchors() {
function hrefEmpty(href) {
// eslint-disable-next-line no-script-url
return href === undefined || href === '' || href === 'javascript:;';
}
const location = document.location || window.location;
const rootUrl = location.protocol + '//' + (location.hostname || location.host) + (location.port ? ':' + location.port : '');
const contentEl = document.getElementById('content');
@@ -527,9 +577,7 @@ $(document).ready(function () {
return;
}
const href = this.pathname;
const internalLink = utils.isInternalURI(this, window.location, config.relative_path);
const rootAndPath = new RegExp(`^${rootUrl}${config.relative_path}/?`);
const process = function () {
if (!e.ctrlKey && !e.shiftKey && !e.metaKey && e.which === 1) {
@@ -560,35 +608,9 @@ $(document).ready(function () {
}
};
if (this.getAttribute('data-ajaxify') === 'false') {
if (!internalLink) {
return;
}
return e.preventDefault();
}
// Default behaviour for rss feeds
if (internalLink && href && href.endsWith('.rss')) {
return;
}
// Default behaviour for sitemap
if (internalLink && href && String(_self.pathname).startsWith(config.relative_path + '/sitemap') && href.endsWith('.xml')) {
return;
}
// Default behaviour for uploads and direct links to API urls
if (internalLink && ['/uploads', '/assets/', '/api/'].some(function (prefix) {
return String(_self.pathname).startsWith(config.relative_path + prefix);
})) {
return;
}
// eslint-disable-next-line no-script-url
if (hrefEmpty(this.href) || this.protocol === 'javascript:' || href === '#' || href === '') {
return e.preventDefault();
}
const check = ajaxify.check(this);
switch (check) {
case true: {
if (app.flags && app.flags.hasOwnProperty('_unsaved') && app.flags._unsaved === true) {
if (e.ctrlKey) {
return;
@@ -606,6 +628,16 @@ $(document).ready(function () {
}
process.call(_self);
break;
}
case null: {
e.preventDefault();
break;
}
// default is default browser behaviour
}
});
}