PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 4.0.8
Visualizer – Tables & Charts Manager with Built-in AI Generator v4.0.8
4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 All 149 releases
visualizer / js / elementor-widget-preview.js

elementor-widget-preview.js in Visualizer – Tables & Charts Manager with Built-in AI Generator 4.0.8, at js/elementor-widget-preview.js

182 lines 5.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /* global elementorFrontend, jQuery */
2 /**
3 * Elementor preview handler for Visualizer charts.
4 *
5 * @since 3.11.16
6 */
7 // Guard against the script being injected more than once into the preview iframe.
8 if ( ! window.visualizerElementorPreview ) {
9 window.visualizerElementorPreview = true;
10
11 ( function ( $ ) {
12 'use strict';
13
14 /**
15 * Poll until `condition()` returns true, then call `callback`.
16 * Gives up after `maxAttempts` × 100 ms.
17 */
18 function waitFor( condition, callback, maxAttempts ) {
19 maxAttempts = maxAttempts === undefined ? 50 : maxAttempts;
20 if ( condition() ) {
21 callback();
22 return;
23 }
24 if ( maxAttempts <= 0 ) {
25 return;
26 }
27 setTimeout( function () {
28 waitFor( condition, callback, maxAttempts - 1 );
29 }, 100 );
30 }
31
32 /**
33 * Given the Elementor widget wrapper element, extract chart data from the
34 * embedded JSON script element and trigger chart rendering.
35 */
36 function renderWidget( widgetEl ) {
37 var $scope = $( widgetEl );
38 var $dataEl = $scope.find( 'script.visualizer-chart-data[type="application/json"]' );
39
40 if ( ! $dataEl.length ) {
41 return;
42 }
43
44 var elementId = $dataEl.attr( 'data-element-id' );
45 var chartEntry;
46
47 try {
48 chartEntry = JSON.parse( $dataEl.text() );
49 } catch ( e ) {
50 return;
51 }
52
53 if ( ! elementId || ! chartEntry ) {
54 return;
55 }
56
57 window.visualizer = window.visualizer || {};
58 window.visualizer.charts = window.visualizer.charts || {};
59 window.visualizer.charts[ elementId ] = chartEntry;
60
61 // Build the viz object that render-google.js / render-chartjs.js expect.
62 // is_front:true tells render-google.js to call renderChart(id) for just
63 // this element rather than render() for all charts.
64 var viz = $.extend( {}, window.visualizer, { id: elementId, is_front: true } );
65
66 function doTrigger() {
67 $( '#' + elementId ).removeClass( 'viz-facade-loaded' );
68 $( 'body' ).trigger( 'visualizer:render:chart:start', viz );
69 }
70
71 if ( chartEntry.library === 'google' || chartEntry.library === 'GoogleCharts' ) {
72 // render-google.js bails silently when typeof google !== 'object'.
73 // Poll until the Google Charts loader script has executed.
74 waitFor( function () { return typeof google === 'object'; }, doTrigger );
75 } else {
76 doTrigger();
77 }
78 }
79
80 /**
81 * Scan a subtree for visualizer-chart widgets and render each one.
82 */
83 function scanAndRender( root ) {
84 var $root = $( root );
85
86 if ( $root.is( '[data-widget_type="visualizer-chart.default"]' ) ) {
87 renderWidget( root );
88 }
89
90 $root.find( '[data-widget_type="visualizer-chart.default"]' ).each( function () {
91 renderWidget( this );
92 } );
93 }
94
95 $( document ).ready( function () {
96 var observer = new MutationObserver( function ( mutations ) {
97 // Collect widget elements to render, de-duplicating within the batch.
98 var toRender = [];
99 var seen = window.WeakSet ? new WeakSet() : null;
100 var seenList = [];
101
102 // Enqueue a widget element for rendering, skipping duplicates.
103 function enqueue( el ) {
104 if ( ! el ) {
105 return;
106 }
107 if ( seen ) {
108 if ( seen.has( el ) ) {
109 return;
110 }
111 seen.add( el );
112 toRender.push( el );
113 return;
114 }
115 if ( seenList.indexOf( el ) !== -1 ) {
116 return;
117 }
118 seenList.push( el );
119 toRender.push( el );
120 }
121
122 mutations.forEach( function ( mutation ) {
123 mutation.addedNodes.forEach( function ( node ) {
124 if ( node.nodeType !== 1 ) {
125 return;
126 }
127
128 // Only react when chart data was injected, not when chart
129 // rendering (SVG / canvas) mutates the DOM — that would loop.
130 var hasData = ( node.matches && node.matches( 'script.visualizer-chart-data[type="application/json"]' ) ) ||
131 ( node.querySelector && node.querySelector( 'script.visualizer-chart-data[type="application/json"]' ) );
132 if ( ! hasData ) {
133 return;
134 }
135
136 // Node is the widget wrapper or contains one (new widget added).
137 if ( $( node ).is( '[data-widget_type="visualizer-chart.default"]' ) ) {
138 enqueue( node );
139 }
140 $( node ).find( '[data-widget_type="visualizer-chart.default"]' ).each( function () {
141 enqueue( this );
142 } );
143
144 // Node is inner content of an existing widget (chart switched).
145 // Look upward for the widget wrapper.
146 enqueue( $( node ).closest( '[data-widget_type="visualizer-chart.default"]' )[ 0 ] );
147 } );
148 } );
149
150 toRender.forEach( function ( el ) {
151 renderWidget( el );
152 } );
153 } );
154
155 observer.observe( document.documentElement, { childList: true, subtree: true } );
156
157 // Handle widgets already present on initial load.
158 scanAndRender( document.body );
159 } );
160
161 // Register Elementor's element_ready hook as a secondary trigger.
162 // Called both immediately (in case elementorFrontend is already initialised)
163 // and on the init event (in case it fires after this script loads).
164 // The guard prevents double-registration if both code paths fire.
165 var elementorHookRegistered = false;
166 function registerElementorHook() {
167 if ( elementorHookRegistered ) {
168 return;
169 }
170 if ( typeof elementorFrontend !== 'undefined' && elementorFrontend.hooks ) {
171 elementorFrontend.hooks.addAction(
172 'frontend/element_ready/visualizer-chart.default',
173 function ( $scope ) { renderWidget( $scope[ 0 ] ); }
174 );
175 elementorHookRegistered = true;
176 }
177 }
178 registerElementorHook();
179 window.addEventListener( 'elementor/frontend/init', registerElementorHook );
180 }( jQuery ) );
181 } // end visualizerElementorPreview guard
182