diff --git a/app/javascript/portal/portalHelpers.js b/app/javascript/portal/portalHelpers.js index de1a36548..1f0f24f66 100644 --- a/app/javascript/portal/portalHelpers.js +++ b/app/javascript/portal/portalHelpers.js @@ -68,6 +68,44 @@ export const updateThemeStyles = theme => { setPortalClass(theme); }; +export const openExternalLinksInNewTab = () => { + const { customDomain, hostURL } = window.portalConfig; + const isSameHost = + window.location.href.includes(customDomain) || + window.location.href.includes(hostURL); + + // Modify external links only on articles page + const isOnArticlePage = + isSameHost && document.querySelector('#cw-article-content') !== null; + + document.addEventListener('click', function (event) { + if (!isOnArticlePage) return; + + // Some of the links come wrapped in strong tag through prosemirror + + const isTagAnchor = event.target.tagName === 'A'; + const isParentTagAnchor = + event.target.tagName === 'STRONG' && + event.target.parentNode.tagName === 'A'; + + if (isTagAnchor || isParentTagAnchor) { + const link = isTagAnchor ? event.target : event.target.parentNode; + + const isInternalLink = + link.hostname === window.location.hostname || + link.href.includes(customDomain) || + link.href.includes(hostURL); + + if (!isInternalLink) { + link.target = '_blank'; + link.rel = 'noopener noreferrer'; // Security and performance benefits + // Prevent default if you want to stop the link from opening in the current tab + event.stopPropagation(); + } + } + }); +}; + export const toggleAppearanceDropdown = () => { const dropdown = document.getElementById('appearance-dropdown'); if (!dropdown) return; @@ -183,6 +221,7 @@ export const InitializationHelpers = { }, initialize: () => { + openExternalLinksInNewTab(); if (window.portalConfig.isPlainLayoutEnabled === 'true') { InitializationHelpers.appendPlainParamToURLs(); } else { diff --git a/app/views/layouts/portal.html.erb b/app/views/layouts/portal.html.erb index b6ec6d435..19295aa95 100644 --- a/app/views/layouts/portal.html.erb +++ b/app/views/layouts/portal.html.erb @@ -50,6 +50,8 @@ By default, it renders: window.portalConfig = { portalSlug: '<%= @portal.slug %>', portalColor: '<%= @portal.color %>', + customDomain: '<%= @portal.custom_domain %>', + hostURL: '<%= ENV.fetch('FRONTEND_URL', '') %>', theme: '<%= @theme %>', localeCode: '<%= @locale %>', searchTranslations: {