From 7c9b19ded74ae16cf849dfa721b4214dd259e80a Mon Sep 17 00:00:00 2001 From: Alex S <17275120+AlexGStapleton@users.noreply.github.com> Date: Wed, 20 Nov 2024 12:03:31 +1300 Subject: [PATCH 1/4] Layouts Block: Prevent Double Page Builder when in Dev Mode --- compat/js/siteorigin-panels-layout-block.js | 65 ++++++++++++-------- compat/js/siteorigin-panels-layout-block.jsx | 13 ++++ 2 files changed, 53 insertions(+), 25 deletions(-) diff --git a/compat/js/siteorigin-panels-layout-block.js b/compat/js/siteorigin-panels-layout-block.js index 32ba0633..1c596967 100644 --- a/compat/js/siteorigin-panels-layout-block.js +++ b/compat/js/siteorigin-panels-layout-block.js @@ -98,11 +98,26 @@ function (_wp$element$Component) { }, { key: "componentWillUnmount", value: function componentWillUnmount() { + var _this3 = this; + this.isStillMounted = false; + this.panelsInitialized = false; if (this.builderView) { this.builderView.off('content_change'); + this.builderView = null; // Remove builder from global builder list. + + if (typeof window.soPanelsBuilderView !== 'undefined') { + window.soPanelsBuilderView = window.soPanelsBuilderView.filter(function (view) { + return view !== _this3.builderView; + }); + } } + + this.panelsContainer = null; + this.previewContainer = null; + this.fetchPreviewTimer = null; + this.state = null; } }, { key: "componentDidUpdate", @@ -130,7 +145,7 @@ function (_wp$element$Component) { }, { key: "setupPanels", value: function setupPanels() { - var _this3 = this; + var _this4 = this; // Should we set up panels? if (this.state.panelsInitialized) { @@ -153,15 +168,15 @@ function (_wp$element$Component) { var panelsData = JSON.parse(JSON.stringify(jQuery.extend({}, this.props.panelsData))); // Disable block selection while dragging rows or widgets. var rowOrWidgetMouseDown = function rowOrWidgetMouseDown() { - if (typeof _this3.props.onRowOrWidgetMouseDown === 'function') { - _this3.props.onRowOrWidgetMouseDown(); + if (typeof _this4.props.onRowOrWidgetMouseDown === 'function') { + _this4.props.onRowOrWidgetMouseDown(); } var rowOrWidgetMouseUp = function rowOrWidgetMouseUp() { jQuery(document).off('mouseup', rowOrWidgetMouseUp); - if (typeof _this3.props.onRowOrWidgetMouseUp === 'function') { - _this3.props.onRowOrWidgetMouseUp(); + if (typeof _this4.props.onRowOrWidgetMouseUp === 'function') { + _this4.props.onRowOrWidgetMouseUp(); } }; @@ -169,18 +184,18 @@ function (_wp$element$Component) { }; this.builderView.on('row_added', function () { - _this3.builderView.$('.so-row-move').off('mousedown', rowOrWidgetMouseDown); + _this4.builderView.$('.so-row-move').off('mousedown', rowOrWidgetMouseDown); - _this3.builderView.$('.so-row-move').on('mousedown', rowOrWidgetMouseDown); + _this4.builderView.$('.so-row-move').on('mousedown', rowOrWidgetMouseDown); - _this3.builderView.$('.so-widget').off('mousedown', rowOrWidgetMouseDown); + _this4.builderView.$('.so-widget').off('mousedown', rowOrWidgetMouseDown); - _this3.builderView.$('.so-widget').on('mousedown', rowOrWidgetMouseDown); + _this4.builderView.$('.so-widget').on('mousedown', rowOrWidgetMouseDown); }); this.builderView.on('widget_added', function () { - _this3.builderView.$('.so-widget').off('mousedown', rowOrWidgetMouseDown); + _this4.builderView.$('.so-widget').off('mousedown', rowOrWidgetMouseDown); - _this3.builderView.$('.so-widget').on('mousedown', rowOrWidgetMouseDown); + _this4.builderView.$('.so-widget').on('mousedown', rowOrWidgetMouseDown); }); this.builderView.render().attach({ container: $panelsContainer @@ -214,16 +229,16 @@ function (_wp$element$Component) { }; this.builderView.on('content_change', function () { - var newPanelsData = _this3.builderView.getData(); + var newPanelsData = _this4.builderView.getData(); - _this3.panelsDataChanged = !SiteOriginIsPanelsEqual(panelsData, newPanelsData); + _this4.panelsDataChanged = !SiteOriginIsPanelsEqual(panelsData, newPanelsData); - if (_this3.panelsDataChanged) { - if (_this3.props.onContentChange && typeof _this3.props.onContentChange === 'function') { - _this3.props.onContentChange(newPanelsData); + if (_this4.panelsDataChanged) { + if (_this4.props.onContentChange && typeof _this4.props.onContentChange === 'function') { + _this4.props.onContentChange(newPanelsData); } - _this3.setState({ + _this4.setState({ loadingPreview: true, previewHtml: '' }); @@ -243,7 +258,7 @@ function (_wp$element$Component) { }, { key: "fetchPreview", value: function fetchPreview(props) { - var _this4 = this; + var _this5 = this; if (!this.isStillMounted) { return; @@ -259,7 +274,7 @@ function (_wp$element$Component) { panelsData: JSON.stringify(this.builderView.getData()) } }).then(function (preview) { - if (!_this4.isStillMounted) { + if (!_this5.isStillMounted) { return; } @@ -267,8 +282,8 @@ function (_wp$element$Component) { jQuery(document).trigger('panels_setup_preview'); }, 1000); - if (fetchRequest === _this4.currentFetchRequest && preview) { - _this4.setState({ + if (fetchRequest === _this5.currentFetchRequest && preview) { + _this5.setState({ previewHtml: preview, loadingPreview: false, previewInitialized: false, @@ -281,16 +296,16 @@ function (_wp$element$Component) { }, { key: "render", value: function render() { - var _this5 = this; + var _this6 = this; var panelsData = this.props.panelsData; var switchToEditing = function switchToEditing() { - _this5.setState({ + _this6.setState({ editing: true }); - var _this = _this5; + var _this = _this6; setTimeout(function () { _this.builderView.trigger('builder_resize'); }); @@ -298,7 +313,7 @@ function (_wp$element$Component) { var switchToPreview = function switchToPreview() { if (panelsData) { - _this5.setState({ + _this6.setState({ editing: false }); } diff --git a/compat/js/siteorigin-panels-layout-block.jsx b/compat/js/siteorigin-panels-layout-block.jsx index b4d56dd8..9825e2d5 100644 --- a/compat/js/siteorigin-panels-layout-block.jsx +++ b/compat/js/siteorigin-panels-layout-block.jsx @@ -37,9 +37,22 @@ class SiteOriginPanelsLayoutBlock extends wp.element.Component { componentWillUnmount() { this.isStillMounted = false; + this.panelsInitialized = false; + if ( this.builderView ) { this.builderView.off( 'content_change' ); + this.builderView = null; + + // Remove builder from global builder list. + if ( typeof window.soPanelsBuilderView !== 'undefined' ) { + window.soPanelsBuilderView = window.soPanelsBuilderView.filter( view => view !== this.builderView ); + } } + + this.panelsContainer = null; + this.previewContainer = null; + this.fetchPreviewTimer = null; + this.state = null; } componentDidUpdate( prevProps ) { From 8edeb943aa88ee712dd7c83493d165ada29ee078 Mon Sep 17 00:00:00 2001 From: Alex S <17275120+AlexGStapleton@users.noreply.github.com> Date: Tue, 26 Nov 2024 13:02:27 +1300 Subject: [PATCH 2/4] Layouts Block: Further Improvements to Unmounting --- compat/js/siteorigin-panels-layout-block.js | 104 ++++++++++++------- compat/js/siteorigin-panels-layout-block.jsx | 78 +++++++++----- 2 files changed, 117 insertions(+), 65 deletions(-) diff --git a/compat/js/siteorigin-panels-layout-block.js b/compat/js/siteorigin-panels-layout-block.js index 1c596967..5a2442f2 100644 --- a/compat/js/siteorigin-panels-layout-block.js +++ b/compat/js/siteorigin-panels-layout-block.js @@ -1,5 +1,11 @@ "use strict"; +function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } + +function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -61,24 +67,40 @@ function (_wp$element$Component) { _classCallCheck(this, SiteOriginPanelsLayoutBlock); _this2 = _super.call(this, props); - var hasPanelsData = _typeof(props.panelsData) === 'object' && Object.keys(props.panelsData).length > 0; - var isDefaultModeEdit = window.soPanelsBlockEditorAdmin.defaultMode === 'edit'; - var editMode = hasPanelsData === true ? isDefaultModeEdit : true; - _this2.state = { - editing: editMode, - loadingPreview: !editMode, - previewHtml: '', - previewInitialized: !editMode, - pendingPreviewRequest: false, - panelsInitialized: false - }; + + _this2.initializeState(props); + _this2.panelsContainer = wp.element.createRef(); _this2.previewContainer = wp.element.createRef(); - _this2.fetchPreviewTimer; + _this2.fetchPreviewTimer = null; + _this2.currentFetchRequest = null; return _this2; } _createClass(SiteOriginPanelsLayoutBlock, [{ + key: "initializeState", + value: function initializeState(props) { + var newState = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; + var hasPanelsData = _typeof(props.panelsData) === 'object' && Object.keys(props.panelsData).length > 0; + var isDefaultModeEdit = window.soPanelsBlockEditorAdmin.defaultMode === 'edit'; + var editMode = hasPanelsData === true ? isDefaultModeEdit : true; + this.initialState = { + editing: editMode, + loadingPreview: true, + previewHtml: '', + previewInitialized: !editMode, + pendingPreviewRequest: false, + panelsInitialized: false + }; // Depending on when this function is called, we need to update the state + // differently. + + if (newState) { + this.state = _objectSpread({}, this.initialState); + } else { + this.setState(_objectSpread({}, this.initialState)); + } + } + }, { key: "componentDidMount", value: function componentDidMount() { this.isStillMounted = true; @@ -86,14 +108,6 @@ function (_wp$element$Component) { if (!this.state.panelsInitialized) { this.setupPanels(); } - - if (!this.previewInitialized) { - clearTimeout(this.fetchPreviewTimer); - var current = this; - this.fetchPreviewTimer = setTimeout(function () { - current.fetchPreview(current.props); - }, 1000); - } } }, { key: "componentWillUnmount", @@ -101,30 +115,42 @@ function (_wp$element$Component) { var _this3 = this; this.isStillMounted = false; - this.panelsInitialized = false; if (this.builderView) { - this.builderView.off('content_change'); - this.builderView = null; // Remove builder from global builder list. - + // Remove builder from global builder list. if (typeof window.soPanelsBuilderView !== 'undefined') { window.soPanelsBuilderView = window.soPanelsBuilderView.filter(function (view) { return view !== _this3.builderView; }); } + + delete this.builderView; + } + + if (this.currentFetchRequest && typeof this.currentFetchRequest.abort === 'function') { + this.currentFetchRequest.abort(); } - this.panelsContainer = null; - this.previewContainer = null; - this.fetchPreviewTimer = null; - this.state = null; + clearTimeout(this.fetchPreviewTimer); + + if (this.panelsContainer) { + jQuery(this.panelsContainer.current).empty(); + } + + if (this.previewContainer) { + jQuery(this.previewContainer.current).empty(); + } + + this.initializeState(this.props, false); } }, { key: "componentDidUpdate", value: function componentDidUpdate(prevProps) { - if (!this.state.panelsInitialized) { - this.setupPanels(); - } else if (this.state.loadingPreview) { + if (!this.isStillMounted || !this.state.panelsInitialized) { + return; + } + + if (this.state.loadingPreview) { if (!this.state.pendingPreviewRequest) { this.setState({ pendingPreviewRequest: true @@ -147,8 +173,7 @@ function (_wp$element$Component) { value: function setupPanels() { var _this4 = this; - // Should we set up panels? - if (this.state.panelsInitialized) { + if (this.state.panelsInitialized || !this.isStillMounted) { return; } @@ -284,10 +309,15 @@ function (_wp$element$Component) { if (fetchRequest === _this5.currentFetchRequest && preview) { _this5.setState({ - previewHtml: preview, - loadingPreview: false, - previewInitialized: false, - pendingPreviewRequest: false + previewHtml: preview + }, // Wait until previewHTML has finished updating to cut + // down on the chance of nothing being rendered. + function () { + _this5.setState({ + loadingPreview: false, + previewInitialized: false, + pendingPreviewRequest: false + }); }); } }); diff --git a/compat/js/siteorigin-panels-layout-block.jsx b/compat/js/siteorigin-panels-layout-block.jsx index 9825e2d5..177a34fd 100644 --- a/compat/js/siteorigin-panels-layout-block.jsx +++ b/compat/js/siteorigin-panels-layout-block.jsx @@ -2,21 +2,35 @@ class SiteOriginPanelsLayoutBlock extends wp.element.Component { constructor( props ) { super( props ); + this.initializeState( props ); + + this.panelsContainer = wp.element.createRef(); + this.previewContainer = wp.element.createRef(); + this.fetchPreviewTimer = null; + this.currentFetchRequest = null; + } + + initializeState(props, newState = true) { const hasPanelsData = typeof props.panelsData === 'object' && Object.keys( props.panelsData ).length > 0; const isDefaultModeEdit = window.soPanelsBlockEditorAdmin.defaultMode === 'edit'; const editMode = hasPanelsData === true ? isDefaultModeEdit : true; - this.state = { + this.initialState = { editing: editMode, - loadingPreview: ! editMode, + loadingPreview: true, previewHtml: '', previewInitialized: ! editMode, pendingPreviewRequest: false, panelsInitialized: false, }; - this.panelsContainer = wp.element.createRef(); - this.previewContainer = wp.element.createRef(); - this.fetchPreviewTimer; + + // Depending on when this function is called, we need to update the state + // differently. + if ( newState ) { + this.state = { ...this.initialState }; + } else { + this.setState( { ...this.initialState } ); + } } componentDidMount() { @@ -25,41 +39,50 @@ class SiteOriginPanelsLayoutBlock extends wp.element.Component { if ( ! this.state.panelsInitialized ) { this.setupPanels(); } - - if ( ! this.previewInitialized ) { - clearTimeout( this.fetchPreviewTimer ); - var current = this; - this.fetchPreviewTimer = setTimeout( function() { - current.fetchPreview( current.props ); - }, 1000 ); - } } componentWillUnmount() { this.isStillMounted = false; - this.panelsInitialized = false; if ( this.builderView ) { - this.builderView.off( 'content_change' ); - this.builderView = null; - // Remove builder from global builder list. if ( typeof window.soPanelsBuilderView !== 'undefined' ) { window.soPanelsBuilderView = window.soPanelsBuilderView.filter( view => view !== this.builderView ); } + + delete this.builderView; } - this.panelsContainer = null; - this.previewContainer = null; - this.fetchPreviewTimer = null; - this.state = null; + if ( + this.currentFetchRequest && + typeof this.currentFetchRequest.abort === 'function' + ) { + this.currentFetchRequest.abort(); + } + + clearTimeout( this.fetchPreviewTimer ); + + if ( this.panelsContainer ) { + jQuery( this.panelsContainer.current ).empty(); + } + + if ( this.previewContainer ) { + jQuery( this.previewContainer.current ).empty(); + } + + this.initializeState( + this.props, + false + ); } componentDidUpdate( prevProps ) { - if ( ! this.state.panelsInitialized ) { - this.setupPanels(); - } else if ( this.state.loadingPreview ) { - if ( ! this.state.pendingPreviewRequest ) { + if ( ! this.isStillMounted || ! this.state.panelsInitialized ) { + return; + } + + if ( this.state.loadingPreview ) { + if ( ! this.state.pendingPreviewRequest ) { this.setState({ pendingPreviewRequest: true, } ); @@ -68,7 +91,7 @@ class SiteOriginPanelsLayoutBlock extends wp.element.Component { this.fetchPreviewTimer = setTimeout( function() { current.fetchPreview( current.props ); }, 1000 ); - } + } } else if ( ! this.state.previewInitialized ) { jQuery( document ).trigger( 'panels_setup_preview' ); this.setState( { @@ -78,8 +101,7 @@ class SiteOriginPanelsLayoutBlock extends wp.element.Component { } setupPanels() { - // Should we set up panels? - if ( this.state.panelsInitialized ) { + if ( this.state.panelsInitialized || ! this.isStillMounted ) { return; } From 1e29f030869b4851668d7b91a3b5e744794ec865 Mon Sep 17 00:00:00 2001 From: Alex S <17275120+AlexGStapleton@users.noreply.github.com> Date: Tue, 26 Nov 2024 13:03:01 +1300 Subject: [PATCH 3/4] Layouts Block: Prevent Nothing Appearing If Preview is Displayed Before Loading has Finished --- compat/js/siteorigin-panels-layout-block.jsx | 22 ++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/compat/js/siteorigin-panels-layout-block.jsx b/compat/js/siteorigin-panels-layout-block.jsx index 177a34fd..154c5055 100644 --- a/compat/js/siteorigin-panels-layout-block.jsx +++ b/compat/js/siteorigin-panels-layout-block.jsx @@ -202,7 +202,10 @@ class SiteOriginPanelsLayoutBlock extends wp.element.Component { ) { this.props.onContentChange( newPanelsData ); } - this.setState( { loadingPreview: true, previewHtml: '' } ); + this.setState( { + loadingPreview: true, + previewHtml: '' + } ); } } ); @@ -248,11 +251,18 @@ class SiteOriginPanelsLayoutBlock extends wp.element.Component { preview ) { this.setState( { - previewHtml: preview, - loadingPreview: false, - previewInitialized: false, - pendingPreviewRequest: false, - } ); + previewHtml: preview, + }, + // Wait until previewHTML has finished updating to cut + // down on the chance of nothing being rendered. + () => { + this.setState( { + loadingPreview: false, + previewInitialized: false, + pendingPreviewRequest: false, + } ); + } + ); } } ); return fetchRequest; From dd579dc7c37ad402f7aa98034f7f95e70d9554df Mon Sep 17 00:00:00 2001 From: Alex S <17275120+AlexGStapleton@users.noreply.github.com> Date: Tue, 26 Nov 2024 13:03:59 +1300 Subject: [PATCH 4/4] Cleanup --- compat/js/siteorigin-panels-layout-block.js | 4 ++-- compat/js/siteorigin-panels-layout-block.jsx | 13 ++++++------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/compat/js/siteorigin-panels-layout-block.js b/compat/js/siteorigin-panels-layout-block.js index 5a2442f2..40dd9110 100644 --- a/compat/js/siteorigin-panels-layout-block.js +++ b/compat/js/siteorigin-panels-layout-block.js @@ -91,8 +91,8 @@ function (_wp$element$Component) { previewInitialized: !editMode, pendingPreviewRequest: false, panelsInitialized: false - }; // Depending on when this function is called, we need to update the state - // differently. + }; // Depending on when this function is called, we need to update the + // state differently. if (newState) { this.state = _objectSpread({}, this.initialState); diff --git a/compat/js/siteorigin-panels-layout-block.jsx b/compat/js/siteorigin-panels-layout-block.jsx index 154c5055..f7016936 100644 --- a/compat/js/siteorigin-panels-layout-block.jsx +++ b/compat/js/siteorigin-panels-layout-block.jsx @@ -24,8 +24,8 @@ class SiteOriginPanelsLayoutBlock extends wp.element.Component { panelsInitialized: false, }; - // Depending on when this function is called, we need to update the state - // differently. + // Depending on when this function is called, we need to update the + // state differently. if ( newState ) { this.state = { ...this.initialState }; } else { @@ -35,7 +35,6 @@ class SiteOriginPanelsLayoutBlock extends wp.element.Component { componentDidMount() { this.isStillMounted = true; - if ( ! this.state.panelsInitialized ) { this.setupPanels(); } @@ -109,9 +108,9 @@ class SiteOriginPanelsLayoutBlock extends wp.element.Component { var config = { editorType: 'standalone', - loadLiveEditor: false, - postId: window.soPanelsBlockEditorAdmin.postId, - editorPreview: window.soPanelsBlockEditorAdmin.liveEditor, + loadLiveEditor: false, + postId: window.soPanelsBlockEditorAdmin.postId, + editorPreview: window.soPanelsBlockEditorAdmin.liveEditor, }; var builderModel = new panels.model.builder(); @@ -193,8 +192,8 @@ class SiteOriginPanelsLayoutBlock extends wp.element.Component { this.builderView.on( 'content_change', () => { const newPanelsData = this.builderView.getData(); - this.panelsDataChanged = ! SiteOriginIsPanelsEqual( panelsData, newPanelsData ); + this.panelsDataChanged = ! SiteOriginIsPanelsEqual( panelsData, newPanelsData ); if ( this.panelsDataChanged ) { if ( this.props.onContentChange &&