PageSourceSearch

https://kfk-muenster.de/wp-content/plugins/custom-facebook-feed/ve…/js/sb-elementor-handler.js?ver=1.0.0

js kfk-muenster.de collected 2026-10-08 11:15:15 UTC 8,755 bytes, 247 lines download raw bytes

1'use strict';
2
3/**
4 * Smash Balloon Elementor Handler
5 *
6 * Handles click/drag behaviour for faux SB widgets in the Elementor editor:
7 * - Disables drag on inactive (uninstalled) SB widgets
8 * - Shows install popup modal on click
9 * - Calls `am_recommended_block_install` AJAX action to install plugins
10 */
11
12let SbElementorHandler = window.SbElementorHandler || ( function( _document, window, $ ) {
13
14	const smashBalloonPlugins = sbHandler.smashPlugins;
15
16	let app = {
17
18		_observer: null,
19		_debounceTimer: null,
20
21		init: function() {
22			app.events();
23		},
24
25		events: function() {
26			app.waitForPanel( function() {
27				app.disableInactiveSmashWidgets();
28				app.observePanelChanges();
29			});
30		},
31
32		/**
33		 * Poll until window.parent.elementor.panel exists, then invoke callback.
34		 */
35		waitForPanel: function( callback ) {
36			var check = function() {
37				if ( window.parent.elementor && window.parent.elementor.panel && window.parent.elementor.panel.$el ) {
38					callback();
39				} else {
40					setTimeout( check, 200 );
41				}
42			};
43			check();
44		},
45
46		/**
47		 * Attach a MutationObserver on the panel element to detect re-renders.
48		 * When Elementor destroys/re-creates the panel DOM (e.g. navigating
49		 * between widget list and widget settings), re-apply disable logic.
50		 */
51		observePanelChanges: function() {
52			if ( app._observer ) {
53				app._observer.disconnect();
54			}
55
56			var panelEl = window.parent.elementor.panel.$el[0];
57			if ( ! panelEl ) {
58				return;
59			}
60
61			app._observer = new window.parent.MutationObserver( function() {
62				clearTimeout( app._debounceTimer );
63				app._debounceTimer = setTimeout( function() {
64					app.disableInactiveSmashWidgets();
65				}, 100 );
66			});
67
68			app._observer.observe( panelEl, {
69				childList: true,
70				subtree: true
71			});
72		},
73
74		disableInactiveSmashWidgets: function() {
75			var panel$ = window.parent.elementor.panel.$el;
76			if ( ! panel$ || ! panel$.length ) {
77				return;
78			}
79
80			// Scan the entire panel rather than scoping to
81			// `#elementor-panel-category-smashballoon`. Elementor renders the
82			// search-results widget list (and lazy-loaded scrolled tiles)
83			// outside that category container, so a category-scoped query
84			// misses faux widgets shown there.
85			for ( const pluginName in smashBalloonPlugins ) {
86				panel$
87					.find( '.sb-elem-inactive.sb-elem-' + pluginName )
88					.each( function() {
89						var pluginWrapper = $( this ).closest( '.elementor-element-wrapper' );
90						if ( ! pluginWrapper.length ) {
91							return;
92						}
93
94						// Skip if already processed
95						if ( pluginWrapper.find( '.sb-click-overlay' ).length ) {
96							return;
97						}
98
99						var pluginWidget = pluginWrapper.find( '.elementor-element' );
100
101						// Block all pointer events on the actual draggable element
102						pluginWidget.css( 'pointer-events', 'none' );
103
104						// Add a click-capturing overlay
105						pluginWrapper.css( 'position', 'relative' );
106						var $overlay = $( '<div class="sb-click-overlay"></div>' ).css({
107							position: 'absolute',
108							top: 0,
109							left: 0,
110							width: '100%',
111							height: '100%',
112							zIndex: 10,
113							cursor: 'pointer'
114						});
115
116						// Use closure to capture pluginName
117						(function( name ) {
118							// Suppress mousedown so Elementor's native Pro
119							// upsell dialog (bound on mousedown for Pro
120							// widgets) does not fire on top of our SB
121							// upsell modal.
122							$overlay.on( 'mousedown', function( e ) {
123								e.stopPropagation();
124								e.preventDefault();
125							});
126							$overlay.on( 'click', function( e ) {
127								e.stopPropagation();
128								e.preventDefault();
129								app.createUpsellPopup( name );
130							});
131						})( pluginName );
132
133						pluginWrapper.append( $overlay );
134					});
135			}
136		},
137
138		createUpsellPopup: function( pluginName ) {
139			let plugin = smashBalloonPlugins[ pluginName ],
140				spinnerIcon = '<svg x="0px" y="0px" width="20px" height="20px" viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve"><path fill="#fff" d="M43.935,25.145c0-10.318-8.364-18.683-18.683-18.683c-10.318,0-18.683,8.365-18.683,18.683h4.068c0-8.071,6.543-14.615,14.615-14.615c8.072,0,14.615,6.543,14.615,14.615H43.935z"><animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 25 25" to="360 25 25" dur="0.6s" repeatCount="indefinite"/></path></svg>',
141				upsellPopupOutput =
142				'<div class="sb-source-ctn sb-fs-boss sb-center-boss">\
143					<div class="sb-source-popup sb-popup-inside sb-install-plugin-modal">\
144						<div class="sb-popup-cls">\
145							<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">\
146								<path d="M14 1.41L12.59 0L7 5.59L1.41 0L0 1.41L5.59 7L0 12.59L1.41 14L7 8.41L12.59 14L14 12.59L8.41 7L14 1.41Z" fill="#141B38"/>\
147							</svg>\
148						</div>\
149						<div class="sb-install-plugin-body sb-fs">\
150							<div class="sb-install-plugin-header">\
151								<div class="sb-plugin-image">' + plugin["svgIcon"] + '\
152								<svg class="sb-plugin-cta-logo" width="26" height="33" viewBox="0 0 26 33" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M25.5608 15.2708C25.5608 6.86286 20.0495 0.046814 13.2486 0.046814C6.44763 0.046814 0.933838 6.86286 0.933838 15.2708C0.933838 23.3312 5.98416 29.9079 12.3795 30.4596L11.6995 32.6132L15.9639 32.2505L14.4677 30.4218C20.6943 29.6661 25.5608 23.1725 25.5608 15.2708Z" fill="#FE544F"/><path fill-rule="evenodd" clip-rule="evenodd" d="M16.1843 5.39911L16.7768 11.5131L22.9165 11.6894L18.4752 15.8189L21.983 20.8926L16.0735 19.7817L14.282 25.6913L11.5618 20.3993L6.0693 22.916L8.18218 17.2428L2.82544 14.5409L8.55968 12.6968L6.97737 7.04787L12.4024 10.1407L16.1843 5.39911Z" fill="white"/></svg>\
153								</div>\
154								<div class="sb-plugin-name">\
155									<strong>Requires</strong>\
156									<h3>\
157										' + plugin["displayName"] + '\
158										<span>Free</span>\
159									</h3>\
160								</div>\
161							</div>\
162							<div class="sb-install-plugin-content">\
163								<p>' + plugin["description"] + '</p>\
164								<button class="sb-install-plugin-btn sb-btn-orange sb-plugin-btn" data-plugin="' + plugin['download_plugin'] + '">\
165									<span class="sb-install-plugin-spinner" style="display:none">' + spinnerIcon + '</span>\
166									' + (plugin["pluginInstalled"] ? 'Activate' : 'Install') + '\
167								</button>\
168								<button class="sb-install-refresh-btn sb-btn-blue sb-plugin-btn" style="display:none">\
169									Refresh The Page\
170								</button>\
171							</div>\
172						</div>\
173					</div>\
174				</div>';
175
176			if ( $( window.parent.document.body ).find( '.sb-center-boss' ).length === 0 ) {
177				$( window.parent.document.body ).append( upsellPopupOutput );
178
179				$( window.parent.document.body ).find( '.sb-install-plugin-btn' ).on( 'click', function() {
180					let downloadPlugin = $( this ).attr( 'data-plugin' );
181					$( this ).find( '.sb-install-plugin-spinner' ).show();
182					app.installPlugin( downloadPlugin, pluginName );
183				});
184
185				$( window.parent.document.body ).find( '.sb-install-refresh-btn' ).on( 'click', function() {
186					window.parent.location.reload();
187				});
188
189				$( window.parent.document.body ).find( '.sb-popup-cls' ).on( 'click', function() {
190					app.closeUpsellPopup();
191				});
192
193				$( window.parent.document.body ).find( '.sb-center-boss' ).on( 'click', function( e ) {
194					if ( e.target === this ) {
195						app.closeUpsellPopup();
196					}
197				});
198			}
199		},
200
201		closeUpsellPopup: function() {
202			$( window.parent.document.body ).find( '.sb-center-boss' ).remove();
203		},
204
205		installPlugin: function( downloadPlugin, pluginName ) {
206			let data = new FormData();
207			data.append( 'action', 'am_recommended_block_install' );
208			data.append( 'nonce', sbHandler.nonce );
209			data.append( 'plugin', downloadPlugin );
210
211			let $btn = $( window.parent.document.body ).find( '.sb-install-plugin-btn' );
212
213			fetch( sbHandler.ajax_handler, {
214				method: 'POST',
215				credentials: 'same-origin',
216				body: data
217			})
218			.then( function( response ) {
219				if ( ! response.ok ) {
220					throw new Error( 'Server error' );
221				}
222				return response.json();
223			} )
224			.then( function( data ) {
225				if ( data.success === true ) {
226					smashBalloonPlugins[ pluginName ].pluginInstalled = true;
227					$btn.hide();
228					$( window.parent.document.body ).find( '.sb-install-refresh-btn' ).show();
229				} else {
230					$btn.find( '.sb-install-plugin-spinner' ).hide();
231					$btn.text( 'Error. Please try again.' );
232				}
233			})
234			.catch( function( err ) {
235				console.error( '[SB] Plugin install error:', err );
236				$btn.find( '.sb-install-plugin-spinner' ).hide();
237				$btn.text( 'Error. Please try again.' );
238			});
239		}
240
241	};
242
243	return app;
244
245}( document, window, jQuery ) );
246
247SbElementorHandler.init();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.