Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TUP-703 TACC Home Banner Links Open in New Window #805

Merged
merged 7 commits into from
Mar 1, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -4,65 +4,24 @@
*/
const SHOULD_DEBUG = window.DEBUG;

/**
* Function to perform after setting link target
* @callback setTargetCallback
* @param {HTMLElement} link
*/

/**
* Set external links (automatically discovered) to open in new tab
* @param {object} [options] - Optional parameters
* @param {array.<string>} [options.pathsToExernalSite=[]] - (DEPRECATED) A list of relative URL paths that should be treated like external URLs
* @param {array.<string|RegExp>} [options.pathsToForceSetTarget=[]] - A list of relative URL paths (or patterns) that should trigger setting a target
* @param {HTMLElement|Document} [options.scopeElement=document] - The element within which to search for links
* @param {setTargetCallback} [options.setTargetCallback] - A callback for after a target is set
*/
export default function findLinksAndSetTargets(options) {
const defaults = {
target: '_blank',
pathsToExernalSite: [],
pathsToForceSetTarget: [],
scopeElement: document
}
const {target, pathsToExernalSite, scopeElement, setTargetCallback} = {...defaults, ...options};
let {pathsToForceSetTarget} = {...defaults, ...options};

if ( pathsToExernalSite.length && ! pathsToForceSetTarget.length ) {
pathsToForceSetTarget = pathsToExernalSite;
}

export default function findLinksAndSetTargets() {
const links = scopeElement.getElementsByTagName('a');
const baseDocumentHost = document.location.host;
const baseDocumentHostWithSubdomain= `www.${baseDocumentHost}`;

[ ...links ].forEach( function setTarget(link) {
if ( ! link.href) {
return false;
}
if (link.href.indexOf('javascript') === 0) {
return false;
}

const isMailto = (link.href.indexOf('mailto:') === 0);
const shouldForceSetTarget = pathsToForceSetTarget.some(path => {
let shouldForce;
if (path instanceof RegExp) {
shouldForce = path.test(link.pathname);
}
if (typeof path === 'string') {
shouldForce = _doPathsMatch(path, link.pathname);
}
if (SHOULD_DEBUG && shouldForce) {
console.debug(`Path "${link.pathname}" matches "${path}"`);
}
return shouldForce;
});
// FAQ: I am literally double-checking, because I don't trust JavaScript
const isExternal = (link.origin !== document.location.origin);
const isInternal = (link.host === document.location.host);
const shouldSetTarget = shouldForceSetTarget || (
! isInternal && isExternal && ! isMailto
);

if ( shouldSetTarget ) {
const isInternalLink = link.host === baseDocumentHost || link.host === baseDocumentHostWithSubdomain

if (!isInternalLink || isMailto ) {
if (link.target !== '_blank') {
link.target = '_blank';
if (SHOULD_DEBUG) {
Expand All @@ -78,21 +37,3 @@ export default function findLinksAndSetTargets(options) {
}
});
}

/**
* Does redirect path match link path (ignoring "/" link path)
* @param {string} redirectPath - A path known to redirect to an external site
* @param {string} testLinkPath - A path found on the page being updated
*/
function _doPathsMatch(redirectPath, testLinkPath) {
if (testLinkPath === '/') {
return false;
}

const isMatch = redirectPath === testLinkPath
|| redirectPath === testLinkPath.slice(1)
|| redirectPath === testLinkPath.slice(0, -1)
|| redirectPath === testLinkPath.slice(1).slice(0, -1);

return isMatch;
}