PluginProbe
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder / 51.1.87
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder v51.1.87
51.1.87 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 All 41 releases
← All changes | includes/admin/js/ai-textfield.js +148 -47 51.1.39 → 51.1.87 View file →
@@ -91,8 +91,64 @@
91 91
92 92 }
93 93 }
94 94
95 + /**
96 + * Flag the editor body when Elementor's panel is dark.
97 + *
98 + * Elementor has no stable "dark panel" class here, and its ui_theme
99 + * preference can be light, dark, or auto (following the OS), so the panel's
100 + * own background is measured instead. That keeps the AI controls readable
101 + * whichever way the theme was arrived at.
102 + */
103 + function syncPanelTheme() {
104 + var isDark = null;
105 +
106 + try {
107 + // Walk up from the control area to the first element that actually
108 + // paints a background. The panel's inner wrappers are transparent,
109 + // so asking any single one of them tells us nothing.
110 + var node = document.querySelector('#elementor-controls')
111 + || document.querySelector('#elementor-panel-content-wrapper')
112 + || document.querySelector('#elementor-panel');
113 +
114 + while (node) {
115 + var parts = getComputedStyle(node).backgroundColor.match(/[\d.]+/g);
116 + if (parts && parts.length >= 3 && (parts.length < 4 || parseFloat(parts[3]) > 0)) {
117 + var luminance = (0.2126 * parts[0] + 0.7152 * parts[1] + 0.0722 * parts[2]) / 255;
118 + isDark = luminance < 0.5;
119 + break;
120 + }
121 + node = node.parentElement;
122 + }
123 + } catch (e) {
124 + // Fall through to the media query below.
125 + }
126 +
127 + if (isDark === null) {
128 + try {
129 + isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
130 + } catch (e) {
131 + isDark = false;
132 + }
133 + }
134 +
135 + $('body').toggleClass('king-addons-ai-dark', !!isDark);
136 + }
137 +
138 + // Keep up with the OS switching themes while the editor is open.
139 + try {
140 + var colorSchemeQuery = window.matchMedia('(prefers-color-scheme: dark)');
141 + var onSchemeChange = function() { syncPanelTheme(); };
142 + if (colorSchemeQuery.addEventListener) {
143 + colorSchemeQuery.addEventListener('change', onSchemeChange);
144 + } else if (colorSchemeQuery.addListener) {
145 + colorSchemeQuery.addListener(onSchemeChange);
146 + }
147 + } catch (e) {
148 + // No media query support: the measured panel background still applies.
149 + }
150 +
95 151 // Add CSS for animations directly to the document
96 152 function injectAnimationStyles() {
97 153 if ($('#king-addons-ai-animations').length === 0) {
98 154 const animationStyles = `
@@ -120,13 +176,11 @@
120 176 animation: kingAddonsPulse 1.5s infinite cubic-bezier(0.66, 0, 0, 1) !important;
121 177 border-color: #5B03FF !important;
122 178 }
123 179 .king-addons-field-shine {
124 - background-image: linear-gradient(90deg,
125 - rgba(91,3,255,0) 0%,
126 - rgba(91,3,255,0.2) 25%,
127 - rgba(225,203,255,0.3) 50%,
128 - rgba(91,3,255,0.2) 75%,
180 + background-image: linear-gradient(90deg,
181 + rgba(91,3,255,0) 0%,
182 + rgba(91,3,255,0.14) 50%,
129 183 rgba(91,3,255,0) 100%);
130 184 background-position: -100px;
131 185 background-size: 140px 100%;
132 186 background-repeat: no-repeat;
@@ -146,18 +200,22 @@
146 200 transition: all 0.3s ease;
147 201 margin-top: 8px;
148 202 width: 100%;
149 203 }
204 + /* These two are unavailable while the prompt is open. Keeping
205 + the violet, only dimmed, reads as "not right now" instead of
206 + a grey block that looks like a styling failure. */
150 207 .king-addons-ai-buttons-wrapper.is-processing .ai-generate-btn,
151 208 .king-addons-ai-buttons-wrapper.is-processing .ai-change-btn {
152 - background: linear-gradient(135deg, #d6d6d6, #a0a0a0) !important;
153 - opacity: 0.7;
209 + background: rgba(91, 3, 255, .05) !important;
210 + color: rgba(74, 2, 214, .42) !important;
154 211 cursor: default;
155 212 box-shadow: none !important;
213 + transform: none !important;
156 214 pointer-events: none;
157 215 }
158 216 .king-addons-ai-buttons-wrapper.is-processing img {
159 - filter: grayscale(100%);
217 + opacity: .4 !important;
160 218 }
161 219 .ai-prompt-container {
162 220 display: flex;
163 221 align-items: center;
@@ -185,16 +243,78 @@
185 243 outline: none;
186 244 }
187 245 .ai-prompt-examples {
188 246 font-size: 11px;
189 - color: #6d7882;
247 + color: #5c666f;
190 248 margin-top: 4px;
191 249 line-height: 1.4;
192 250 }
193 251 .ai-prompt-examples strong {
194 - color: #556068;
195 - font-weight: 500;
252 + color: #3f4750;
253 + font-weight: 600;
196 254 }
255 +
256 + /*
257 + * Elementor's panel can be light or dark, and the setting
258 + * follows the OS when it is set to Auto, so the theme is
259 + * detected at runtime and flagged on <body>. Without this
260 + * the hint text is near-invisible on the dark panel.
261 + */
262 + body.king-addons-ai-dark .ai-prompt-examples {
263 + color: #a7aeb6;
264 + }
265 + body.king-addons-ai-dark .ai-prompt-examples strong {
266 + color: #e6e9ed;
267 + }
268 + body.king-addons-ai-dark .ai-prompt-input {
269 + background: #2a2d32;
270 + border-color: #45494f;
271 + color: #e6e9ed;
272 + }
273 + body.king-addons-ai-dark .ai-prompt-input::placeholder {
274 + color: #8d949c;
275 + }
276 + body.king-addons-ai-dark .ai-prompt-cancel {
277 + background: #2a2d32;
278 + border-color: #45494f;
279 + color: #d5d9de;
280 + }
281 + body.king-addons-ai-dark .ai-prompt-cancel:hover {
282 + background: #35393f;
283 + }
284 + body.king-addons-ai-dark .king-addons-ai-buttons-wrapper.is-processing .ai-generate-btn,
285 + body.king-addons-ai-dark .king-addons-ai-buttons-wrapper.is-processing .ai-change-btn {
286 + background: rgba(124, 77, 255, .09) !important;
287 + color: rgba(201, 182, 255, .45) !important;
288 + }
289 +
290 + /* The tint needs a lighter hue and a brighter label on the
291 + dark panel; the light-panel values are in ai-textfield.css. */
292 + body.king-addons-ai-dark .ai-generate-btn,
293 + body.king-addons-ai-dark .ai-change-btn {
294 + --ka-ai-btn-bg: rgba(124, 77, 255, .22);
295 + --ka-ai-btn-bg-hover: rgba(124, 77, 255, .32);
296 + --ka-ai-btn-bg-active: rgba(124, 77, 255, .40);
297 + --ka-ai-btn-fg: #C9B6FF;
298 + --ka-ai-btn-ring: #8C7DFF;
299 + }
300 +
301 + body.king-addons-ai-dark .ai-generate-btn img,
302 + body.king-addons-ai-dark .ai-change-btn img {
303 + /* The icon files are white already - let them through. */
304 + filter: none;
305 + opacity: .92;
306 + }
307 +
308 + body.king-addons-ai-dark .ai-prompt-submit {
309 + background: #7C4DFF;
310 + color: #ffffff;
311 + border-color: transparent;
312 + }
313 +
314 + body.king-addons-ai-dark .ai-prompt-submit:hover {
315 + background: #6B3DEE;
316 + }
197 317 .ai-prompt-cancel {
198 318 width: 24px;
199 319 height: 24px;
200 320 display: flex;
@@ -221,9 +341,9 @@
221 341 cursor: pointer;
222 342 transition: all 0.3s ease;
223 343 }
224 344 .ai-prompt-submit.is-processing {
225 - background: linear-gradient(135deg, #E1CBFF, #5B03FF) !important;
345 + background: #5B03FF !important;
226 346 border-color: transparent !important;
227 347 }
228 348 .ai-prompt-submit.is-processing img {
229 349 animation: kingAddonsRotatePulse 2s infinite ease-in-out;
@@ -250,8 +370,11 @@
250 370 function injectAiButtons($container) {
251 371
252 372 // Inject animation styles first
253 373 injectAnimationStyles();
374 +
375 + // The panel is rebuilt on every open, so re-check the theme here.
376 + syncPanelTheme();
254 377
255 378 // Handle standard text/textarea controls
256 379 $container.find('.elementor-control-type-text label.elementor-control-title, .elementor-control-type-textarea label.elementor-control-title').each(function(){
257 380 var $label = $(this);
@@ -305,31 +428,15 @@
305 428 if (!$inputWrapper.length) return;
306 429 }
307 430
308 431 // Create "Generate" button
309 - var $btnLabel = $('<button type="button" class="ai-generate-btn ai-generate-btn--futuristic" title="AI Generate"></button>').css({
310 - verticalAlign: 'middle',
311 - padding: '4px 8px',
312 - fontSize: '12px',
313 - cursor: 'pointer',
314 - background: 'linear-gradient(135deg, #E1CBFF, #5B03FF)',
315 - border: 'none',
316 - borderRadius: '4px',
317 - color: '#ffffff',
318 - display: 'inline-flex',
319 - alignItems: 'center',
320 - // boxShadow: '0 0 6px rgba(225,203,255,0.7), 0 0 12px rgba(91,3,255,0.5)',
321 - boxShadow: 'none',
322 - transition: 'box-shadow 0.3s ease'
323 - });
432 + // Appearance lives in ai-textfield.css so the buttons get real hover,
433 + // active, focus and disabled states instead of inline overrides.
434 + var $btnLabel = $('<button type="button" class="ai-generate-btn" title="AI Generate"></button>');
324 435 $btnLabel.append(
325 - $('<img>').attr('src', KingAddonsAiField.icon_url).css({ marginRight: '6px', width: '16px', height: '16px', verticalAlign: 'middle' }),
436 + $('<img>').attr({ src: KingAddonsAiField.icon_url, alt: '' }),
326 437 $('<span>').addClass('ai-generate-btn__label').text('AI Generate')
327 438 );
328 - $btnLabel.hover(
329 - function() { $(this).css('boxShadow', '0 0 8px rgba(225,203,255,0.9), 0 0 16px rgba(91,3,255,0.7)'); },
330 - function() { $(this).css('boxShadow', 'none'); }
331 - );
332 439
333 440 // Create "Change" button
334 441 var $changeBtn = $btnLabel.clone();
335 442 $changeBtn.removeClass('ai-generate-btn').addClass('ai-change-btn');
@@ -335,14 +442,8 @@
335 442 $changeBtn.removeClass('ai-generate-btn').addClass('ai-change-btn');
336 443 $changeBtn.find('span.ai-generate-btn__label').text('AI Change');
337 444 $changeBtn.attr('title', 'AI Change');
338 445 $changeBtn.find('img').attr('src', KingAddonsAiField.rewrite_icon_url || KingAddonsAiField.plugin_url + '/includes/admin/img/ai-rewrite.svg');
339 -
340 - // Add hover effect to the change button - cloning doesn't preserve hover handlers
341 - $changeBtn.hover(
342 - function() { $(this).css('boxShadow', '0 0 8px rgba(225,203,255,0.9), 0 0 16px rgba(91,3,255,0.7)'); },
343 - function() { $(this).css('boxShadow', 'none'); }
344 - );
345 446
346 447 // Add buttons to wrapper
347 448 $buttonsWrapper.append($btnLabel).append($changeBtn);
348 449
@@ -390,9 +491,9 @@
390 491 var settingsUrl = window.KingAddonsAiField && window.KingAddonsAiField.settings_url
391 492 ? window.KingAddonsAiField.settings_url
392 493 : '/wp-admin/admin.php?page=king-addons-ai-settings';
393 494 $errorMessage.html(
394 - '<span>OpenAI API key is missing or invalid. Please configure your API key in AI Settings.</span>' +
495 + '<span>' + ((window.KingAddonsAiField && KingAddonsAiField.missing_key_message) || 'The AI API key is missing or invalid. Please configure your API key in AI Settings.') + '</span>' +
395 496 '<a href="' + settingsUrl + '" style="color:#0073aa;text-decoration:underline;white-space:nowrap;margin-left:10px;" target="_blank">Settings</a>'
396 497 );
397 498 $errorMessage.insertAfter($buttonsWrapper).hide().fadeIn(200);
398 499 setTimeout(function() { $errorMessage.fadeOut(200, function() { $(this).remove(); }); }, 5000);
@@ -497,9 +598,9 @@
497 598 // Also try to add a class to the iframe body
498 599 try {
499 600 $($iframe[0].contentDocument.body).addClass('king-addons-field-shine');
500 601 } catch(e) {
501 - console.error('Could not access iframe body', e);
602 + // console.error('Could not access iframe body', e);
502 603 }
503 604 }
504 605 } else {
505 606 // For regular text inputs and textareas
@@ -536,9 +637,9 @@
536 637 $iframe.removeClass('king-addons-wysiwyg-active');
537 638 try {
538 639 $($iframe[0].contentDocument.body).removeClass('king-addons-field-shine');
539 640 } catch(e) {
540 - console.error('Could not access iframe body', e);
641 + // console.error('Could not access iframe body', e);
541 642 }
542 643 }
543 644 } else {
544 645 $field.removeClass('king-addons-field-pulsing king-addons-field-shine');
@@ -588,9 +689,9 @@
588 689 var settingsUrl = window.KingAddonsAiField && window.KingAddonsAiField.settings_url
589 690 ? window.KingAddonsAiField.settings_url
590 691 : '/wp-admin/admin.php?page=king-addons-ai-settings';
591 692 $errorMessage.html(
592 - '<span>OpenAI API key is missing or invalid. Please configure your API key in AI Settings.</span>' +
693 + '<span>' + ((window.KingAddonsAiField && KingAddonsAiField.missing_key_message) || 'The AI API key is missing or invalid. Please configure your API key in AI Settings.') + '</span>' +
593 694 '<a href="' + settingsUrl + '" style="color:#0073aa;text-decoration:underline;white-space:nowrap;margin-left:10px;" target="_blank">Settings</a>'
594 695 );
595 696 $errorMessage.insertAfter($buttonsWrapper).hide().fadeIn(200);
596 697 setTimeout(function() { $errorMessage.fadeOut(200, function() { $(this).remove(); }); }, 5000);
@@ -693,9 +794,9 @@
693 794 // Also try to add a class to the iframe body
694 795 try {
695 796 $($iframe[0].contentDocument.body).addClass('king-addons-field-shine');
696 797 } catch(e) {
697 - console.error('Could not access iframe body', e);
798 + // console.error('Could not access iframe body', e);
698 799 }
699 800 }
700 801 } else {
701 802 // For regular text inputs and textareas
@@ -733,9 +834,9 @@
733 834 $iframe.removeClass('king-addons-wysiwyg-active');
734 835 try {
735 836 $($iframe[0].contentDocument.body).removeClass('king-addons-field-shine');
736 837 } catch(e) {
737 - console.error('Could not access iframe body', e);
838 + // console.error('Could not access iframe body', e);
738 839 }
739 840 }
740 841 } else {
741 842 $field.removeClass('king-addons-field-pulsing king-addons-field-shine');
@@ -769,9 +870,9 @@
769 870 // Log for debugging
770 871
771 872 // Check if we have a valid editor ID
772 873 if (!editorId) {
773 - console.error('King Addons: No editor ID found for WYSIWYG field');
874 + // console.error('King Addons: No editor ID found for WYSIWYG field');
774 875 if (appendMode) {
775 876 // Append the new content to the original
776 877 $field.val(originalContent + '\n\n' + value);
777 878 } else {
@@ -871,9 +972,9 @@
871 972 $field.val(value);
872 973 }
873 974 }
874 975 } catch (e) {
875 - console.error('King Addons: Error updating WYSIWYG content', e);
976 + // console.error('King Addons: Error updating WYSIWYG content', e);
876 977 // Fallback - set the textarea value directly
877 978 if (appendMode) {
878 979 // Maintain HTML structure in fallback case
879 980 var existingContent = originalContent || '';
@@ -910,9 +1011,9 @@
910 1011 if (isWysiwyg && window.tinymce && tinymce.get($field.attr('id'))) {
911 1012 try {
912 1013 tinymce.get($field.attr('id')).fire('change');
913 1014 } catch (e) {
914 - console.error('King Addons: Error triggering TinyMCE change event', e);
1015 + // console.error('King Addons: Error triggering TinyMCE change event', e);
915 1016 }
916 1017 }
917 1018 }
918 1019