diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index cd251194aa..1b61699c6e 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -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,52 +608,36 @@ $(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(); - } - - if (app.flags && app.flags.hasOwnProperty('_unsaved') && app.flags._unsaved === true) { - if (e.ctrlKey) { - return; - } - - require(['bootbox'], function (bootbox) { - bootbox.confirm('[[global:unsaved-changes]]', function (navigate) { - if (navigate) { - app.flags._unsaved = false; - process.call(_self); + const check = ajaxify.check(this); + switch (check) { + case true: { + if (app.flags && app.flags.hasOwnProperty('_unsaved') && app.flags._unsaved === true) { + if (e.ctrlKey) { + return; } - }); - }); - return e.preventDefault(); - } - process.call(_self); + require(['bootbox'], function (bootbox) { + bootbox.confirm('[[global:unsaved-changes]]', function (navigate) { + if (navigate) { + app.flags._unsaved = false; + process.call(_self); + } + }); + }); + return e.preventDefault(); + } + + process.call(_self); + break; + } + + case null: { + e.preventDefault(); + break; + } + + // default is default browser behaviour + } }); }