Last active
February 28, 2023 18:19
-
-
Save matipojo/044fd89844ab6b7c63a43984cf84df2e to your computer and use it in GitHub Desktop.
A demonstration of advanced elements manipulation before save in Elementor Editor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class Component extends $e.modules.ComponentBase { | |
| getNamespace() { | |
| return 'elements-checker'; | |
| } | |
| defaultHooks() { | |
| // It should be in a separated file and imported with `import * as hooks from './hooks';` | |
| // this.importHooks( hooks ); | |
| return { | |
| // The `dependency` hook runs before the specified command. | |
| // It returns true/false whether to continue the save or not. | |
| 'check-elements-before-save': new class extends $e.modules.hookData.Dependency { | |
| getCommand() { | |
| return 'document/save/save'; | |
| } | |
| getId() { | |
| return 'check-elements-before-save'; | |
| } | |
| getConditions( args ) { | |
| return 'publish' === args.status && ! args.force; // Don't check if it's a forced save. | |
| } | |
| apply() { | |
| const restoreEditorState = this.switchToDesktopTop(); | |
| const hideNotification = this.showNotification(); | |
| // Check elements here | |
| const elements = this.getFlattedElementsList( elementor.getPreviewContainer().children ); | |
| // Reset all elements | |
| this.setAboveTheFold( elements, false ); | |
| const devices = elementor.breakpoints.getActiveBreakpointsList( { largeToSmall: true, withDesktop: true } ); | |
| devices.forEach( ( device ) => { | |
| $e.run( 'panel/change-device-mode', { device } ); | |
| // Filter elements that are above the fold | |
| const aboveTheFoldElements = this.getElementsAboveTheFold( elements ); | |
| this.setAboveTheFold( aboveTheFoldElements, true ); | |
| } ); | |
| restoreEditorState(); | |
| hideNotification(); | |
| return true; // Continue the save | |
| } | |
| switchToDesktopTop() { | |
| const currentDeviceMode = elementor.channels.deviceMode.request( 'currentMode' ), | |
| iframeWindow = elementor.$preview[ 0 ].contentWindow, | |
| currentScrollPosition = iframeWindow.scrollY; | |
| $e.run( 'panel/change-device-mode', { device: 'desktop' } ); | |
| iframeWindow.scrollTo( 0, 0 ); | |
| return () => { | |
| $e.run( 'panel/change-device-mode', { device: currentDeviceMode } ); | |
| iframeWindow.scrollTo( 0, currentScrollPosition ); | |
| }; | |
| } | |
| showNotification() { | |
| const notification = elementor.notifications.showToast( { | |
| message: 'Performance Improving. Checking elements above the fold...', | |
| } ); | |
| return () => { | |
| // Show the notification for at least 2 seconds | |
| setTimeout( () => { | |
| notification.hide(); | |
| }, 2000 ); | |
| }; | |
| } | |
| getFlattedElementsList( elements ) { | |
| let flatted = []; | |
| for ( const element of elements ) { | |
| flatted.push( element ); | |
| if ( element.children.length ) { | |
| flatted = flatted.concat( this.getFlattedElementsList( element.children ) ); | |
| } | |
| } | |
| return flatted; | |
| } | |
| setAboveTheFold( elements, value ) { | |
| elements.forEach( ( element ) => { | |
| if ( ( !! element.settings.get( 'is_above_the_fold' ) ) === value ) { | |
| return; | |
| } | |
| // Use the internal command because it's not a user action | |
| $e.internal( 'document/elements/set-settings', { | |
| container: element, | |
| settings: { | |
| is_above_the_fold: value, // Todo: if `false` then remove the setting | |
| }, | |
| options: { | |
| external: true, // Update panel if it's open | |
| render: false, // Don't re-render the element | |
| }, | |
| } ); | |
| } ); | |
| } | |
| getElementsAboveTheFold( elements ) { | |
| return elements.filter( ( element ) => { | |
| // Is the element visible? | |
| if ( ! element.view.el.offsetParent ) { | |
| return false; | |
| } | |
| const elementRect = element.view.el.getBoundingClientRect(); | |
| return elementRect.top < window.innerHeight; | |
| } ); | |
| } | |
| }, | |
| }; | |
| } | |
| } | |
| // Should be registered from the module file | |
| $e.components.register( new Component() ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment