PluginProbe ʕ •ᴥ•ʔ
Download Manager / 3.3.63
Download Manager v3.3.63
3.3.64 3.3.63 3.3.62 3.3.61 3.3.60 3.3.59 3.3.58 3.3.57 3.3.56 trunk 2.1.3 2.3.0 2.5.96 2.5.97 2.6.2 2.6.96 2.8.3 2.9.99 3.0.4 3.1.05 3.1.07 3.1.08 3.1.11 3.1.12 3.1.14 3.1.17 3.1.18 3.1.22 3.1.23 3.1.24 3.1.25 3.1.26 3.1.27 3.1.28 3.2.04 3.2.13 3.2.14 3.2.16 3.2.18 3.2.19 3.2.21 3.2.22 3.2.23 3.2.24 3.2.25 3.2.27 3.2.28 3.2.29 3.2.30 3.2.31 3.2.32 3.2.33 3.2.34 3.2.35 3.2.37 3.2.38 3.2.39 3.2.40 3.2.41 3.2.42 3.2.43 3.2.44 3.2.45 3.2.46 3.2.47 3.2.48 3.2.49 3.2.50 3.2.51 3.2.52 3.2.53 3.2.54 3.2.55 3.2.56 3.2.57 3.2.58 3.2.59 3.2.60 3.2.61 3.2.63 3.2.64 3.2.65 3.2.66 3.2.67 3.2.68 3.2.69 3.2.70 3.2.71 3.2.72 3.2.73 3.2.74 3.2.75 3.2.76 3.2.77 3.2.78 3.2.79 3.2.80 3.2.81 3.2.82 3.2.83 3.2.84 3.2.85 3.2.86 3.2.87 3.2.88 3.2.89 3.2.90 3.2.91 3.2.92 3.2.93 3.2.94 3.2.95 3.2.96 3.2.97 3.2.98 3.2.99 3.3.00 3.3.01 3.3.02 3.3.03 3.3.04 3.3.05 3.3.06 3.3.07 3.3.08 3.3.09 3.3.10 3.3.11 3.3.12 3.3.13 3.3.14 3.3.15 3.3.16 3.3.17 3.3.18 3.3.19 3.3.20 3.3.21 3.3.22 3.3.23 3.3.24 3.3.25 3.3.26 3.3.27 3.3.28 3.3.29 3.3.30 3.3.31 3.3.32 3.3.33 3.3.34 3.3.35 3.3.36 3.3.37 3.3.38 3.3.39 3.3.40 3.3.41 3.3.42 3.3.43 3.3.44 3.3.45 3.3.46 3.3.47 3.3.48 3.3.49 3.3.50 3.3.51 3.3.52 3.3.53 3.3.54 3.3.55
download-manager / assets / modal / wpdm-modal.js
download-manager / assets / modal Last commit date
README.md 5 months ago wpdm-modal.css 3 months ago wpdm-modal.js 3 months ago wpdm-modal.min.css 3 months ago wpdm-modal.min.js 3 months ago
wpdm-modal.js
603 lines
1 /**
2 * WPDM Modal Dialog System
3 * Enterprise-Grade Modal Dialogs for WordPress Download Manager
4 * Version: 1.1.0
5 *
6 * Usage:
7 * WPDMDialog.alert('Title', 'Message');
8 * WPDMDialog.confirm('Title', 'Message').then(confirmed => { ... });
9 * WPDMDialog.prompt('Title', 'Message', { placeholder: 'Enter value' }).then(value => { ... });
10 * WPDMDialog.ajax('Title', '/api/endpoint').then(result => { ... });
11 * WPDMDialog.ajax('Title', { url: '/api', method: 'POST', data: {...} }, { size: 'lg' });
12 *
13 * Or via WPDM global (if available):
14 * WPDM.dialog.alert('Title', 'Message');
15 * WPDM.dialog.ajax('Title', '/api/endpoint');
16 */
17
18 var WPDMDialog = (function($) {
19 'use strict';
20
21 // SVG Icons
22 var icons = {
23 info: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg>',
24 success: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline></svg>',
25 warning: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path><line x1="12" y1="9" x2="12" y2="13"></line><line x1="12" y1="17" x2="12.01" y2="17"></line></svg>',
26 danger: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="15" y1="9" x2="9" y2="15"></line><line x1="9" y1="9" x2="15" y2="15"></line></svg>',
27 question: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path><line x1="12" y1="17" x2="12.01" y2="17"></line></svg>',
28 close: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>'
29 };
30
31 // Loading spinner HTML (uses CSS pseudo-elements + span for 3-dot bounce animation)
32 var loadingSpinner = '<div class="wpdm-dialog__loading"><div class="wpdm-dialog__spinner"><span></span></div><p class="wpdm-dialog__loading-text">Loading...</p></div>';
33
34 /**
35 * Detect dark mode from WPDM settings or page classes/attributes
36 * Priority: WPDM settings > page classes > system preference
37 * @returns {string} 'light-mode', 'dark-mode', or '' (system preference)
38 */
39 function detectDarkMode() {
40
41 if($('body').hasClass('wp-admin')) return 'light-mode';
42
43 // Check WPDM color scheme setting first (from wpdm_js localized script)
44 if (typeof wpdm_js !== 'undefined' && wpdm_js.color_scheme) {
45 if (wpdm_js.color_scheme === 'light') return 'light-mode';
46 if (wpdm_js.color_scheme === 'dark') return 'dark-mode';
47 // 'system' falls through to check page classes or return empty
48 }
49
50 // Check page classes and attributes
51 var isLightMode = $('body').hasClass('light-mode') ||
52 $('.w3eden').hasClass('light-mode') ||
53 $('html').attr('data-theme') === 'light' ||
54 $('body').attr('data-theme') === 'light';
55 var isDarkMode = $('body').hasClass('dark-mode') ||
56 $('.w3eden').hasClass('dark-mode') ||
57 $('html').hasClass('dark-mode') ||
58 $('body').hasClass('dark') ||
59 $('html').attr('data-theme') === 'dark' ||
60 $('body').attr('data-theme') === 'dark';
61
62 if (isLightMode) return 'light-mode';
63 if (isDarkMode) return 'dark-mode';
64 return ''; // System preference (CSS media query handles this)
65 }
66
67 /**
68 * Escape HTML to prevent XSS
69 * @param {string} text Text to escape
70 * @returns {string} Escaped text
71 */
72 function escapeHtml(text) {
73 if (typeof text !== 'string') return text;
74 var map = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#039;' };
75 return text.replace(/[&<>"']/g, function(m) { return map[m]; });
76 }
77
78 /**
79 * Generate unique ID for dialog
80 * @returns {string} Unique ID
81 */
82 function uniqueId() {
83 return 'wpdm-dialog-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);
84 }
85
86 /**
87 * Create dialog HTML
88 * @param {Object} options Dialog options
89 * @returns {string} HTML string
90 */
91 function createDialogHtml(options) {
92
93 var id = options.id || uniqueId();
94 var darkModeClass = detectDarkMode();
95 var sizeClass = options.size ? 'wpdm-dialog--' + options.size : '';
96 var showIcon = options.icon !== false;
97 var iconType = options.type || 'info';
98
99 var html = '<div class="wpdm-dialog-wrapper w3eden ' + darkModeClass + '" id="' + id + '">';
100 html += '<div class="wpdm-dialog-backdrop"></div>';
101 html += '<div class="wpdm-dialog ' + sizeClass + '" role="dialog" aria-modal="true" aria-labelledby="' + id + '-title">';
102
103 // Close button (if closable)
104 if (options.closable !== false) {
105 html += '<button type="button" class="wpdm-dialog__close" aria-label="Close">' + icons.close + '</button>';
106 }
107
108 // Header
109 html += '<div class="wpdm-dialog__header">';
110 if (showIcon) {
111 html += '<div class="wpdm-dialog__icon wpdm-dialog__icon--' + iconType + '">' + icons[iconType] + '</div>';
112 }
113 html += '<div class="wpdm-dialog__header-content">';
114 html += '<h3 class="wpdm-dialog__title" id="' + id + '-title">' + escapeHtml(options.title) + '</h3>';
115 if (options.subtitle) {
116 html += '<p class="wpdm-dialog__subtitle">' + escapeHtml(options.subtitle) + '</p>';
117 }
118 html += '</div>';
119 html += '</div>';
120
121 // Body
122 html += '<div class="wpdm-dialog__body">';
123 if (options.message) {
124 html += '<p class="wpdm-dialog__message">' + (options.html ? options.message : escapeHtml(options.message)) + '</p>';
125 }
126 if (options.input) {
127 html += '<div class="wpdm-dialog__input-wrapper">';
128 html += '<input type="' + (options.inputType || 'text') + '" class="wpdm-dialog__input" placeholder="' + escapeHtml(options.placeholder || '') + '" value="' + escapeHtml(options.inputValue || '') + '">';
129 html += '</div>';
130 }
131 if (options.content) {
132 html += options.content;
133 }
134 html += '</div>';
135
136 // Footer
137 if (options.buttons && options.buttons.length > 0) {
138 var footerClass = options.compactFooter ? 'wpdm-dialog__footer wpdm-dialog__footer--compact' : 'wpdm-dialog__footer';
139 html += '<div class="' + footerClass + '">';
140 options.buttons.forEach(function(btn, index) {
141 var btnClass = 'wpdm-dialog__btn wpdm-dialog__btn--' + (btn.type || 'secondary');
142 html += '<button type="button" class="' + btnClass + '" data-action="' + (btn.action || index) + '">' + escapeHtml(btn.text) + '</button>';
143 });
144 html += '</div>';
145 }
146
147 html += '</div>';
148 html += '</div>';
149
150 return html;
151 }
152
153 /**
154 * Show dialog
155 * @param {Object} options Dialog options
156 * @returns {Promise} Resolves with { action: string, value: string|null }
157 */
158 function show(options) {
159 return new Promise(function(resolve) {
160 var html = createDialogHtml(options);
161 var $dialog = $(html);
162 $('body').append($dialog);
163
164 // Focus trap elements
165 var $wrapper = $dialog;
166 var $input = $wrapper.find('.wpdm-dialog__input');
167 var $buttons = $wrapper.find('.wpdm-dialog__btn');
168 var $closeBtn = $wrapper.find('.wpdm-dialog__close');
169
170 // Show dialog with animation
171 requestAnimationFrame(function() {
172 $wrapper.addClass('wpdm-dialog-visible');
173 if ($input.length) {
174 $input.focus().select();
175 } else if ($buttons.length) {
176 $buttons.last().focus();
177 }
178 });
179
180 // Close function
181 function close(result) {
182 $wrapper.removeClass('wpdm-dialog-visible');
183 $(document).off('keydown.wpdmDialog');
184 setTimeout(function() {
185 $wrapper.remove();
186 resolve(result);
187 }, 250);
188 }
189
190 // Button clicks
191 $buttons.on('click', function() {
192 var action = $(this).data('action');
193 var inputValue = $input.length ? $input.val() : null;
194 close({ action: action, value: inputValue });
195 });
196
197 // Close button click
198 $closeBtn.on('click', function() {
199 close({ action: 'close', value: null });
200 });
201
202 // Backdrop click (if not static)
203 if (options.backdrop !== 'static') {
204 $wrapper.find('.wpdm-dialog-backdrop').on('click', function() {
205 close({ action: 'backdrop', value: null });
206 });
207 }
208
209 // Escape key
210 if (options.keyboard !== false) {
211 $(document).on('keydown.wpdmDialog', function(e) {
212 if (e.key === 'Escape') {
213 close({ action: 'escape', value: null });
214 }
215 });
216 }
217
218 // Enter key for prompt
219 if (options.input) {
220 $input.on('keydown', function(e) {
221 if (e.key === 'Enter') {
222 e.preventDefault();
223 close({ action: 'confirm', value: $input.val() });
224 }
225 });
226 }
227 });
228 }
229
230 // Public API
231 return {
232 /**
233 * Show a custom dialog
234 * @param {Object} options Dialog options
235 * @returns {Promise}
236 */
237 show: show,
238
239 /**
240 * Show an alert dialog
241 * @param {string} title Dialog title
242 * @param {string} message Dialog message
243 * @param {Object} options Additional options
244 * @returns {Promise<string>}
245 */
246 alert: function(title, message, options) {
247 options = options || {};
248 options.buttons = options.buttons || [
249 { text: options.buttonText || 'OK', type: 'primary', action: 'ok' }
250 ];
251 return show({
252 title: title,
253 message: message,
254 type: options.type || 'info',
255 icon: options.icon,
256 size: options.size || 'sm',
257 html: options.html,
258 compactFooter: true,
259 buttons: options.buttons,
260 backdrop: 'static',
261 keyboard: true
262 }).then(function(result) {
263 return result.action;
264 });
265 },
266
267 /**
268 * Show a success alert
269 * @param {string} title Dialog title
270 * @param {string} message Dialog message
271 * @param {Object} options Additional options
272 * @returns {Promise<string>}
273 */
274 success: function(title, message, options) {
275 options = options || {};
276 options.type = 'success';
277 return this.alert(title, message, options);
278 },
279
280 /**
281 * Show a warning alert
282 * @param {string} title Dialog title
283 * @param {string} message Dialog message
284 * @param {Object} options Additional options
285 * @returns {Promise<boolean>}
286 */
287 warning: function(title, message, options) {
288 options = options || {};
289 options.type = 'warning';
290 return this.alert(title, message, options);
291 },
292
293 /**
294 * Show an error alert
295 * @param {string} title Dialog title
296 * @param {string} message Dialog message
297 * @param {Object} options Additional options
298 * @returns {Promise<boolean>}
299 */
300 error: function(title, message, options) {
301 options = options || {};
302 options.type = 'danger';
303 return this.alert(title, message, options);
304 },
305
306 /**
307 * Show a confirm dialog
308 * @param {string} title Dialog title
309 * @param {string} message Dialog message
310 * @param {Object} options Additional options
311 * @returns {Promise<boolean>}
312 */
313 confirm: function(title, message, options) {
314 options = options || {};
315 options.buttons = options.buttons || [
316 { text: options.cancelText || 'Cancel', type: 'secondary', action: 'cancel' },
317 { text: options.confirmText || 'Confirm', type: options.confirmType || 'primary', action: 'confirm' }
318 ];
319 return show({
320 title: title,
321 message: message,
322 type: options.type || 'question',
323 icon: options.icon,
324 size: options.size || 'sm',
325 html: options.html,
326 buttons: options.buttons,
327 backdrop: options.backdrop || 'static',
328 keyboard: options.keyboard !== false
329 }).then(function(result) {
330 return result.action === 'confirm';
331 });
332 },
333
334 /**
335 * Show a delete confirm dialog
336 * @param {string} title Dialog title
337 * @param {string} message Dialog message
338 * @param {Object} options Additional options
339 * @returns {Promise<boolean>}
340 */
341 confirmDelete: function(title, message, options) {
342 options = options || {};
343 options.type = 'danger';
344 options.confirmText = options.confirmText || 'Delete';
345 options.confirmType = 'danger';
346 return this.confirm(title, message, options);
347 },
348
349 /**
350 * Show a prompt dialog
351 * @param {string} title Dialog title
352 * @param {string} message Dialog message (optional)
353 * @param {Object} options Additional options
354 * @returns {Promise<string|null>}
355 */
356 prompt: function(title, message, options) {
357 options = options || {};
358 return show({
359 title: title,
360 message: message,
361 type: options.type || 'question',
362 icon: options.icon,
363 size: options.size || 'md',
364 input: true,
365 inputType: options.inputType || 'text',
366 inputValue: options.inputValue || '',
367 placeholder: options.placeholder || '',
368 html: options.html,
369 buttons: [
370 { text: options.cancelText || 'Cancel', type: 'secondary', action: 'cancel' },
371 { text: options.confirmText || 'Submit', type: 'primary', action: 'confirm' }
372 ],
373 backdrop: options.backdrop || 'static',
374 keyboard: options.keyboard !== false
375 }).then(function(result) {
376 return result.action === 'confirm' ? result.value : null;
377 });
378 },
379
380 /**
381 * Show a dialog with async content loaded via AJAX
382 * @param {string} title Dialog title
383 * @param {string|Object} urlOrOptions URL string or AJAX options object
384 * @param {Object} options Additional dialog options
385 * @returns {Promise} Resolves with { action: string, data: any }
386 *
387 * Usage:
388 * WPDMDialog.ajax('Title', '/api/endpoint');
389 * WPDMDialog.ajax('Title', '/api/endpoint', { size: 'lg' });
390 * WPDMDialog.ajax('Title', { url: '/api/endpoint', method: 'POST', data: { id: 123 } });
391 */
392 ajax: function(title, urlOrOptions, options) {
393 options = options || {};
394 var ajaxOptions = typeof urlOrOptions === 'string' ? { url: urlOrOptions } : urlOrOptions;
395
396 return new Promise(function(resolve, reject) {
397 var dialogId = uniqueId();
398 var darkModeClass = detectDarkMode();
399 var sizeClass = options.size ? 'wpdm-dialog--' + options.size : 'wpdm-dialog--md';
400
401 // Build dialog HTML with loading state
402 var html = '<div class="wpdm-dialog-wrapper w3eden ' + darkModeClass + '" id="' + dialogId + '">';
403 html += '<div class="wpdm-dialog-backdrop"></div>';
404 html += '<div class="wpdm-dialog ' + sizeClass + '" role="dialog" aria-modal="true" aria-labelledby="' + dialogId + '-title">';
405
406 // Close button
407 if (options.closable !== false) {
408 html += '<button type="button" class="wpdm-dialog__close" aria-label="Close">' + icons.close + '</button>';
409 }
410
411 // Header
412 html += '<div class="wpdm-dialog__header">';
413 if (options.icon !== false) {
414 var iconType = options.type || 'info';
415 html += '<div class="wpdm-dialog__icon wpdm-dialog__icon--' + iconType + '">' + icons[iconType] + '</div>';
416 }
417 html += '<div class="wpdm-dialog__header-content">';
418 html += '<h3 class="wpdm-dialog__title" id="' + dialogId + '-title">' + escapeHtml(title) + '</h3>';
419 if (options.subtitle) {
420 html += '<p class="wpdm-dialog__subtitle">' + escapeHtml(options.subtitle) + '</p>';
421 }
422 html += '</div></div>';
423
424 // Body with loading spinner
425 html += '<div class="wpdm-dialog__body wpdm-dialog__body--ajax">' + loadingSpinner + '</div>';
426
427 // Footer placeholder (will be updated after AJAX)
428 html += '<div class="wpdm-dialog__footer wpdm-dialog__footer--hidden"></div>';
429
430 html += '</div></div>';
431
432 var $dialog = $(html);
433 $('body').append($dialog);
434
435 var $wrapper = $dialog;
436 var $body = $wrapper.find('.wpdm-dialog__body');
437 var $footer = $wrapper.find('.wpdm-dialog__footer');
438 var $closeBtn = $wrapper.find('.wpdm-dialog__close');
439
440 // Show dialog
441 requestAnimationFrame(function() {
442 $wrapper.addClass('wpdm-dialog-visible');
443 });
444
445 // Close function
446 function close(result) {
447 $wrapper.removeClass('wpdm-dialog-visible');
448 $(document).off('keydown.wpdmDialog');
449 setTimeout(function() {
450 $wrapper.remove();
451 resolve(result);
452 }, 250);
453 }
454
455 // Close button click
456 $closeBtn.on('click', function() {
457 close({ action: 'close', data: null });
458 });
459
460 // Backdrop click
461 if (options.backdrop !== 'static') {
462 $wrapper.find('.wpdm-dialog-backdrop').on('click', function() {
463 close({ action: 'backdrop', data: null });
464 });
465 }
466
467 // Escape key
468 if (options.keyboard !== false) {
469 $(document).on('keydown.wpdmDialog', function(e) {
470 if (e.key === 'Escape') {
471 close({ action: 'escape', data: null });
472 }
473 });
474 }
475
476 // Make AJAX request
477 $.ajax({
478 url: ajaxOptions.url,
479 method: ajaxOptions.method || 'GET',
480 data: ajaxOptions.data || {},
481 dataType: ajaxOptions.dataType || 'html',
482 headers: ajaxOptions.headers || {},
483 timeout: ajaxOptions.timeout || 30000
484 }).done(function(response) {
485 // Handle JSON response with content field
486 var content = response;
487 var buttons = options.buttons;
488 var responseData = null;
489
490 if (typeof response === 'object') {
491 responseData = response;
492 content = response.content || response.html || response.body || '';
493 // Allow response to override buttons
494 if (response.buttons) {
495 buttons = response.buttons;
496 }
497 }
498
499 // Update body content with animation
500 $body.removeClass('wpdm-dialog__body--ajax wpdm-dialog__body--loaded').html(content);
501
502 // Trigger reflow and add loaded class for animation
503 requestAnimationFrame(function() {
504 $body.addClass('wpdm-dialog__body--loaded');
505 });
506
507 // Update footer with buttons if provided
508 if (buttons && buttons.length > 0) {
509 var footerHtml = '';
510 buttons.forEach(function(btn, index) {
511 var btnClass = 'wpdm-dialog__btn wpdm-dialog__btn--' + (btn.type || 'secondary');
512 footerHtml += '<button type="button" class="' + btnClass + '" data-action="' + (btn.action || index) + '">' + escapeHtml(btn.text) + '</button>';
513 });
514 $footer.html(footerHtml).removeClass('wpdm-dialog__footer--hidden');
515
516 // Bind button clicks
517 $footer.find('.wpdm-dialog__btn').on('click', function() {
518 var action = $(this).data('action');
519 close({ action: action, data: responseData });
520 });
521 }
522
523 // Run callback if provided
524 if (typeof options.onLoad === 'function') {
525 options.onLoad($body, responseData);
526 }
527
528 }).fail(function(xhr, status, error) {
529 // Show error state
530 var errorHtml = '<div class="wpdm-dialog__error">';
531 errorHtml += '<div class="wpdm-dialog__error-icon">' + icons.danger + '</div>';
532 errorHtml += '<p class="wpdm-dialog__error-message">' + escapeHtml(options.errorMessage || 'Failed to load content. Please try again.') + '</p>';
533 if (options.showRetry !== false) {
534 errorHtml += '<button type="button" class="wpdm-dialog__btn wpdm-dialog__btn--secondary wpdm-dialog__retry">Retry</button>';
535 }
536 errorHtml += '</div>';
537
538 // Update body with error and animate
539 $body.removeClass('wpdm-dialog__body--ajax wpdm-dialog__body--loaded').html(errorHtml);
540 requestAnimationFrame(function() {
541 $body.addClass('wpdm-dialog__body--loaded');
542 });
543
544 // Retry button
545 $body.find('.wpdm-dialog__retry').on('click', function() {
546 $body.addClass('wpdm-dialog__body--ajax').html(loadingSpinner);
547 // Re-trigger AJAX
548 $.ajax({
549 url: ajaxOptions.url,
550 method: ajaxOptions.method || 'GET',
551 data: ajaxOptions.data || {},
552 dataType: ajaxOptions.dataType || 'html',
553 headers: ajaxOptions.headers || {},
554 timeout: ajaxOptions.timeout || 30000
555 }).done(function(response) {
556 var content = response;
557 if (typeof response === 'object') {
558 content = response.content || response.html || response.body || '';
559 }
560 $body.removeClass('wpdm-dialog__body--ajax wpdm-dialog__body--loaded').html(content);
561 requestAnimationFrame(function() {
562 $body.addClass('wpdm-dialog__body--loaded');
563 });
564 if (typeof options.onLoad === 'function') {
565 options.onLoad($body, response);
566 }
567 }).fail(function() {
568 $body.removeClass('wpdm-dialog__body--ajax wpdm-dialog__body--loaded').html(errorHtml);
569 requestAnimationFrame(function() {
570 $body.addClass('wpdm-dialog__body--loaded');
571 });
572 });
573 });
574
575 // Call error callback if provided
576 if (typeof options.onError === 'function') {
577 options.onError(xhr, status, error);
578 }
579 });
580 });
581 },
582
583 /**
584 * Show a dialog and load content into body from URL
585 * Alias for ajax() with simplified options
586 * @param {string} title Dialog title
587 * @param {string} url URL to load
588 * @param {Object} options Additional options
589 * @returns {Promise}
590 */
591 load: function(title, url, options) {
592 return this.ajax(title, url, options);
593 }
594 };
595 })(jQuery);
596
597 // Attach to WPDM global object after all JS is fully loaded
598 jQuery(function($) {
599 if (typeof WPDM !== 'undefined') {
600 WPDM.dialog = WPDMDialog;
601 }
602 });
603