PluginProbe
Master Addons for Elementor – Elementor Addons, Widgets, Mega Menu Builder, Popup Builder, Widget Builder & Template Kits / 3.1.2
Master Addons for Elementor – Elementor Addons, Widgets, Mega Menu Builder, Popup Builder, Widget Builder & Template Kits v3.1.2
3.2.2 3.2.3 3.2.1 3.2.0 3.1.9 3.1.8 3.1.7 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.9 trunk 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.3 1.1.4 1.1.5 All 174 releases
master-addons / assets / js / admin / widget-admin.js

widget-admin.js in Master Addons for Elementor – Elementor Addons, Widgets, Mega Menu Builder, Popup Builder, Widget Builder & Template Kits 3.1.2, at assets/js/admin/widget-admin.js

791 lines 32.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function(){
2 var STYLE_ID = "jltma-dialog-styles";
3 var PORTAL_ID = "jltma-dialog-portal";
4 var CSS = [
5 /* z-index must beat the template-library uploader modal (999999)
6 and match the shared shadcn DialogOverlay/DialogContent convention
7 (9999999). The dialog is the topmost interactive layer in the admin,
8 so we anchor at one more order of magnitude to leave room underneath. */
9 ".jltma-dialog{position:fixed;inset:0;z-index:9999999;display:flex;align-items:center;justify-content:center;animation:jltma-dialog-fade-in 0.15s ease-out;}",
10 ".jltma-dialog__overlay{position:absolute;inset:0;background:rgba(15,23,42,0.55);backdrop-filter:blur(1.5px);-webkit-backdrop-filter:blur(1.5px);}",
11 '.jltma-dialog__content{position:relative;z-index:1;width:min(460px,calc(100% - 32px));background:var(--jltma-popover,#ffffff);color:var(--jltma-popover-foreground,#0f172a);border:1px solid var(--jltma-border,#e2e8f0);border-radius:var(--jltma-radius,10px);box-shadow:0 20px 48px rgba(15,23,42,0.24),0 8px 16px rgba(15,23,42,0.12);padding:24px;box-sizing:border-box;animation:jltma-dialog-scale-in 0.18s cubic-bezier(0.16,1,0.3,1);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;}',
12 ".jltma-dialog__title{margin:0 0 10px;font-size:18px;font-weight:600;line-height:1.35;letter-spacing:-0.01em;color:var(--jltma-foreground,#0f172a);}",
13 ".jltma-dialog__message{margin:0 0 24px;font-size:14px;line-height:1.55;color:var(--jltma-muted-foreground,#475569);white-space:pre-line;}",
14 ".jltma-dialog__actions{display:flex;justify-content:flex-end;gap:10px;flex-wrap:wrap;}",
15 ".jltma-dialog__btn{appearance:none;border:1px solid transparent;border-radius:calc(var(--jltma-radius,10px) - 2px);height:36px;padding:0 16px;font-size:13px;font-weight:600;line-height:1;cursor:pointer;transition:background-color 0.15s ease,border-color 0.15s ease,color 0.15s ease,box-shadow 0.15s ease,opacity 0.15s ease;font-family:inherit;display:inline-flex;align-items:center;justify-content:center;gap:6px;}",
16 ".jltma-dialog__btn:focus-visible{outline:2px solid var(--jltma-ring,rgba(104,20,205,0.45));outline-offset:2px;}",
17 ".jltma-dialog__btn:disabled{opacity:0.6;cursor:not-allowed;}",
18 ".jltma-dialog__btn--secondary{background:var(--jltma-background,#ffffff);border-color:var(--jltma-border,#e2e8f0);color:var(--jltma-foreground,#334155);}",
19 ".jltma-dialog__btn--secondary:hover:not(:disabled){background:var(--jltma-accent,#f1f5f9);border-color:var(--jltma-border,#cbd5e1);}",
20 ".jltma-dialog__btn--primary{background:var(--jltma-primary,#6814cd);color:var(--jltma-primary-foreground,#ffffff);}",
21 ".jltma-dialog__btn--primary:hover:not(:disabled){opacity:0.9;}",
22 ".jltma-dialog__btn--danger{background:var(--jltma-destructive,#dc2626);color:#ffffff;}",
23 ".jltma-dialog__btn--danger:hover:not(:disabled){opacity:0.9;}",
24 ".jltma-dialog__btn--success{background:#16a34a;color:#ffffff;}",
25 ".jltma-dialog__btn--success:hover:not(:disabled){opacity:0.9;}",
26 ".jltma-dialog__btn--warning{background:#d97706;color:#ffffff;}",
27 ".jltma-dialog__btn--warning:hover:not(:disabled){opacity:0.9;}",
28 ".jltma-dialog--loading .jltma-dialog__content{padding:32px 28px;width:min(340px,calc(100% - 32px));text-align:center;}",
29 ".jltma-dialog--loading .jltma-dialog__message{margin:0;color:var(--jltma-foreground,#0f172a);font-weight:500;font-size:14px;}",
30 ".jltma-dialog__spinner{width:36px;height:36px;border:3px solid var(--jltma-border,#e2e8f0);border-top-color:var(--jltma-primary,#6814cd);border-radius:50%;margin:0 auto 16px;animation:jltma-dialog-spin 0.8s linear infinite;}",
31 "@keyframes jltma-dialog-fade-in{from{opacity:0;}to{opacity:1;}}",
32 "@keyframes jltma-dialog-scale-in{from{opacity:0;transform:scale(0.94) translateY(4px);}to{opacity:1;transform:scale(1) translateY(0);}}",
33 "@keyframes jltma-dialog-spin{to{transform:rotate(360deg);}}"
34 ].join("");
35 function ensureStyles() {
36 if (typeof document === "undefined") return;
37 if (document.getElementById(STYLE_ID)) return;
38 var style = document.createElement("style");
39 style.id = STYLE_ID;
40 style.textContent = CSS;
41 document.head.appendChild(style);
42 }
43 function ensurePortal() {
44 var portal = document.getElementById(PORTAL_ID);
45 if (!portal) {
46 portal = document.createElement("div");
47 portal.id = PORTAL_ID;
48 document.body.appendChild(portal);
49 }
50 return portal;
51 }
52 function openDialog(opts) {
53 return new Promise(function(resolve) {
54 ensureStyles();
55 var portal = ensurePortal();
56 var tone = opts.tone || "primary";
57 var showCancel = !!opts.showCancel;
58 var root = document.createElement("div");
59 root.className = "jltma-dialog";
60 var overlay = document.createElement("div");
61 overlay.className = "jltma-dialog__overlay";
62 var content = document.createElement("div");
63 content.className = "jltma-dialog__content jltma-dialog-tone-" + tone;
64 content.setAttribute("role", "alertdialog");
65 content.setAttribute("aria-modal", "true");
66 if (opts.title) {
67 var titleEl = document.createElement("h3");
68 titleEl.className = "jltma-dialog__title";
69 titleEl.textContent = opts.title;
70 content.appendChild(titleEl);
71 }
72 if (opts.message) {
73 var msgEl = document.createElement("p");
74 msgEl.className = "jltma-dialog__message";
75 msgEl.textContent = opts.message;
76 content.appendChild(msgEl);
77 }
78 var actions = document.createElement("div");
79 actions.className = "jltma-dialog__actions";
80 var cleanup = function(value) {
81 document.removeEventListener("keydown", onKey);
82 overlay.removeEventListener("click", onOverlay);
83 if (root.parentNode) root.parentNode.removeChild(root);
84 resolve(value);
85 };
86 var onKey = function(e) {
87 if (e.key === "Escape") {
88 e.preventDefault();
89 cleanup(false);
90 } else if (e.key === "Enter") {
91 e.preventDefault();
92 cleanup(true);
93 }
94 };
95 document.addEventListener("keydown", onKey);
96 var onOverlay = function() {
97 cleanup(false);
98 };
99 overlay.addEventListener("click", onOverlay);
100 if (showCancel) {
101 var cancelBtn = document.createElement("button");
102 cancelBtn.type = "button";
103 cancelBtn.className = "jltma-dialog__btn jltma-dialog__btn--secondary";
104 cancelBtn.textContent = opts.cancelText || "Cancel";
105 cancelBtn.addEventListener("click", function() {
106 cleanup(false);
107 });
108 actions.appendChild(cancelBtn);
109 }
110 var confirmBtn = document.createElement("button");
111 confirmBtn.type = "button";
112 confirmBtn.className = "jltma-dialog__btn jltma-dialog__btn--" + tone;
113 confirmBtn.textContent = opts.confirmText || "OK";
114 confirmBtn.addEventListener("click", function() {
115 cleanup(true);
116 });
117 actions.appendChild(confirmBtn);
118 content.appendChild(actions);
119 root.appendChild(overlay);
120 root.appendChild(content);
121 portal.appendChild(root);
122 try {
123 confirmBtn.focus({ preventScroll: true });
124 } catch (e) {
125 confirmBtn.focus();
126 }
127 });
128 }
129 function confirmDialog(options) {
130 var opts = options || {};
131 return openDialog({
132 title: opts.title || "Are you sure?",
133 message: opts.message || "",
134 confirmText: opts.confirmText || "Confirm",
135 cancelText: opts.cancelText || "Cancel",
136 tone: opts.tone || "primary",
137 showCancel: true
138 });
139 }
140 function alertDialog(options) {
141 var opts = options || {};
142 return openDialog({
143 title: opts.title || "Notice",
144 message: opts.message || "",
145 confirmText: opts.confirmText || "OK",
146 tone: opts.tone || "primary",
147 showCancel: false
148 });
149 }
150 function loadingDialog(options) {
151 var opts = options || {};
152 ensureStyles();
153 var portal = ensurePortal();
154 var root = document.createElement("div");
155 root.className = "jltma-dialog jltma-dialog--loading";
156 var overlay = document.createElement("div");
157 overlay.className = "jltma-dialog__overlay";
158 var content = document.createElement("div");
159 content.className = "jltma-dialog__content";
160 content.setAttribute("role", "status");
161 content.setAttribute("aria-live", "polite");
162 var spinner = document.createElement("div");
163 spinner.className = "jltma-dialog__spinner";
164 spinner.setAttribute("aria-hidden", "true");
165 content.appendChild(spinner);
166 var msgEl = document.createElement("p");
167 msgEl.className = "jltma-dialog__message";
168 msgEl.textContent = opts.message || "Working…";
169 content.appendChild(msgEl);
170 root.appendChild(overlay);
171 root.appendChild(content);
172 portal.appendChild(root);
173 var closed = false;
174 return {
175 close: function() {
176 if (closed) return;
177 closed = true;
178 if (root.parentNode) root.parentNode.removeChild(root);
179 },
180 setMessage: function(next) {
181 msgEl.textContent = next;
182 }
183 };
184 }
185 if (typeof window !== "undefined") {
186 window.JLTMA_Dialog = window.JLTMA_Dialog || {};
187 window.JLTMA_Dialog.confirm = confirmDialog;
188 window.JLTMA_Dialog.alert = alertDialog;
189 window.JLTMA_Dialog.loading = loadingDialog;
190 }
191 const dialog = { confirmDialog, alertDialog, loadingDialog };
192 ;
193 (function($) {
194 "use strict";
195 var JLTMA_Toaster = {
196 container: null,
197 init: function() {
198 if (!this.container) {
199 this.container = $('<div class="jltma-toaster-container"></div>');
200 $("body").append(this.container);
201 }
202 },
203 show: function(message, type = "success", duration = 3e3) {
204 this.init();
205 var toaster = $(`
206 <div class="jltma-toaster ${type}">
207 <span class="jltma-toaster-icon ${type}-icon"></span>
208 <span class="jltma-toaster-content">${message}</span>
209 <button class="jltma-toaster-close"></button>
210 <div class="jltma-toaster-progress"></div>
211 </div>
212 `);
213 this.container.append(toaster);
214 toaster.find(".jltma-toaster-close").on("click", function() {
215 JLTMA_Toaster.dismiss(toaster);
216 });
217 if (duration > 0) {
218 setTimeout(function() {
219 JLTMA_Toaster.dismiss(toaster);
220 }, duration);
221 }
222 return toaster;
223 },
224 dismiss: function(toaster) {
225 toaster.addClass("jltma-toaster-exit");
226 setTimeout(function() {
227 toaster.remove();
228 }, 300);
229 },
230 success: function(message, duration) {
231 return this.show(message, "success", duration);
232 },
233 error: function(message, duration) {
234 return this.show(message, "error", duration);
235 },
236 warning: function(message, duration) {
237 return this.show(message, "warning", duration);
238 },
239 info: function(message, duration) {
240 return this.show(message, "info", duration);
241 }
242 };
243 const WidgetAdmin = {
244 init: function() {
245 this.bindEvents();
246 this.setupNativeCPTList();
247 },
248 /**
249 * Setup native CPT list table interception
250 * Intercept WP's native "Add New" button and inject extra buttons
251 */
252 setupNativeCPTList: function() {
253 var self = this;
254 $(document).on("click", ".wrap .page-title-action:not(.jltma-cpt-btn)", function(e) {
255 e.preventDefault();
256 self.openModal(e);
257 });
258 var $addNewBtn = $(".wrap .page-title-action").first();
259 if ($addNewBtn.length) {
260 $addNewBtn.text("Add New Widget");
261 if (!$(".jltma-import-widget").length) {
262 $addNewBtn.after(
263 '<a href="#" class="jltma-cpt-btn jltma-cpt-btn-secondary jltma-import-widget"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg> Import Widget</a><a href="https://master-addons.com/widget-builder/" target="_blank" class="jltma-cpt-btn jltma-cpt-btn-youtube"><svg width="16" height="16" viewBox="0 0 24 24" fill="#ff0000"><path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.546 12 3.546 12 3.546s-7.505 0-9.377.504A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.504 9.376.504 9.376.504s7.505 0 9.377-.504a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"/></svg> Video Tutorial</a>'
264 );
265 }
266 }
267 },
268 bindEvents: function() {
269 $(document).on("click", ".jltma-add-new-widget", this.openModal.bind(this));
270 $(document).on("change", "#jltma_widget_category", this.handleCategoryChange.bind(this));
271 $(document).on("click", ".jltma-cancel-inline-category", this.hideInlineCategoryAdd.bind(this));
272 $(document).on("click", ".jltma-save-inline-category", this.saveInlineCategory.bind(this));
273 $(document).on("click", ".jltma-pop-close, .close-btn, .jltma-modal-backdrop", this.closeModal.bind(this));
274 $(document).on("click", ".jltma-import-widget", this.openImportModal.bind(this));
275 $(document).on("click", ".jltma-import-close, .jltma-import-backdrop", this.closeImportModal.bind(this));
276 $(document).on("change", "#jltma-import-file", this.handleFileSelect.bind(this));
277 $(document).on("keydown", function(e) {
278 if (e.key === "Escape" || e.keyCode === 27) {
279 if ($("#jltma_import_widget_modal").is(":visible")) {
280 $("#jltma_import_widget_modal").fadeOut(300);
281 $("body").removeClass("jltma-modal-open");
282 WidgetAdmin.resetImportModal();
283 }
284 }
285 });
286 $(document).on("dragover", "#jltma-dropzone", this.handleDragOver.bind(this));
287 $(document).on("dragleave", "#jltma-dropzone", this.handleDragLeave.bind(this));
288 $(document).on("drop", "#jltma-dropzone", this.handleDrop.bind(this));
289 $(document).on("keypress", "#jltma_new_category_title", function(e) {
290 if (e.which === 13) {
291 e.preventDefault();
292 $(".jltma-save-inline-category").trigger("click");
293 }
294 });
295 $(document).on("keydown", "#jltma_new_category_title", function(e) {
296 if (e.which === 27) {
297 e.preventDefault();
298 $(".jltma-cancel-inline-category").trigger("click");
299 }
300 });
301 $(document).on("submit", "#jltma-widget-form", this.saveWidget.bind(this));
302 $(document).on("click", ".jltma-save-widget", function(e) {
303 e.preventDefault();
304 $("#jltma-widget-form").trigger("submit");
305 });
306 $(document).on("click", ".jltma-delete-widget", this.deleteWidget.bind(this));
307 $(document).on("click", ".jltma-copy-shortcode-widget", this.copyShortcode.bind(this));
308 $(document).on("click", ".jltma-widget-edit-category, .jltma-widget-edit-cond", this.openModalFromConditions.bind(this));
309 },
310 openModal: function(e) {
311 e.preventDefault();
312 var $target = $(e.currentTarget);
313 var widgetId = $target.data("widget-id") || 0;
314 var modal = $("#jltma_widget_builder_modal");
315 modal.addClass("loading");
316 modal.addClass("active");
317 $("body").addClass("jltma-modal-open");
318 if (widgetId > 0) {
319 modal.find(".jltma-modal-title").text("Edit Widget");
320 $("#jltma_widget_id").val(widgetId);
321 this.loadWidgetData(widgetId);
322 } else {
323 modal.find(".jltma-modal-title").text("Create New Widget");
324 this.resetForm();
325 modal.removeClass("loading");
326 }
327 modal.find("form").attr("data-widget-id", widgetId);
328 },
329 closeModal: function(e) {
330 if ($(e.target).hasClass("jltma-modal-backdrop") || $(e.target).hasClass("close-btn") || $(e.target).closest(".jltma-pop-close").length) {
331 $("#jltma_widget_builder_modal").removeClass("active");
332 $("#jltma_category_modal").removeClass("active");
333 $("body").removeClass("jltma-modal-open");
334 e.preventDefault();
335 }
336 },
337 resetForm: function() {
338 var form = $("#jltma-widget-form");
339 form[0].reset();
340 $("#jltma_widget_id").val("");
341 var categorySelect = $("select#jltma_widget_category");
342 var initialValue = categorySelect.val() || "general";
343 categorySelect.data("previous-value", initialValue);
344 $("#jltma-inline-category-add").hide();
345 $("#jltma_new_category_title").val("");
346 },
347 loadWidgetData: function(widgetId) {
348 var self = this;
349 var modal = $("#jltma_widget_builder_modal");
350 $.ajax({
351 url: jltmaWidgetAdmin.ajax_url,
352 type: "GET",
353 data: {
354 action: "jltma_widget_get_data",
355 widget_id: widgetId,
356 _nonce: jltmaWidgetAdmin.widget_nonce
357 },
358 success: function(response) {
359 if (response.success) {
360 $("#jltma_widget_id").val(widgetId);
361 $("#jltma_widget_title").val(response.data.title);
362 var categoryDropdown = $("select#jltma_widget_category");
363 var categoryValue = response.data.category || "general";
364 categoryDropdown.val(categoryValue);
365 categoryDropdown.data("previous-value", categoryValue);
366 $("#jltma-inline-category-add").hide();
367 $("#jltma_new_category_title").val("");
368 }
369 modal.removeClass("loading");
370 },
371 error: function(xhr, status, error) {
372 modal.removeClass("loading");
373 JLTMA_Toaster.error(jltmaWidgetAdmin.strings.error);
374 }
375 });
376 },
377 handleCategoryChange: function(e) {
378 var $select = $(e.currentTarget);
379 var selectedValue = $select.val();
380 if (selectedValue === "__add_new__") {
381 var previousValue = $select.data("previous-value") || "general";
382 $select.data("previous-value", previousValue);
383 $("#jltma-inline-category-add").slideDown(200);
384 $("#jltma_new_category_title").val("").focus();
385 } else {
386 $select.data("previous-value", selectedValue);
387 }
388 },
389 showInlineCategoryAdd: function(e) {
390 e.preventDefault();
391 $("#jltma-inline-category-add").slideDown(200);
392 $("#jltma_new_category_title").focus();
393 },
394 hideInlineCategoryAdd: function(e) {
395 e.preventDefault();
396 var categorySelect = $("select#jltma_widget_category");
397 var previousValue = categorySelect.data("previous-value") || "general";
398 $("#jltma-inline-category-add").slideUp(200);
399 $("#jltma_new_category_title").val("");
400 categorySelect.val(previousValue);
401 },
402 saveInlineCategory: function(e) {
403 e.preventDefault();
404 var title = $("#jltma_new_category_title").val().trim();
405 var categorySelect = $("select#jltma_widget_category");
406 var saveBtn = $(".jltma-save-inline-category");
407 if (!title) {
408 JLTMA_Toaster.error("Category title is required.");
409 return;
410 }
411 var originalText = saveBtn.text();
412 saveBtn.prop("disabled", true).text("Saving...");
413 var slug = title.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").trim();
414 $.ajax({
415 url: jltmaWidgetAdmin.admin_url + "admin-ajax.php?rest_route=/jltma/v1/categories",
416 type: "POST",
417 headers: {
418 "X-WP-Nonce": jltmaWidgetAdmin.widget_nonce
419 },
420 contentType: "application/json",
421 data: JSON.stringify({
422 name: title,
423 slug
424 }),
425 success: function(response) {
426 if (response.success && response.data) {
427 var newSlug = response.data.slug;
428 var newTitle = response.data.title;
429 if (categorySelect.find('option[value="' + newSlug + '"]').length === 0) {
430 categorySelect.find('option[value="__add_new__"]').before(
431 '<option value="' + newSlug + '">' + newTitle + "</option>"
432 );
433 }
434 categorySelect.val(newSlug);
435 categorySelect.data("previous-value", newSlug);
436 $("#jltma-inline-category-add").slideUp(200);
437 $("#jltma_new_category_title").val("");
438 JLTMA_Toaster.success(jltmaWidgetAdmin.strings.category_added);
439 } else {
440 JLTMA_Toaster.error("Failed to create category. Please try again.");
441 categorySelect.val(categorySelect.data("previous-value") || "general");
442 }
443 saveBtn.prop("disabled", false).text(originalText);
444 },
445 error: function(xhr, status, error) {
446 JLTMA_Toaster.error("Failed to create category. Please try again.");
447 categorySelect.val(categorySelect.data("previous-value") || "general");
448 saveBtn.prop("disabled", false).text(originalText);
449 }
450 });
451 },
452 saveWidget: function(e) {
453 e.preventDefault();
454 var form = $("#jltma-widget-form");
455 var submitBtn = $(".jltma-save-widget");
456 var widgetId = $("#jltma_widget_id").val();
457 var title = $("#jltma_widget_title").val().trim();
458 var category = $("select#jltma_widget_category").val();
459 if (!title) {
460 JLTMA_Toaster.error(jltmaWidgetAdmin.strings.widget_title_required);
461 return;
462 }
463 var originalText = submitBtn.text();
464 submitBtn.prop("disabled", true).text(jltmaWidgetAdmin.strings.saving);
465 $.ajax({
466 url: jltmaWidgetAdmin.ajax_url,
467 type: "POST",
468 data: {
469 action: "jltma_widget_save_data",
470 widget_id: widgetId,
471 widget_title: title,
472 widget_category: category,
473 _nonce: jltmaWidgetAdmin.widget_nonce
474 },
475 success: function(response) {
476 if (response.success) {
477 if (widgetId) {
478 var categoryName = $("select#jltma_widget_category option:selected").text();
479 $("#jltma_widget_builder_modal").removeClass("active");
480 $("body").removeClass("jltma-modal-open");
481 var $row = $("#post-" + widgetId);
482 var $categoryColumn = $row.find("td.column-jltma_widget_category");
483 $categoryColumn.html(
484 '<span class="jltma-widget-category">' + categoryName + '</span><br><a href="#" class="jltma-widget-edit-category" data-post-id="' + widgetId + '" data-category="' + category + '"><span class="dashicons dashicons-edit"></span> Edit Category</a>'
485 );
486 JLTMA_Toaster.success(jltmaWidgetAdmin.strings.saved);
487 } else {
488 window.location.href = response.data.edit_url;
489 }
490 } else {
491 JLTMA_Toaster.error(response.data.message || jltmaWidgetAdmin.strings.error);
492 submitBtn.prop("disabled", false).text(originalText);
493 }
494 },
495 error: function(xhr, status, error) {
496 JLTMA_Toaster.error(jltmaWidgetAdmin.strings.error);
497 submitBtn.prop("disabled", false).text(originalText);
498 }
499 });
500 },
501 deleteWidget: function(e) {
502 e.preventDefault();
503 var widgetId = $(e.currentTarget).data("widget-id");
504 if (!confirm(jltmaWidgetAdmin.strings.confirm_delete)) {
505 return;
506 }
507 $.ajax({
508 url: jltmaWidgetAdmin.ajax_url,
509 type: "POST",
510 data: {
511 action: "jltma_widget_delete",
512 widget_id: widgetId,
513 _nonce: jltmaWidgetAdmin.widget_nonce
514 },
515 success: function(response) {
516 if (response.success) {
517 location.reload();
518 } else {
519 JLTMA_Toaster.error(response.data.message || jltmaWidgetAdmin.strings.error);
520 }
521 },
522 error: function() {
523 JLTMA_Toaster.error(jltmaWidgetAdmin.strings.error);
524 }
525 });
526 },
527 copyShortcode: function(e) {
528 e.preventDefault();
529 var shortcode = $(e.currentTarget).data("shortcode");
530 var button = $(e.currentTarget);
531 var temp = $("<textarea>");
532 $("body").append(temp);
533 temp.val(shortcode).select();
534 document.execCommand("copy");
535 temp.remove();
536 var originalHtml = button.html();
537 button.html('<span class="dashicons dashicons-yes"></span> ' + jltmaWidgetAdmin.strings.copied);
538 setTimeout(function() {
539 button.html(originalHtml);
540 }, 2e3);
541 },
542 openModalFromConditions: function(e) {
543 e.preventDefault();
544 var widgetId = $(e.currentTarget).data("post-id") || $(e.currentTarget).attr("id");
545 var modal = $("#jltma_widget_builder_modal");
546 modal.addClass("loading");
547 modal.addClass("active");
548 $("body").addClass("jltma-modal-open");
549 if (widgetId > 0) {
550 modal.find(".jltma-modal-title").text("Edit Widget");
551 $("#jltma_widget_id").val(widgetId);
552 this.loadWidgetData(widgetId);
553 }
554 modal.find("form").attr("data-widget-id", widgetId);
555 },
556 // Import Widget Functions
557 openImportModal: function(e) {
558 e.preventDefault();
559 $("#jltma_import_widget_modal").fadeIn(300);
560 $("body").addClass("jltma-modal-open");
561 },
562 closeImportModal: function(e) {
563 if ($(e.target).hasClass("jltma-import-backdrop") || $(e.target).hasClass("jltma-import-close") || $(e.target).closest(".jltma-import-close").length) {
564 $("#jltma_import_widget_modal").fadeOut(300);
565 $("body").removeClass("jltma-modal-open");
566 this.resetImportModal();
567 e.preventDefault();
568 }
569 },
570 resetImportModal: function() {
571 $("#jltma-dropzone").removeClass("dragging");
572 $(".jltma-dropzone-content").show();
573 $(".jltma-importing").hide();
574 $("#jltma-import-file").val("");
575 },
576 handleDragOver: function(e) {
577 e.preventDefault();
578 e.stopPropagation();
579 $("#jltma-dropzone").addClass("dragging");
580 },
581 handleDragLeave: function(e) {
582 e.preventDefault();
583 e.stopPropagation();
584 $("#jltma-dropzone").removeClass("dragging");
585 },
586 handleDrop: function(e) {
587 e.preventDefault();
588 e.stopPropagation();
589 $("#jltma-dropzone").removeClass("dragging");
590 var files = e.originalEvent.dataTransfer.files;
591 if (files.length > 0) {
592 this.processImportFile(files[0]);
593 }
594 },
595 handleFileSelect: function(e) {
596 var file = e.target.files[0];
597 if (file) {
598 this.processImportFile(file);
599 }
600 },
601 processImportFile: function(file) {
602 var self = this;
603 if (!file.name.endsWith(".json")) {
604 JLTMA_Toaster.error("Please select a valid JSON file.", 5e3);
605 return;
606 }
607 $(".jltma-dropzone-content").hide();
608 $(".jltma-importing").show();
609 var reader = new FileReader();
610 reader.onload = function(event) {
611 try {
612 var jsonData = JSON.parse(event.target.result);
613 var isValid = true;
614 if (window.jltmaWidgetBuilder && window.jltmaWidgetBuilder.hooks) {
615 isValid = window.jltmaWidgetBuilder.hooks.applyFilters(
616 "jltma_cwb_import_validate",
617 isValid,
618 jsonData
619 );
620 }
621 if (!jsonData.widget || !jsonData.version) {
622 throw new Error("Invalid widget file format");
623 }
624 if (!isValid) {
625 throw new Error("Import validation failed");
626 }
627 var importedWidget = jsonData.widget;
628 if (window.jltmaWidgetBuilder && window.jltmaWidgetBuilder.hooks) {
629 window.jltmaWidgetBuilder.hooks.doAction(
630 "jltma_cwb_before_import",
631 importedWidget
632 );
633 }
634 var processedWidget = importedWidget;
635 if (window.jltmaWidgetBuilder && window.jltmaWidgetBuilder.hooks) {
636 processedWidget = window.jltmaWidgetBuilder.hooks.applyFilters(
637 "jltma_cwb_import_data",
638 importedWidget,
639 jsonData
640 );
641 }
642 self.createWidgetFromImport(processedWidget, jsonData);
643 } catch (parseError) {
644 console.error("Failed to parse widget file:", parseError);
645 JLTMA_Toaster.error("Failed to import widget. Invalid JSON file format.", 5e3);
646 self.resetImportModal();
647 }
648 };
649 reader.onerror = function() {
650 console.error("Failed to read file");
651 JLTMA_Toaster.error("Failed to read file. Please try again.", 5e3);
652 self.resetImportModal();
653 };
654 reader.readAsText(file);
655 },
656 createWidgetFromImport: function(widgetData, originalJsonData) {
657 var self = this;
658 var CUSTOM_CATEGORY_PREFIX = "jltma_cwb_custom_";
659 var categorySlug = widgetData.category || "general";
660 var isCustomCategory = widgetData.isCustomCategory || categorySlug.startsWith(CUSTOM_CATEGORY_PREFIX);
661 var createWidget = function() {
662 console.log("Creating widget via REST API with data:", widgetData);
663 $.ajax({
664 url: jltmaWidgetAdmin.rest_url + "/widgets",
665 type: "POST",
666 headers: {
667 "X-WP-Nonce": jltmaWidgetAdmin.rest_nonce
668 },
669 contentType: "application/json",
670 data: JSON.stringify(widgetData),
671 success: function(response) {
672 console.log("Widget created successfully:", response);
673 if (window.jltmaWidgetBuilder && window.jltmaWidgetBuilder.hooks) {
674 window.jltmaWidgetBuilder.hooks.doAction(
675 "jltma_cwb_imported",
676 widgetData,
677 originalJsonData
678 );
679 }
680 JLTMA_Toaster.success("Widget imported successfully! Redirecting...", 3e3);
681 setTimeout(function() {
682 $("#jltma_import_widget_modal").fadeOut(300);
683 $("body").removeClass("jltma-modal-open");
684 setTimeout(function() {
685 var newId = response && response.data ? response.data.id : null;
686 var editUrl = response && response.data && response.data.edit_url ? response.data.edit_url : jltmaWidgetAdmin.admin_url + "admin.php?page=jltma-widget-editor&widget_id=" + newId;
687 window.location.href = editUrl;
688 }, 300);
689 }, 1500);
690 },
691 error: function(xhr, status, error) {
692 console.error("Failed to create widget:", error);
693 console.error("XHR Response:", xhr);
694 console.error("Status:", xhr.status);
695 console.error("Response Text:", xhr.responseText);
696 console.error("Request Data:", widgetData);
697 var errorMessage = "Failed to import widget. Please try again.";
698 try {
699 var errorData = JSON.parse(xhr.responseText);
700 if (errorData.message) {
701 errorMessage = errorData.message;
702 }
703 } catch (e) {
704 }
705 JLTMA_Toaster.error(errorMessage + " Check console for details.", 5e3);
706 self.resetImportModal();
707 }
708 });
709 };
710 if (isCustomCategory) {
711 $.ajax({
712 url: jltmaWidgetAdmin.rest_url + "/categories",
713 type: "GET",
714 headers: {
715 "X-WP-Nonce": jltmaWidgetAdmin.rest_nonce
716 },
717 success: function(categories) {
718 var categoryExists = categories.some(function(cat) {
719 return cat.slug === categorySlug;
720 });
721 if (!categoryExists) {
722 self.createCategoryIfNotExists(categorySlug, createWidget);
723 } else {
724 createWidget();
725 }
726 },
727 error: function(xhr, status, error) {
728 console.warn("Failed to check categories, proceeding with widget creation:", error);
729 createWidget();
730 }
731 });
732 } else {
733 createWidget();
734 }
735 },
736 createCategoryIfNotExists: function(categorySlug, callback) {
737 var CUSTOM_CATEGORY_PREFIX = "jltma_cwb_custom_";
738 var categoryName = categorySlug.replace(CUSTOM_CATEGORY_PREFIX, "").split("_").map(function(word) {
739 return word.charAt(0).toUpperCase() + word.slice(1);
740 }).join(" ");
741 var shouldCreate = true;
742 if (window.jltmaWidgetBuilder && window.jltmaWidgetBuilder.hooks) {
743 shouldCreate = window.jltmaWidgetBuilder.hooks.applyFilters(
744 "jltma_cwb_before_create_category",
745 shouldCreate,
746 categorySlug,
747 categoryName
748 );
749 }
750 if (!shouldCreate) {
751 if (callback) callback();
752 return;
753 }
754 $.ajax({
755 url: jltmaWidgetAdmin.rest_url + "/categories",
756 type: "POST",
757 headers: {
758 "X-WP-Nonce": jltmaWidgetAdmin.rest_nonce
759 },
760 contentType: "application/json",
761 data: JSON.stringify({
762 name: categoryName,
763 slug: categorySlug,
764 custom_prefix: CUSTOM_CATEGORY_PREFIX,
765 auto_created: true
766 }),
767 success: function(result) {
768 if (window.jltmaWidgetBuilder && window.jltmaWidgetBuilder.hooks) {
769 window.jltmaWidgetBuilder.hooks.doAction(
770 "jltma_cwb_category_created",
771 result.data,
772 categorySlug,
773 categoryName
774 );
775 }
776 if (callback) callback();
777 },
778 error: function(xhr, status, error) {
779 console.error("Failed to create category:", categorySlug, error);
780 JLTMA_Toaster.warning('Could not create category "' + categoryName + '". Widget will use "general" category.', 5e3);
781 if (callback) callback();
782 }
783 });
784 }
785 };
786 $(document).ready(function() {
787 WidgetAdmin.init();
788 });
789 })(jQuery);
790 })();
791