PluginProbe
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder / 51.1.82
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder v51.1.82
51.1.83 51.1.82 51.1.81 51.1.79 51.1.78 51.1.77 51.1.76 51.1.74 51.1.75 51.1.65 51.1.64 51.1.63 trunk 51.1.14 51.1.2 51.1.35 51.1.36 51.1.37 51.1.38 51.1.39 51.1.44 51.1.45 51.1.46 51.1.47 51.1.49 All 37 releases
king-addons / includes / admin / js / elementor-editor.js

elementor-editor.js in King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder 51.1.82, at includes/admin/js/elementor-editor.js

560 lines 23.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 "use strict";
2
3 (function($) {
4 function createProTooltip() {
5 const tooltip = document.createElement('div');
6 tooltip.className = 'king-addons-pro-tooltip';
7 tooltip.innerHTML = `
8 <p>This is available in <strong><a href="https://kingaddons.com/pricing/?utm_source=kng-module-upgrade-pro&utm_medium=plugin&utm_campaign=kng" target="_blank">King Addons PRO</a></strong> version</p>
9 `;
10 return tooltip;
11 }
12
13 function appendProTooltip(controlElement) {
14 // Only append if a tooltip doesn't already exist
15 if (!controlElement.querySelector('.king-addons-pro-tooltip')) {
16 controlElement.appendChild(createProTooltip());
17 }
18 }
19
20 // Function for handling custom menu and submenu
21 function setupMegaMenuItemsHandling() {
22 // Carefully apply styles to submenu elements
23 function markSubmenuItems() {
24 $('.elementor-control-submenu_items .elementor-repeater-fields').addClass('king-addons-submenu-item');
25
26 $('.elementor-control-item_type select').each(function() {
27 if ($(this).val() === 'submenu') {
28 $(this).closest('.elementor-repeater-fields').addClass('king-addons-parent-submenu-item');
29 }
30 });
31 }
32
33 // Process menu item type change events
34 $(document).on('change', '.elementor-control-item_type select', function() {
35 var $select = $(this);
36 var selectedValue = $select.val();
37
38 // If submenu type is selected
39 if (selectedValue === 'submenu') {
40 // Find item container
41 var $itemContainer = $select.closest('.elementor-repeater-fields');
42
43 // Mark element as parent for submenu
44 $itemContainer.addClass('king-addons-parent-submenu-item');
45 } else {
46 $select.closest('.elementor-repeater-fields').removeClass('king-addons-parent-submenu-item');
47 }
48
49 // Apply styles to all submenu items after change
50 markSubmenuItems();
51 });
52
53 // Immediately style submenu items on page load
54 markSubmenuItems();
55
56 // Apply styles when loading panel
57 if (window.elementor) {
58 elementor.hooks.addAction('panel/open_editor/widget', function(panel, model, view) {
59 if (model.attributes.widgetType === 'king-mega-menu' || model.attributes.widgetType === 'king-mega-menu-pro') {
60 // Apply styles and classes on first opening
61 markSubmenuItems();
62
63 // Check for submenu items every 500ms for the first few seconds
64 // to catch items that might be added dynamically
65 for (let i = 1; i <= 10; i++) {
66 setTimeout(markSubmenuItems, i * 500);
67 }
68
69 // Track element addition via MutationObserver more safely
70 try {
71 const observer = new MutationObserver(function(mutations) {
72 mutations.forEach(function(mutation) {
73 if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
74 // If new nodes are added, apply styles
75 if ($(mutation.target).closest('.elementor-control-submenu_items').length > 0) {
76 // If change is in submenu
77 markSubmenuItems();
78 }
79 }
80 });
81 });
82
83 // Start observing the entire editor, but with a narrower focus on changes
84 observer.observe(panel.$el[0], {
85 childList: true,
86 subtree: true,
87 attributes: false
88 });
89
90 // Stop observing when panel is closed
91 elementor.hooks.addAction('panel/close_editor', function() {
92 observer.disconnect();
93 });
94 } catch (error) {
95 // console.error('Error when setting up observer:', error);
96 }
97 }
98 });
99
100 // Hook after adding a new element to Elementor repeater
101 $(document).on('DOMNodeInserted', '.elementor-repeater-row-item-title', function(e) {
102 // Apply styles after any item is inserted
103 setTimeout(markSubmenuItems, 150);
104 });
105 }
106
107 // Add styles for visual distinction of submenu elements
108 try {
109 const style = document.createElement('style');
110 style.textContent = `
111 .king-addons-parent-submenu-item {
112 border-left: 3px solid #4054b2 !important;
113 background-color: rgba(64, 84, 178, 0.05) !important;
114 }
115 .king-addons-submenu-item {
116 border-left: 3px solid #6d7882 !important;
117 margin-left: 15px !important;
118 width: calc(100% - 15px) !important;
119 }
120
121 /* Custom styles for bug report section */
122 .king-addons-help-wrapper {
123 width: 100%;
124 max-width: 100%;
125 box-sizing: border-box;
126 display: block;
127 flex: 0 0 100%;
128 min-width: 0;
129 }
130
131 /* Ensure injected blocks sit under the Need Help link */
132 #elementor-panel__editor__help.king-addons-help-injected {
133 flex-wrap: wrap;
134 }
135
136 #elementor-panel__editor__help.king-addons-help-injected > #elementor-panel__editor__help__link {
137 flex: 0 0 100%;
138 }
139
140 .king-addons-bug-report {
141 background: #ffffff;
142 border: 1px solid #ddd;
143 border-radius: 5px;
144 padding: 15px;
145 margin-top: 8px;
146 line-height: 1.4;
147 width: 100%;
148 box-sizing: border-box;
149 }
150
151 .king-addons-bug-report-title {
152 font-weight: 600;
153 font-size: 14px;
154 color: #333;
155 margin-bottom: 8px;
156 }
157
158 .king-addons-bug-report-text {
159 font-size: 12px;
160 color: #666;
161 margin-bottom: 10px;
162 }
163
164 .king-addons-bug-report-email-section {
165 display: flex;
166 align-items: center;
167 gap: 8px;
168 }
169
170 .king-addons-bug-report-email-field {
171 flex: 1;
172 background: #f8f9fa;
173 border: 1px solid #ddd;
174 border-radius: 4px;
175 padding: 6px 10px;
176 font-family: monospace;
177 font-size: 11px;
178 color: #333;
179 user-select: all;
180 }
181
182 .king-addons-bug-report-copy-btn {
183 padding: 6px 12px;
184 background: #666666;
185 color: white;
186 border: none;
187 border-radius: 4px;
188 cursor: pointer;
189 font-size: 11px;
190 font-weight: 500;
191 transition: background 0.2s;
192 }
193
194 .king-addons-bug-report-copy-btn:hover {
195 background: #2d3a80;
196 }
197
198 .king-addons-bug-report-copy-btn.copied {
199 background: #28a745;
200 }
201
202 /* Responsive: prevent overflow in narrow Elementor panels */
203 @media (max-width: 420px) {
204 .king-addons-bug-report-email-section {
205 flex-direction: column;
206 align-items: stretch;
207 }
208
209 .king-addons-bug-report-email-field {
210 width: 100%;
211 }
212
213 .king-addons-bug-report-copy-btn {
214 width: 100%;
215 }
216 }
217
218 /* Promo block styles */
219 .king-addons-promo-block {
220 background: linear-gradient(135deg, #93117e 0%, #d946ef 100%);
221 border-radius: 6px;
222 padding: 16px;
223 margin-top: 12px;
224 margin-bottom: 12px;
225 color: white;
226 position: relative;
227 overflow: hidden;
228 width: 100%;
229 box-sizing: border-box;
230 min-width: 0;
231 }
232
233 .king-addons-promo-block::before {
234 content: '';
235 position: absolute;
236 top: 0;
237 right: 0;
238 bottom: 0;
239 left: 0;
240 background: rgba(255, 255, 255, 0.05);
241 border-radius: 6px;
242 pointer-events: none;
243 }
244
245 .king-addons-promo-title {
246 font-weight: 600;
247 font-size: 13px;
248 margin-bottom: 6px;
249 line-height: 1.3;
250 position: relative;
251 z-index: 1;
252 }
253
254 .king-addons-promo-text {
255 font-size: 11px;
256 line-height: 1.4;
257 margin-bottom: 8px;
258 opacity: 0.9;
259 position: relative;
260 z-index: 1;
261 }
262
263 .king-addons-promo-highlight {
264 font-weight: 600;
265 color: #fbbf24;
266 }
267
268 .king-addons-promo-small {
269 font-size: 10px;
270 opacity: 0.8;
271 margin-bottom: 10px;
272 position: relative;
273 z-index: 1;
274 }
275
276 .king-addons-promo-buttons {
277 display: flex;
278 gap: 8px;
279 position: relative;
280 z-index: 1;
281 flex-wrap: wrap;
282 }
283
284 .king-addons-promo-btn {
285 padding: 6px 12px;
286 border: none;
287 border-radius: 4px;
288 font-size: 11px;
289 font-weight: 600;
290 cursor: pointer;
291 transition: all 0.2s;
292 text-decoration: none;
293 display: inline-block;
294 white-space: nowrap;
295 }
296
297 .king-addons-promo-btn-primary {
298 background: #ffffff;
299 color: #93117e;
300 }
301
302 .king-addons-promo-btn-primary:hover {
303 background: #f3f4f6;
304 transform: translateY(-1px);
305 }
306
307 .king-addons-promo-btn-secondary {
308 background: rgba(255, 255, 255, 0.2);
309 color: white;
310 }
311
312 .king-addons-promo-btn-secondary:hover {
313 background: rgba(255, 255, 255, 0.3);
314 color: rgb(255 255 255 / 80%);
315 }
316
317 /* Dark mode styles using system preference */
318 @media (prefers-color-scheme: dark) {
319 .king-addons-bug-report {
320 background: #2c2c2c;
321 border-color: #444;
322 }
323
324 .king-addons-bug-report-title {
325 color: #ffffff;
326 }
327
328 .king-addons-bug-report-text {
329 color: #b0b0b0;
330 }
331
332 .king-addons-bug-report-email-field {
333 background: #383838;
334 border-color: #555;
335 color: #ffffff;
336 }
337 }
338 `;
339 document.head.appendChild(style);
340 } catch (styleError) {
341 // console.error('Error when adding styles:', styleError);
342 }
343 }
344
345 $(window).on('elementor:init', function() {
346 // console.log('elementor:init event fired for mega menu editor');
347 const panelEl = document.getElementById('elementor-panel');
348
349 // Watch for newly-added .king-addons-pro-control elements
350 const observer = new MutationObserver(function(mutations) {
351 mutations.forEach((mutation) => {
352 if (mutation.type === 'childList') {
353 mutation.addedNodes.forEach((node) => {
354 if (node.nodeType === Node.ELEMENT_NODE) {
355 // Find .king-addons-pro-control .elementor-control-content in newly added nodes
356 const proControls = node.querySelectorAll('.king-addons-pro-control .elementor-control-content');
357 proControls.forEach(appendProTooltip);
358 }
359 });
360 }
361 });
362 });
363
364 // Start observing if the elementor panel is found
365 if (panelEl) {
366 observer.observe(panelEl, {
367 childList: true,
368 subtree: true
369 });
370 }
371
372 // Initial pass for any controls already in the DOM
373 const initialProControls = document.querySelectorAll('.king-addons-pro-control .elementor-control-content');
374 initialProControls.forEach(appendProTooltip);
375
376 // Initialize custom menu handling
377 setupMegaMenuItemsHandling();
378
379 // Replace default "Need Help" link with King Addons bug report section
380 (function replaceHelpLink() {
381 const EMAIL = 'contact@kingaddons.com';
382
383 // Function to copy text to clipboard
384 function copyToClipboard(text) {
385 return new Promise((resolve, reject) => {
386 if (navigator.clipboard && window.isSecureContext) {
387 navigator.clipboard.writeText(text)
388 .then(() => resolve(true))
389 .catch(err => reject(err));
390 } else {
391 // Fallback for older browsers
392 const textArea = document.createElement('textarea');
393 textArea.value = text;
394 textArea.style.position = 'fixed';
395 textArea.style.left = '-999999px';
396 textArea.style.top = '-999999px';
397 document.body.appendChild(textArea);
398 textArea.focus();
399 textArea.select();
400
401 try {
402 document.execCommand('copy');
403 document.body.removeChild(textArea);
404 resolve(true);
405 } catch (err) {
406 document.body.removeChild(textArea);
407 reject(err);
408 }
409 }
410 });
411 }
412
413 function createBugReportSection() {
414 // Create new bug report section
415 const bugReportSection = document.createElement('div');
416 bugReportSection.className = 'king-addons-bug-report';
417 bugReportSection.innerHTML = `
418 <div class="king-addons-bug-report-title">Questions, bugs, feedback, or ideas?</div>
419 <div class="king-addons-bug-report-text">Reach out to us at ${EMAIL} we love hearing from our users!</div>
420 <div class="king-addons-bug-report-email-section">
421 <span class="king-addons-bug-report-email-field">${EMAIL}</span>
422 <button class="king-addons-bug-report-copy-btn">Copy</button>
423 </div>
424 `;
425
426 // Add copy functionality
427 const copyBtn = bugReportSection.querySelector('.king-addons-bug-report-copy-btn');
428
429 // Copy email address function
430 copyBtn.addEventListener('click', () => {
431 copyToClipboard(EMAIL).then(() => {
432 copyBtn.textContent = 'Copied!';
433 copyBtn.classList.add('copied');
434 setTimeout(() => {
435 copyBtn.textContent = 'Copy';
436 copyBtn.classList.remove('copied');
437 }, 2000);
438 }).catch(err => {
439 // console.error('Error copying email:', err);
440 alert('Failed to copy email address.');
441 });
442 });
443
444 return bugReportSection;
445 }
446
447 function createPromoBlock() {
448 // Check if PRO is active
449 if (typeof kingAddonsEditor !== 'undefined' && kingAddonsEditor.isPro) {
450 return null; // Don't show promo for PRO users
451 }
452
453 const promoBlock = document.createElement('div');
454 promoBlock.className = 'king-addons-promo-block';
455 promoBlock.innerHTML = `
456 <div class="king-addons-promo-title">Get <span class="king-addons-promo-highlight">4,000+</span> premium templates and sections, <span class="king-addons-promo-highlight">80+</span> widgets, <span class="king-addons-promo-highlight">200+</span> advanced features, and AI tools for Elementor. From <span class="king-addons-promo-highlight">$4</span>/mo, billed annually.</div>
457 <div class="king-addons-promo-text">Upgrade now and boost your website's performance!</div>
458 <div class="king-addons-promo-small">Trusted by 20,000+ users</div>
459 <div class="king-addons-promo-buttons">
460 <a href="https://kingaddons.com/pricing/?utm_source=kng-module-elementor-panel-upgrade&utm_medium=plugin&utm_campaign=kng" target="_blank" class="king-addons-promo-btn king-addons-promo-btn-primary">Upgrade Now</a>
461 <a href="https://kingaddons.com/pricing/?utm_source=kng-module-elementor-panel-lm&utm_medium=plugin&utm_campaign=kng" target="_blank" class="king-addons-promo-btn king-addons-promo-btn-secondary">Learn More</a>
462 </div>
463 `;
464 return promoBlock;
465 }
466
467 function updateHelpPanel(widgetType) {
468 const helpSection = document.querySelector('#elementor-panel__editor__help');
469 if (!helpSection) {
470 return;
471 }
472
473 const helpLink = helpSection.querySelector('#elementor-panel__editor__help__link');
474
475 const shouldShowPromo = !(typeof kingAddonsEditor !== 'undefined' && kingAddonsEditor.isPro);
476 const shouldShowBugReport = !!(widgetType && widgetType.startsWith('king-addons-'));
477
478 let wrapper = helpSection.querySelector('.king-addons-help-wrapper');
479 if (!wrapper) {
480 wrapper = document.createElement('div');
481 wrapper.className = 'king-addons-help-wrapper';
482 helpSection.appendChild(wrapper);
483 }
484
485 // Promo: show for ALL widgets when Pro is not active.
486 const existingPromo = wrapper.querySelector('.king-addons-promo-block');
487 if (shouldShowPromo) {
488 if (!existingPromo) {
489 const promoBlock = createPromoBlock();
490 if (promoBlock) {
491 wrapper.prepend(promoBlock);
492 }
493 }
494 } else if (existingPromo) {
495 existingPromo.remove();
496 }
497
498 // Bug report: only for King Addons widgets.
499 const existingBugReport = wrapper.querySelector('.king-addons-bug-report');
500 if (shouldShowBugReport) {
501 if (!existingBugReport) {
502 wrapper.appendChild(createBugReportSection());
503 }
504 } else if (existingBugReport) {
505 existingBugReport.remove();
506 }
507
508 // Clean up empty wrapper.
509 if (!wrapper.querySelector('.king-addons-promo-block') && !wrapper.querySelector('.king-addons-bug-report')) {
510 wrapper.remove();
511 }
512
513 // Place the Elementor "Need Help" link at the very end when we inject content.
514 // If bug-report is visible (King Addons widget), hide the link entirely.
515 const hasWrapper = !!helpSection.querySelector('.king-addons-help-wrapper');
516 const hasBugReport = !!helpSection.querySelector('.king-addons-bug-report');
517 if (helpLink) {
518 if (hasBugReport) {
519 helpLink.style.display = 'none';
520 } else {
521 helpLink.style.display = '';
522 }
523
524 if (hasWrapper && helpLink.parentNode === helpSection) {
525 helpSection.appendChild(helpLink);
526 }
527 }
528
529 // Toggle layout helper class only when we inject content.
530 if (hasWrapper) {
531 helpSection.classList.add('king-addons-help-injected');
532 } else {
533 helpSection.classList.remove('king-addons-help-injected');
534 }
535 }
536
537 // Hook into Elementor panel events to inject promo (all widgets) + bug report (King Addons only)
538 if (window.elementor) {
539 elementor.hooks.addAction('panel/open_editor/widget', function(panel, model, view) {
540 const widgetType = model.attributes.widgetType;
541
542 // Wait a bit for the panel to fully load, then update help panel.
543 setTimeout(() => {
544 updateHelpPanel(widgetType);
545 }, 100);
546 });
547 }
548
549 // Initial injection if we're already on a widget
550 setTimeout(() => {
551 if (window.elementor && elementor.panel && elementor.panel.currentView) {
552 const currentModel = elementor.panel.currentView.model;
553 const widgetType = currentModel && currentModel.attributes ? currentModel.attributes.widgetType : '';
554 updateHelpPanel(widgetType);
555 }
556 }, 500);
557 })();
558 });
559
560 }(jQuery));