diff --git a/src/editor/components/ThemerComponent.js b/src/editor/components/ThemerComponent.js index 8d3478a..6069d2b 100644 --- a/src/editor/components/ThemerComponent.js +++ b/src/editor/components/ThemerComponent.js @@ -1,4 +1,4 @@ -import { mergeWith, isEmpty } from 'lodash'; +import { mergeWith, isEmpty, isEqual } from 'lodash'; import { Button, Spinner, TabPanel } from '@wordpress/components'; import { useSelect, dispatch } from '@wordpress/data'; import { useEffect, useState, useMemo } from '@wordpress/element'; @@ -36,12 +36,13 @@ const ThemerComponent = () => { ); }; - const { globalStylesId, baseConfig, userConfig } = useSelect( - ( select ) => { + const { globalStylesId, baseConfig, userConfig, savedUserConfig } = + useSelect( ( select ) => { const { __experimentalGetCurrentGlobalStylesId, __experimentalGetCurrentThemeBaseGlobalStyles, getEditedEntityRecord, + getEntityRecord, } = select( 'core' ); const currentGlobalStylesId = @@ -55,9 +56,13 @@ const ThemerComponent = () => { 'globalStyles', currentGlobalStylesId ), + savedUserConfig: getEntityRecord( + 'root', + 'globalStyles', + currentGlobalStylesId + ), }; - } - ); + } ); /** * Returns merged base and user configs @@ -70,6 +75,13 @@ const ThemerComponent = () => { return merged; }, [ userConfig, baseConfig ] ); + /** + * Determines if the user config is different from the most recently saved config. + */ + const hasUnsavedChanges = useMemo( () => { + return ! isEqual( userConfig, savedUserConfig ); + }, [ userConfig, savedUserConfig ] ); + /** * Fetch new preview CSS whenever config is changed */ @@ -107,6 +119,20 @@ const ThemerComponent = () => { validateThemeJson(); }, [] ); + /** + * Alert user if they try to leave Themer without saving. + */ + useEffect( () => { + // Detecting browser closing + window.onbeforeunload = hasUnsavedChanges + ? () => hasUnsavedChanges + : null; + + return () => { + window.removeEventListener( 'beforeunload', () => {} ); + }; + }, [ hasUnsavedChanges ] ); + /** * saves edited entity data */ @@ -124,14 +150,14 @@ const ThemerComponent = () => { }; /** - * resets updated theme db data back to original theme.json + * Resets theme db data back to the most recently saved config. */ const reset = () => { dispatch( 'core' ).editEntityRecord( 'root', 'globalStyles', globalStylesId, - baseConfig + savedUserConfig ); }; @@ -169,11 +195,13 @@ const ThemerComponent = () => { isSecondary onClick={ () => reset() } text="Reset" + disabled={ ! hasUnsavedChanges } />