From 58850cd6248adb0d27a6d08b2f636a2beecab4c5 Mon Sep 17 00:00:00 2001 From: "david.griffon" Date: Tue, 3 Dec 2024 10:44:04 +0100 Subject: [PATCH 1/2] Change preview loading --- pom.xml | 2 +- .../IframeViewer/IframeViewer.jsx | 88 +++++++++---------- 2 files changed, 41 insertions(+), 49 deletions(-) diff --git a/pom.xml b/pom.xml index d7fb0fa29..d0a947b86 100644 --- a/pom.xml +++ b/pom.xml @@ -48,7 +48,7 @@ system build:production osgi.extender;filter:="(osgi.extender=org.jahia.bundles.blueprint.extender.config)" - MCwCFHCtnj+P1xhvdTUewCQnP1MOcum5AhRASPcyKZR6Sycr4VEBqyy3z4DkTg== + MCwCFHCtnj+P1xhvdTUewCQnP1MOcum5AhRASPcyKZR6Sycr4VEBqyy3z4DkTg== app-shell=2.7,graphql-dxm-provider=2.19.1,jcontent=2.9 6.9 diff --git a/src/javascript/editorTabs/EditPanelContent/Preview/PreviewViewers/IframeViewer/IframeViewer.jsx b/src/javascript/editorTabs/EditPanelContent/Preview/PreviewViewers/IframeViewer/IframeViewer.jsx index 370188bb8..96329c5d0 100644 --- a/src/javascript/editorTabs/EditPanelContent/Preview/PreviewViewers/IframeViewer/IframeViewer.jsx +++ b/src/javascript/editorTabs/EditPanelContent/Preview/PreviewViewers/IframeViewer/IframeViewer.jsx @@ -1,4 +1,4 @@ -import React, {useCallback, useEffect, useRef, useState} from 'react'; +import React, {useEffect, useRef, useState} from 'react'; import PropTypes from 'prop-types'; import {Paper} from '@material-ui/core'; import styles from './IframeViewer.scss'; @@ -49,61 +49,50 @@ function loadAssets(assets, iframeDocument) { return Promise.all(assets.map(asset => loadAsset(asset, iframeHeadEl))); } -function writeInIframe(html, iframeWindow) { - return new Promise((resolve, reject) => { - iframeWindow.document.open(); - iframeWindow.onload = resolve; - iframeWindow.onerror = reject; - iframeWindow.document.write(html); - iframeWindow.document.close(); - }); -} - export const IframeViewer = ({previewContext, data, onContentNotFound}) => { const [loading, setLoading] = useState(true); const editorContext = useContentEditorContext(); const {t} = useTranslation('content-editor'); const iframeRef = useRef(null); + const onLoadTimeoutRef = useRef(null); + let displayValue = data && data.nodeByPath && data.nodeByPath.renderedContent ? data.nodeByPath.renderedContent.output : ''; + if (displayValue === '') { + displayValue = t('label.contentManager.contentPreview.noViewAvailable'); + } - const renderIFrame = useCallback(() => { - const element = iframeRef.current; - - if (!element) { - return; - } - - setLoading(true); - let displayValue = data && data.nodeByPath && data.nodeByPath.renderedContent ? data.nodeByPath.renderedContent.output : ''; - if (displayValue === '') { - displayValue = t('label.contentManager.contentPreview.noViewAvailable'); + useEffect(() => { + // Add a timer to always remove the loader and click on links after 5 seconds + onLoadTimeoutRef.current = setTimeout(() => { + console.debug('iframe onLoad did not trigger, remove loader and disable click events'); + const element = iframeRef.current; + const iframeWindow = element.contentWindow || element; + iframeWindow.document.body.setAttribute('style', 'pointer-events: none'); + setLoading(false); + }, 5000); + return () => clearTimeout(onLoadTimeoutRef.current); + }, []); + + const onLoad = () => { + try { + console.debug('Preview loaded, add assets and remove loader'); + const element = iframeRef.current; + const iframeWindow = element.contentWindow || element; + iframeWindow.document.body.setAttribute('style', 'pointer-events: none'); + + const assets = data && data.nodeByPath && data.nodeByPath.renderedContent ? + data.nodeByPath.renderedContent.staticAssets : []; + loadAssets(assets, iframeWindow.document); + + if (previewContext.requestAttributes) { + zoom(iframeWindow.document, onContentNotFound, editorContext); + } + } catch (e) { + console.error('Error while processing preview', e); } - const iframeWindow = element.contentWindow || element; - writeInIframe(displayValue, iframeWindow) - .then(() => { - iframeWindow.document.body.setAttribute('style', 'pointer-events: none'); - }) - .then(() => { - const assets = data && data.nodeByPath && data.nodeByPath.renderedContent ? - data.nodeByPath.renderedContent.staticAssets : - []; - return loadAssets(assets, iframeWindow.document); - }) - .catch(err => console.error('Error in the preview', err)) - .then(() => { - // No zoom on full if no content wrapped in the page - if (previewContext.requestAttributes) { - zoom(iframeWindow.document, onContentNotFound, editorContext); - } - }) - .then(() => { - setLoading(false); - }); - }, [data, editorContext, onContentNotFound, previewContext.requestAttributes, t]); - - useEffect(() => { - renderIFrame(); - }, [renderIFrame]); + setLoading(false); + clearTimeout(onLoadTimeoutRef.current); + }; return ( @@ -112,6 +101,9 @@ export const IframeViewer = ({previewContext, data, onContentNotFound}) => { aria-labelledby="preview-tab" data-sel-role={previewContext.workspace + '-preview-frame'} className={`${styles.iframe} ${loading ? styles.iframeLoading : ''}`} + srcDoc={displayValue} + sandbox="allow-same-origin allow-scripts" + onLoad={onLoad} /> ); From d7b0db04d5abfca72026c3bf565746c5c0a95528 Mon Sep 17 00:00:00 2001 From: "david.griffon" Date: Wed, 4 Dec 2024 17:01:53 +0100 Subject: [PATCH 2/2] QA-14926 : do not load assets for page configuration + avoid flickering effect on content change --- .../PreviewViewers/IframeViewer/IframeViewer.jsx | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/javascript/editorTabs/EditPanelContent/Preview/PreviewViewers/IframeViewer/IframeViewer.jsx b/src/javascript/editorTabs/EditPanelContent/Preview/PreviewViewers/IframeViewer/IframeViewer.jsx index 96329c5d0..0592092bb 100644 --- a/src/javascript/editorTabs/EditPanelContent/Preview/PreviewViewers/IframeViewer/IframeViewer.jsx +++ b/src/javascript/editorTabs/EditPanelContent/Preview/PreviewViewers/IframeViewer/IframeViewer.jsx @@ -61,16 +61,17 @@ export const IframeViewer = ({previewContext, data, onContentNotFound}) => { } useEffect(() => { + setLoading(true); // Add a timer to always remove the loader and click on links after 5 seconds onLoadTimeoutRef.current = setTimeout(() => { console.debug('iframe onLoad did not trigger, remove loader and disable click events'); const element = iframeRef.current; const iframeWindow = element.contentWindow || element; - iframeWindow.document.body.setAttribute('style', 'pointer-events: none'); + iframeWindow?.document?.body?.setAttribute('style', 'pointer-events: none'); setLoading(false); }, 5000); return () => clearTimeout(onLoadTimeoutRef.current); - }, []); + }, [displayValue]); const onLoad = () => { try { @@ -79,9 +80,11 @@ export const IframeViewer = ({previewContext, data, onContentNotFound}) => { const iframeWindow = element.contentWindow || element; iframeWindow.document.body.setAttribute('style', 'pointer-events: none'); - const assets = data && data.nodeByPath && data.nodeByPath.renderedContent ? - data.nodeByPath.renderedContent.staticAssets : []; - loadAssets(assets, iframeWindow.document); + if (previewContext.contextConfiguration !== 'page') { + const assets = data && data.nodeByPath && data.nodeByPath.renderedContent ? + data.nodeByPath.renderedContent.staticAssets : []; + loadAssets(assets, iframeWindow.document); + } if (previewContext.requestAttributes) { zoom(iframeWindow.document, onContentNotFound, editorContext); @@ -112,7 +115,8 @@ export const IframeViewer = ({previewContext, data, onContentNotFound}) => { IframeViewer.propTypes = { previewContext: PropTypes.shape({ workspace: PropTypes.string.isRequired, - requestAttributes: PropTypes.array + requestAttributes: PropTypes.array, + contextConfiguration: PropTypes.string }).isRequired, onContentNotFound: PropTypes.func.isRequired, data: PropTypes.object.isRequired