PluginProbe
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder / 51.1.86
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder v51.1.86
51.1.86 51.1.84 51.1.85 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 All 40 releases
← All changes | includes/admin/js/elementor-editor.js +560 -0 51.1.2 → 51.1.86 View file →
@@ -1,0 +1,560 @@
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 = '[email protected]';
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">100+</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));