Skip to content

Commit

Permalink
feat: introduce cssStylesToInject prop for SilverbackIframe
Browse files Browse the repository at this point in the history
  • Loading branch information
Leksat committed Jan 12, 2024
1 parent 56f32d4 commit dbbde74
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 22 deletions.
16 changes: 16 additions & 0 deletions apps/silverback-gatsby/src/templates/webform.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,22 @@ const Webform: React.FC<
marginLeft: '-0.25em',
marginRight: '-0.25em',
}}
cssStylesToInject={
location.search.includes('test-inject-css=true')
? `
/*
comment with special chars
#$@;\`'()*
*/
* {
color: green;
}
.form-item-optional-text-field {
margin-bottom: 200px;
}
`
: undefined
}
/>
</StandardLayout>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,23 +82,11 @@
},
};

// Ask parent for the base URL to adjust links.
waitForParentIframe(function (parentIFrame) {
parentIFrame.sendMessage({ action: 'getBaseUrl' }, '*');
parentIFrame.sendMessage({ action: 'init' }, '*');
});

// Update links using the given base URL.
window.addEventListener('message', (event) => {
// The message looks like this:
// [iFrameSizer]message:"silverback-iframe-base-url:http://localhost:8000"
var prefix = '[iFrameSizer]message:"silverback-iframe-base-url:';
if (typeof event.data !== 'string' || event.data.indexOf(prefix) !== 0) {
return;
}
var baseUrl = event.data.substr(
prefix.length,
event.data.length - prefix.length - 1,
);
var updateBaseUrlInLinks = (baseUrl) => {
$('a:visible').each(function () {
var $this = $(this);
var href = $this.attr('href');
Expand Down Expand Up @@ -132,5 +120,58 @@
});
// This class is used by integration tests.
$('body').addClass('silverback-iframe-links-processed');
};

var injectCssStyles = (styles) => {
var id = 'silverback-iframe-injected-styles';
var el = document.getElementById(id);
if (!el) {
el = document.createElement('style');
el.id = id;
document.head.appendChild(el);
}
el.textContent = styles;
};

window.addEventListener('message', (event) => {
var parsed = parseMessage(event.data);
if (!parsed) {
return;
}
if (parsed.type === 'init') {
updateBaseUrlInLinks(parsed.baseUrl);
if (parsed.injectStyles) {
injectCssStyles(parsed.injectStyles);
}
}
});

/**
*
* @param {string} message
* @returns {{type: 'init', baseUrl: string, injectStyles: string | undefined} | null}
*/
function parseMessage(message) {
if (typeof message !== 'string') {
return null;
}
var prefix = '[iFrameSizer]message:';
if (!message.startsWith(prefix)) {
return null;
}
var parsed = null;
try {
parsed = JSON.parse(message.substring(prefix.length));
} catch (e) {
return null;
}
if (
typeof parsed !== 'object' ||
typeof parsed.silverbackIframe !== 'object' ||
parsed.silverbackIframe.type !== 'init'
) {
return null;
}
return parsed.silverbackIframe;
}
})(jQuery, Drupal, drupalSettings);
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ type OwnProps = {
buildMessages: (htmlMessages: Array<string>) => JSX.Element | null;
redirect: (url: string, htmlMessages?: Array<string>) => void;
scroll?: (to: string, iframeWrapper: HTMLElement) => void;
/**
* Not recommended for using in production.
* Because injecting CSS takes time and produces flashing.
*/
cssStylesToInject?: string;
};

type Props = OwnProps & IframeResizer.IframeResizerProps;
Expand All @@ -19,6 +24,7 @@ export const SilverbackIframe = ({
buildMessages,
redirect,
scroll,
cssStylesToInject,
...iframeResizerProps
}: Props) => {
const silverbackIframeReference = useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -50,9 +56,15 @@ export const SilverbackIframe = ({
if (!isIframeCommand(message)) {
return;
}
if (message.action === 'getBaseUrl') {
if (message.action === 'init') {
iframeRef.current?.sendMessage(
`silverback-iframe-base-url:${window.location.origin}`,
{
silverbackIframe: {
type: 'init',
baseUrl: window.location.origin,
injectStyles: cssStylesToInject,
},
},
'*',
);
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ const sets = [
result: false,
},
{
case: 'getBaseUrl',
data: { action: 'getBaseUrl' },
case: 'init',
data: { action: 'init' },
result: true,
},
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export type IframeCommandGetBaseUrl = {
action: 'getBaseUrl';
export type IframeCommandInit = {
action: 'init';
};

export type IframeCommandRedirect = {
Expand All @@ -20,14 +20,17 @@ export type IframeCommandScroll = {
};

export type IframeCommand =
| IframeCommandGetBaseUrl
| IframeCommandInit
| IframeCommandRedirect
| IframeCommandOther
| IframeCommandScroll;

export const isIframeCommand = (variable: any): variable is IframeCommand => {
if (typeof variable === 'object' && typeof variable.action === 'string') {
if (['getBaseUrl', 'scroll'].includes(variable.action)) {
if (variable.action === 'init') {
return true;
}
if (variable.action === 'scroll' && typeof variable.scroll === 'string') {
return true;
}
if (
Expand Down
2 changes: 2 additions & 0 deletions packages/tests/silverback-gatsby/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
"test:integration": "playwright install chromium && pnpm test:readonly && pnpm test:mutating",
"test:readonly": "playwright test --pass-with-no-tests",
"test:mutating": "playwright test --pass-with-no-tests -c playwright.config.mutating.ts",
"headed:readonly": "pnpm test:readonly --headed",
"headed:mutating": "pnpm test:mutating --headed",
"dev:readonly": "DEBUG=pw:api pnpm test:readonly --ui",
"dev:mutating": "DEBUG=pw:api pnpm test:mutating --ui"
}
Expand Down
29 changes: 29 additions & 0 deletions packages/tests/silverback-gatsby/specs/webform.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { gatsby } from '@amazeelabs/silverback-playwright';
import { expect, test } from '@playwright/test';

import { getIframe } from '../../silverback-drupal/common';

test('injected CSS styles', async ({ page }) => {
// Check if it isn't green by default.
await page.goto(`${gatsby.baseUrl}/en/form/for-testing-confirmation-options`);
await expect((await getIframe(page)).locator('h1')).not.toHaveCSS(
'color',
'rgb(0, 128, 0)',
);

// Inject CSS.
await page.goto(
`${gatsby.baseUrl}/en/form/for-testing-confirmation-options?test-inject-css=true`,
);
// Check if it's green.
await expect((await getIframe(page)).locator('h1')).toHaveCSS(
'color',
'rgb(0, 128, 0)',
);
// Check if we have additional margin at the bottom of the field.
await expect(
(await getIframe(page)).locator('.form-item-optional-text-field'),
).toHaveCSS('margin-bottom', '200px');
// Check if the iframe was resized. We should still see the Submit button.
await expect((await getIframe(page)).locator('text=Submit')).toBeVisible();
});

0 comments on commit dbbde74

Please sign in to comment.