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

feat(TMC-27): Opening links in new tab #3936

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/article-skeleton/src/article-skeleton.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import insertDropcapIntoAST from "./contentModifiers/dropcap-util";
import insertNewsletterPuff from "./contentModifiers/newsletter-puff";
import insertInlineAd from "./contentModifiers/inline-ad";
import { getIsLiveOrBreakingFlag } from "./data-helper";
import shouldIncludeDisclaimer from "./contentModifiers/should-include-disclaimer";

export const reduceArticleContent = (content, reducers) =>
content &&
Expand Down Expand Up @@ -149,12 +150,15 @@ const ArticleSkeleton = ({
const articleUrl =
hostName && canonicalUrl ? `${hostName}${canonicalUrl}` : url;

//tu
const articleContentReducers = [
shouldIncludeDisclaimer,
insertDropcapIntoAST(template, dropcapsDisabled),
insertNewsletterPuff(section, isPreview, expirableFlags),
insertInlineAd,
tagLastParagraph
];
//salje u article body
const newContent = reduceArticleContent(content, articleContentReducers);

const HeaderAdContainer = getHeaderAdStyles(template);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const contentChildren = [
{
name: 'paragraph',
children: [
{
name: 'link',
attributes: {
href: 'https://www.example.com',
},
children: [],
},
],
},
];

export const setExternalLinkTargets = (children) => {
const clonedChildren = [...children];
const checkAndSetLinkTarget = (elements) => {
elements.forEach((el) => {
// Check if element is a link or an interactive element with a URL
if (
(el.name === 'link' || (el.name === 'interactive' && el.attributes?.element?.value === 'times-travel-cta'))
) {
const href = el.name === 'interactive'
? el.attributes?.element?.attributes?.url ?? ''
: el.attributes?.href ?? '';

// If the link is external, set target to _blank
if (href && !href.startsWith('https://www.thetimes.co.uk') && !href.startsWith('https://www.thetimes.com')) {
el.attributes = {
...el.attributes,
target: '_blank',
};
}
}

// Recursively check for nested children
if (el.children && el.children.length) {
checkAndSetLinkTarget(el.children);
}
});
};

checkAndSetLinkTarget(clonedChildren);
return clonedChildren;
};

const updatedChildren = setExternalLinkTargets(contentChildren);
console.log(updatedChildren);

export default setExternalLinkTargets;
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import setExternalLinkTargets from './setExternalLinkTargets';

const newDisclaimerText = {
name: 'paragraph',
children: [
{
name: 'italic',
children: [
{
name: 'text',
children: [],
attributes: {
value: 'All recommendations within this article are informed by expert editorial opinion. If you click on a link in this story we may earn affiliate revenue.'
}
}
]
}
]
}


const oldDisclaimerTexts = [
'This article contains affiliate links that can earn us revenue',
'This article contains affiliate links that may earn us revenue',
'This article contains affiliate links which may earn us revenue',
'This article contains affiliate links, which can earn us revenue',
'This article contains affiliate links, which may earn us revenue',
'This article contains affiliate links, which may earn�us revenue',
'This article contains affiliate links, which�may earn us revenue',
'This article contains�affiliate links, which may earn us revenue',
'This article contains affiliate links',
'This article contains links that can earn us revenue',
'This article contains links which may earn us revenue',
'This article contains links, which can earn us revenue',
'This article contains links, which may earn us revenu',
'This article contains links from which we may earn revenue',
];

const shouldIncludeDisclaimer = (children) => {
const clonedChildren = [...children];
let affiliateLinkExist = false;
let affiliateDisclaimerExist = false;
const checkForAffiliate = (elements) => { // eslint-disable-next-line array-callback-return, consistent-return
elements.some((el) => {
// Check if disclaimer text already exists.
if (
!affiliateDisclaimerExist &&
(el.name === 'text' ||
(el.name === 'interactive' && el.attributes?.element?.value === 'times-text-collapse'))
) {
const text = (el.name === 'interactive') ? (el.attributes?.element?.attributes?.disclaimer_text ?? '') : (el.attributes?.value ?? '');
if (oldDisclaimerTexts.some((contentText) => text.includes(contentText))) {
affiliateDisclaimerExist = true;
}
}
if (affiliateDisclaimerExist) {
return true;
}
// Move to next iteration if element is not link, and doesn't have children.
if (
el.name !== 'interactive' &&
el.name !== 'link' &&
(el.children === undefined || !el.children.length)
) {
return false;
}
// Check for affiliate links.
if (
!affiliateLinkExist &&
((el.name === 'interactive' && el.attributes?.element?.value === 'times-travel-cta') ||
el.name === 'link')
) {
const href = (el.name === 'interactive') ? (el.attributes?.element?.attributes?.url ?? '') : (el.attributes?.href ?? '');
if (
!href ||
href.startsWith('https://www.thetimes.co.uk') ||
href.startsWith('https://www.thetimes.com')
) {
return false;
}
affiliateLinkExist = true;
}
// Check recursively for nested children.
if (el.children !== undefined && el.children.length) {
checkForAffiliate(el.children);
}
});
return {
affiliateLinkExist,
affiliateDisclaimerExist
};
}
const affiliatesCheck = checkForAffiliate(clonedChildren);
// Add disclaimer after first paragraph (in case disclaimer doesn't already exist).
if (!affiliatesCheck.affiliateDisclaimerExist && affiliatesCheck.affiliateLinkExist) {
const firstParagraph = clonedChildren.find((el) => el.name === 'paragraph');
clonedChildren.splice(clonedChildren.indexOf(firstParagraph) + 1, 0, newDisclaimerText);
}
return clonedChildren;
}
export default shouldIncludeDisclaimer;