Skip to content

Commit 73b19e8

Browse files
Merge pull request #13647 from guardian/dark-mode-param-for-ai2html
Add `dark=false` param for in-house interactive embeds
2 parents 2698ed3 + 2ce7721 commit 73b19e8

File tree

3 files changed

+81
-37
lines changed

3 files changed

+81
-37
lines changed

dotcom-rendering/playwright/lib/iframe.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,16 @@ const getIframeBody = async (
1010
return iframeBodyLocator;
1111
};
1212

13-
export { getIframeBody };
13+
const getIframePart = async (
14+
page: Page,
15+
iframeSelector: string,
16+
partSelector: string,
17+
): Promise<Locator> => {
18+
const iframePartLocator = page
19+
.frameLocator(iframeSelector)
20+
.locator(partSelector);
21+
await expect(iframePartLocator).toBeAttached({ timeout: 10_000 });
22+
return iframePartLocator;
23+
};
24+
25+
export { getIframeBody, getIframePart };

dotcom-rendering/playwright/tests/article.embeds.e2e.spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { expect, test } from '@playwright/test';
22
import { cmpAcceptAll } from '../lib/cmp';
3-
import { getIframeBody } from '../lib/iframe';
3+
import { getIframeBody, getIframePart } from '../lib/iframe';
44
import { waitForIsland } from '../lib/islands';
55
import { loadPage } from '../lib/load-page';
66
import { expectToBeVisible } from '../lib/locators';
@@ -43,9 +43,10 @@ test.describe('Embeds', () => {
4343

4444
await waitForIsland(page, 'InteractiveBlockComponent');
4545
await expect(
46-
await getIframeBody(
46+
await getIframePart(
4747
page,
4848
'[data-testid="interactive-element-LA%20Rams%20dead%20cap%20numbers"] > iframe',
49+
'.title',
4950
),
5051
).toContainText('The Rams’ dead cap numbers for 2020');
5152
});

dotcom-rendering/src/components/InteractiveBlockComponent.importable.tsx

Lines changed: 65 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -326,46 +326,84 @@ export const InteractiveBlockComponent = ({
326326
const placeholderLinkRef = useRef<HTMLAnchorElement>(null);
327327
const [loaded, setLoaded] = useState(false);
328328
const { darkModeAvailable } = useConfig();
329+
330+
// Define some one-time flags
331+
const isDatawrapperGraphic =
332+
url && url.includes('interactive.guim.co.uk/datawrapper')
333+
? true
334+
: false;
335+
336+
const isUploaderEmbedPath =
337+
url && url.includes('interactive.guim.co.uk/uploader/embed/')
338+
? true
339+
: false;
340+
341+
const scriptUrlIsBoot =
342+
scriptUrl &&
343+
scriptUrl.includes(
344+
'interactive.guim.co.uk/embed/iframe-wrapper/0.1/boot.js',
345+
)
346+
? true
347+
: false;
348+
329349
useOnce(() => {
330350
// We've brought the behavior from boot.js into this file to avoid loading 2 extra scripts
331-
if (
332-
scriptUrl ===
333-
'https://interactive.guim.co.uk/embed/iframe-wrapper/0.1/boot.js' &&
334-
url &&
335-
placeholderLinkRef.current
336-
) {
351+
352+
// Define additional one-time flags - these depend on window/document objects
353+
const isRunningInWebEnvironment =
354+
!document.querySelector('.ios') &&
355+
!document.querySelector('.android')
356+
? true
357+
: false;
358+
359+
const prefersDarkScheme = window.matchMedia(
360+
'(prefers-color-scheme: dark)',
361+
).matches;
362+
const requiresDarkMode =
363+
darkModeAvailable && prefersDarkScheme ? true : false;
364+
365+
if (url && scriptUrlIsBoot && placeholderLinkRef.current) {
366+
// Prepare for graphic url dynamic updates
367+
const graphicUrl = new URL(url);
368+
369+
// Begin creating new iframe element
337370
const iframe = document.createElement('iframe');
338371
iframe.style.width = '100%';
339372
iframe.style.border = 'none';
340373
iframe.height = decideHeight(role).toString();
341374
iframe.title = caption ?? alt ?? 'Interactive Content';
342-
if (url.startsWith('http:')) {
343-
iframe.src = url.replace('http:', 'https:');
344-
} else {
345-
iframe.src = url;
346-
}
347375

348-
// Datawrapper-specific fix to suppress scrollbars appearing
349-
if (url.includes('datawrapper')) {
376+
// Fix for Datawrapper graphic
377+
if (isDatawrapperGraphic) {
350378
iframe.scrolling = 'no';
351-
// Turn off dark mode for Datawrapper embeds on web
352-
// This should be removed if/when dark mode is implements on the website
353-
if (
354-
!document.querySelector('.ios') &&
355-
!document.querySelector('.android')
356-
) {
357-
const prefersDarkScheme = window.matchMedia(
358-
'(prefers-color-scheme: dark)',
359-
).matches;
360-
const darkMode = darkModeAvailable && prefersDarkScheme;
361-
if (!darkMode) {
362-
iframe.src +=
363-
(iframe.src.includes('?') ? '&' : '?') +
364-
'dark=false';
379+
}
380+
381+
// Fix darkmode for web environment
382+
if (isRunningInWebEnvironment && !requiresDarkMode) {
383+
if (isDatawrapperGraphic || isUploaderEmbedPath) {
384+
// Add the 'dark=false' search param
385+
if (graphicUrl.search.length) {
386+
graphicUrl.search += '&dark=false';
387+
} else {
388+
// Embed URLs without a trailing slash are redirected and the
389+
// search param is lost so we need to add it to the pathname
390+
const hasTrailingSlash = graphicUrl.pathname.endsWith(
391+
'/',
392+
)
393+
? true
394+
: false;
395+
graphicUrl.pathname += hasTrailingSlash ? '' : '/';
396+
graphicUrl.search += '?dark=false';
365397
}
366398
}
367399
}
368400

401+
// Always serve graphic over https, not http
402+
graphicUrl.protocol = 'https:';
403+
404+
// Finalise new iframe element
405+
iframe.src = graphicUrl.href;
406+
369407
setupWindowListeners(iframe);
370408

371409
wrapperRef.current?.prepend(iframe);
@@ -397,13 +435,6 @@ export const InteractiveBlockComponent = ({
397435
}
398436
}, [loaded]);
399437

400-
const isDatawrapperGraphic =
401-
url == undefined
402-
? false
403-
: /^https?:\/\/interactive\.guim\.co\.uk\/datawrapper(-test)?\/embed/.test(
404-
url,
405-
);
406-
407438
return (
408439
<>
409440
<figure

0 commit comments

Comments
 (0)