diff --git a/README.md b/README.md index 3035d9c..3d8b3db 100644 --- a/README.md +++ b/README.md @@ -141,9 +141,29 @@ If you wish to make the editing experience faster you can register for ```onSave #### Enable Show changes while editing -You will need to subscribe to an ```onEditChange``` event that will send blocks or metadata changes +You will need to subscribe to an ```onEditChange``` event that will call the callback with the updated data. -TODO: not implemented yet. +The `onEditChange` method listens for changes in the Hydra and triggers a callback with updated data. +The 'data' object follows the same format as you get from the [ploneClient](https://6.docs.plone.org/volto/client/quick-start.html?highlight=data#query-or-mutation-options-factories). + +`onEditChange` takes following args: +| Args | Description | +| :-----------:| :-------| +| *callback* | A function to call with the updated data when a change is detected. | + +Usage: +```js +// the initial data (from ploneClient) +const initialData = data; + +// Define the callback function +function handleEditChange(updatedData) { + console.log('Updated data:', updatedData); +} + +// Set up the onEditChange listener +onEditChange(initialData, handleEditChange); +``` #### Enable Managing Blocks directly on your frontend diff --git a/hydra.js b/hydra.js index 4e754ae..282b814 100644 --- a/hydra.js +++ b/hydra.js @@ -29,7 +29,19 @@ class Bridge { } }); } - + onEditChange(callback) { + window.addEventListener('message', (event) => { + if (event.origin === this.adminOrigin) { + if (event.data.type === 'FORM') { + if (event.data.data) { + callback(event.data.data); + } else { + throw new Error('No form data has been sent from the adminUI'); + } + } + } + }); + } async get_token() { if (this.token !== null) { return this.token; @@ -130,3 +142,13 @@ export async function getToken() { } return ''; } +/** + * Enable the frontend to listen for changes in the admin and call the callback with updated data + * @param {*} initialData + * @param {*} callback + */ +export function onEditChange(callback) { + if (bridgeInstance) { + bridgeInstance.onEditChange(callback); + } +} diff --git a/packages/volto-hydra/src/components/Iframe/View.jsx b/packages/volto-hydra/src/components/Iframe/View.jsx index 6b54beb..92b7907 100644 --- a/packages/volto-hydra/src/components/Iframe/View.jsx +++ b/packages/volto-hydra/src/components/Iframe/View.jsx @@ -4,27 +4,33 @@ import { useSelector } from 'react-redux'; import Cookies from 'js-cookie'; import './styles.css'; -const Iframe = () => { - const [url, setUrl] = useState(''); +function isValidUrl(string) { + try { + new URL(string); + return true; + } catch (error) { + console.error(error); + return false; + } +} - const [src, setSrc] = useState(''); +const Iframe = () => { const history = useHistory(); const token = useSelector((state) => state.userSession.token); - + const form = useSelector((state) => state.form.global); const getDefualtUrlFromEnv = () => process.env['RAZZLE_DEFAULT_IFRAME_URL'] || (typeof window !== 'undefined' && window.env['RAZZLE_DEFAULT_IFRAME_URL']); - useEffect(() => { - const defaultUrl = getDefualtUrlFromEnv() || 'http://localhost:3002'; // fallback if env is not set - const savedUrl = Cookies.get('iframe_url'); - const initialUrl = savedUrl - ? `${savedUrl}${window.location.pathname.replace('/edit', '')}` - : `${defaultUrl}${window.location.pathname.replace('/edit', '')}`; - - setUrl(initialUrl); - setSrc(initialUrl); + const defaultUrl = getDefualtUrlFromEnv() || 'http://localhost:3002'; // fallback if env is not set + const savedUrl = Cookies.get('iframe_url'); + const initialUrl = savedUrl + ? `${savedUrl}${history.location.pathname.replace('/edit', '')}` + : `${defaultUrl}${history.location.pathname.replace('/edit', '')}`; + const [url, setUrl] = useState(initialUrl); + const [src, setSrc] = useState(initialUrl); + useEffect(() => { // Listen for messages from the iframe const initialUrlOrigin = new URL(initialUrl).origin; window.addEventListener('message', (event) => { @@ -51,15 +57,28 @@ const Iframe = () => { }); }, [token]); + useEffect(() => { + if (Object.keys(form).length > 0 && isValidUrl(initialUrl)) { + // Send the form data to the iframe + const origin = new URL(initialUrl).origin; + document + .getElementById('previewIframe') + .contentWindow.postMessage({ type: 'FORM', data: form }, origin); + } + }, [form, initialUrl]); + const handleUrlChange = (event) => { setUrl(event.target.value); }; const handleNavigateToUrl = (givenUrl = '') => { // Update adminUI URL with the new URL + if (!isValidUrl(givenUrl) && !isValidUrl(url)) { + return; + } const formattedUrl = givenUrl ? new URL(givenUrl) : new URL(url); - const newUrl = formattedUrl.href; - setSrc(newUrl); + // const newUrl = formattedUrl.href; + // setSrc(newUrl); const newOrigin = formattedUrl.origin; Cookies.set('iframe_url', newOrigin, { expires: 7 });