PluginProbe
Contact Forms by Cimatti / 2.2.0
Contact Forms by Cimatti v2.2.0
2.3.6 2.3.5 2.3.0 2.2.32 2.2.4 2.2.0 2.1.2 2.1.1 trunk 1.0 1.1 1.2 1.2.1 1.3 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 All 62 releases
contact-forms / assets / js / admin / form-fields.js

form-fields.js in Contact Forms by Cimatti 2.2.0, at assets/js/admin/form-fields.js

470 lines 18.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 var accuaWidgets = {};
2 (function($) {
3
4 accuaWidgets = {
5
6 init : function() {
7 var rem, sidebars = $('div.widgets-sortables'), isRTL = !! ( 'undefined' != typeof isRtl && isRtl ),
8 margin = ( isRtl ? 'marginRight' : 'marginLeft' ), the_id;
9
10 //Evento per widget-action (aggiunto in modalità "live")
11 // Uses CSS class toggle instead of jQuery slideDown/slideUp
12 $(document).on('click', 'a.widget-action', function(){
13 var $action = $(this),
14 widget = $action.closest('div.widget'),
15 $inside = widget.find('.widget-inside'),
16 isOpen = widget.hasClass('open');
17
18 if ( !isOpen ) {
19 // Opening: add .open class, fix labels, update ARIA
20 accuaWidgets.fixLabels(widget);
21 widget.addClass('open');
22 // Remove any inline display style (from jQuery .hide() during drag)
23 $inside.css('display', '');
24 $action.attr('aria-expanded', 'true');
25 } else {
26 // Closing: remove .open class, update ARIA
27 widget.removeClass('open');
28 $action.attr('aria-expanded', 'false');
29 }
30 return false;
31 });
32
33 //Click sul bottone di salvataggio
34 // $('input.widget-control-save').live('click', function(){
35 $(document).on('click', 'input.widget-control-save', function(){
36 var $button = $(this);
37 var originalText = $button.val();
38
39 // Add saving state with "Saving..." text
40 $button.addClass('accua-saving-active').val(accua_forms_i18n.saving || 'Saving...');
41
42 accuaWidgets.save( $button.closest('div.widget'), 0, 1, 0, function(success) {
43 // Restore button text immediately
44 $button.val(originalText);
45
46 if (success) {
47 // Show success state
48 $button.removeClass('accua-saving-active').addClass('accua-saved-active');
49
50 // Remove success state after 1.5 seconds
51 setTimeout(function() {
52 $button.removeClass('accua-saved-active');
53 }, 1500);
54 } else {
55 // Show error state
56 $button.removeClass('accua-saving-active').addClass('accua-error');
57
58 // Remove error state after 2 seconds
59 setTimeout(function() {
60 $button.removeClass('accua-error');
61 }, 2000);
62 }
63 });
64 return false;
65 });
66
67 //Click sul bottone di rimozione
68 //$('a.widget-control-remove').live('click', function(){
69 $(document).on('click', 'a.widget-control-remove', function(){
70 accuaWidgets.save( $(this).closest('div.widget'), 1, 1, 0 );
71 return false;
72 });
73
74 //Click sul bottone di chiusura
75 //$('a.widget-control-close').live('click', function(){
76 $(document).on('click', 'a.widget-control-close', function(){
77 accuaWidgets.close( $(this).closest('div.widget') );
78 return false;
79 });
80
81 // Refresh Preview link for Custom HTML fields
82 $(document).on('click', 'a.accua-refresh-preview', function(e){
83 e.preventDefault();
84 var widget = $(this).closest('div.widget');
85 accuaWidgets.save( widget, 0, 0, 0, function(success) {
86 if (success) {
87 accuaWidgets.refreshPreviewWithCurrentOrder();
88 }
89 });
90 });
91
92 // Auto-save + preview refresh when field options change
93 // Only for widgets inside the form area (not the available-widgets sidebar)
94 var previewDebounceTimers = {};
95
96 function saveAndRefreshPreview(widget) {
97 accuaWidgets.saveSilent(widget, function(success) {
98 if (success) {
99 accuaWidgets.refreshPreviewWithCurrentOrder();
100 }
101 });
102 }
103
104 function debouncedSaveAndRefresh(widget, delay) {
105 var widgetId = widget.attr('id');
106 if (previewDebounceTimers[widgetId]) {
107 clearTimeout(previewDebounceTimers[widgetId]);
108 }
109 previewDebounceTimers[widgetId] = setTimeout(function() {
110 delete previewDebounceTimers[widgetId];
111 saveAndRefreshPreview(widget);
112 }, delay);
113 }
114
115 // Immediate change: checkboxes, selects
116 $(document).on('change', 'div.widgets-sortables .widget-content select, div.widgets-sortables .widget-content input[type="checkbox"]', function() {
117 var widget = $(this).closest('div.widget');
118 saveAndRefreshPreview(widget);
119 });
120
121 // Debounced change: text inputs and textareas (800ms delay)
122 $(document).on('input', 'div.widgets-sortables .widget-content input[type="text"], div.widgets-sortables .widget-content textarea', function() {
123 var widget = $(this).closest('div.widget');
124 debouncedSaveAndRefresh(widget, 800);
125 });
126
127 //Impostazione titolo e apertura widget se c'è un errore
128 sidebars.children('.widget').each(function() {
129 accuaWidgets.appendTitle(this);
130 if ( $('p.widget-error', this).length )
131 $('a.widget-action', this).click();
132 });
133
134 //Trascinabilità dei widget nella lista
135 $('#widget-list').children('.widget').draggable({
136 connectToSortable: 'div.widgets-sortables',
137 handle: '> .widget-top > .widget-title',
138 distance: 2,
139 helper: 'clone',
140 zIndex: 5,
141 containment: 'document',
142 start: function(e,ui) {
143 accuaWidgets.fixWebkit(1);
144 ui.helper.find('div.widget-description').hide();
145 the_id = this.id;
146 },
147 stop: function(e,ui) {
148 if ( rem )
149 $(rem).hide();
150 rem = '';
151 accuaWidgets.fixWebkit();
152 }
153 });
154
155 //Ordinabilità dei widget
156 sidebars.sortable({
157 placeholder: 'widget-placeholder',
158 items: '> .widget',
159 handle: '> .widget-top > .widget-title',
160 cursor: 'move',
161 distance: 2,
162 containment: 'document',
163 start: function(e,ui) {
164 accuaWidgets.fixWebkit(1);
165 ui.item.children('.widget-inside').hide();
166 ui.item.css({margin:'', 'width':''});
167 },
168 stop: function(e,ui) {
169 // Mark form as having unsaved changes
170 if (window.accuaFormsEditorDirty) { window.accuaFormsEditorDirty.mark(); }
171
172 if ( ui.item.hasClass('ui-draggable') && ui.item.data('draggable') )
173 ui.item.draggable('destroy');
174
175 if ( ui.item.hasClass('deleting') ) {
176 accuaWidgets.save( ui.item, 1, 0, 1 ); // delete widget
177 ui.item.remove();
178 return;
179 }
180
181 var add = ui.item.find('input.add_new').val(),
182 n = ui.item.find('input.multi_number').val(),
183 id = the_id,
184 sb = $(this).attr('id');
185
186 ui.item.css({margin:'', 'width':''});
187 the_id = '';
188
189 accuaWidgets.fixWebkit();
190 if ( add ) {
191 if ( 'multi' == add ) {
192 ui.item.html( ui.item.html().replace(/<[^<>]+>/g, function(m){ return m.replace(/__i__|%i%/g, n); }) );
193 ui.item.attr( 'id', id.replace(/__i__|%i%/g, n) );
194 n++;
195 $('div#' + id).find('input.multi_number').val(n);
196 } else if ( 'single' == add ) {
197 ui.item.attr( 'id', 'new-' + id );
198 rem = 'div#' + id;
199 }
200 // Save the new widget to DB, but DON'T save order yet
201 accuaWidgets.save( ui.item, 0, 0, 0, function(success) {
202 if (success) {
203 // Refresh preview with current order
204 accuaWidgets.refreshPreviewWithCurrentOrder();
205 }
206 });
207 ui.item.find('input.add_new').val('');
208 ui.item.find('a.widget-action').click();
209 return;
210 }
211 // Refresh preview (without saving to database)
212 accuaWidgets.refreshPreviewWithCurrentOrder();
213 },
214 receive: function(e,ui) {
215 var t = $(this);
216 if ( !t.is(':visible') ) {
217 t.sortable('cancel');
218 }
219 }
220 }).sortable('option', 'connectWith', 'div.widgets-sortables').parent().filter('.closed').children('.widgets-sortables').sortable('disable');
221
222 //Droppabilità dei widget disponibili
223 $('#available-widgets').droppable({
224 tolerance: 'pointer',
225 accept: function(o){
226 return $(o).parent().attr('id') != 'widget-list';
227 },
228 drop: function(e,ui) {
229 // Mark form as having unsaved changes
230 if (window.accuaFormsEditorDirty) { window.accuaFormsEditorDirty.mark(); }
231 ui.draggable.addClass('deleting');
232 $('#removing-widget').hide().children('span').html('');
233 },
234 over: function(e,ui) {
235 ui.draggable.addClass('deleting');
236 $('div.widget-placeholder').hide();
237
238 if ( ui.draggable.hasClass('ui-sortable-helper') )
239 $('#removing-widget').show().children('span')
240 .html( ui.draggable.find('div.widget-title').children('h4').html() );
241 },
242 out: function(e,ui) {
243 ui.draggable.removeClass('deleting');
244 $('div.widget-placeholder').show();
245 $('#removing-widget').hide().children('span').html('');
246 }
247 });
248
249 // Wrapper divs are now in PHP to prevent layout shift on load
250 // var holders = $('#widgets-left .widget-holder, #widgets-right .widgets-sortables');
251 // holders.wrap('<div class="accua-form-widget-scroll-wrapper"></div>');
252 },
253
254 // Get current field order from sortable areas (without saving)
255 getCurrentOrder: function() {
256 var order = {};
257 $('div.widgets-sortables').each(function() {
258 var $sortable = $(this);
259 if ($sortable.sortable) {
260 order[$sortable.attr('id')] = $sortable.sortable('toArray').join(',');
261 }
262 });
263 return order;
264 },
265
266 // Refresh preview with current (unsaved) order via POST
267 refreshPreviewWithCurrentOrder: function() {
268 var self = this;
269 var $iframe = $('#accua_form_preview_area');
270 var $wrapper = $('#accua_form_preview_area_wrapper');
271
272 if (!$iframe.length || typeof accua_forms_nonces === 'undefined') {
273 return;
274 }
275
276 var formId = $('#accua_form_save_settings_id').val();
277 if (!formId) {
278 return;
279 }
280
281 // Show loading state
282 $wrapper.addClass('accua-form-preview-loading');
283
284 // Get current unsaved order
285 var orderData = self.getCurrentOrder();
286
287 // Create a hidden form to POST the order to a new iframe
288 // This allows preview to render with unsaved order
289 var previewUrl = 'admin-ajax.php?action=accua_forms_preview&fid=' + formId + '&_wpnonce=' + accua_forms_nonces.preview_nonce;
290
291 // Add order as URL parameter (encoded JSON)
292 previewUrl += '&preview_order=' + encodeURIComponent(JSON.stringify(orderData));
293
294 $iframe[0].src = previewUrl;
295
296 // Remove loading state when iframe loads
297 $iframe.off('load.previewRefresh').on('load.previewRefresh', function() {
298 $wrapper.removeClass('accua-form-preview-loading');
299 });
300 },
301
302 // Refresh preview from database (after save)
303 refreshPreview : function() {
304 var $iframe = $('#accua_form_preview_area');
305 var $wrapper = $('#accua_form_preview_area_wrapper');
306 if ($iframe.length && typeof accua_forms_nonces !== 'undefined') {
307 var formId = $('#accua_form_save_settings_id').val();
308 if (formId) {
309 // Show loading state
310 $wrapper.addClass('accua-form-preview-loading');
311 // Refresh from database
312 $iframe[0].src = 'admin-ajax.php?action=accua_forms_preview&fid=' + formId + '&_wpnonce=' + accua_forms_nonces.preview_nonce;
313 // Remove loading state when iframe loads
314 $iframe.off('load.previewRefresh').on('load.previewRefresh', function() {
315 $wrapper.removeClass('accua-form-preview-loading');
316 });
317 }
318 }
319 },
320
321 // Save field order to database via AJAX
322 saveOrder : function(sb, callback) {
323 var self = this;
324
325 // Collect field order from all sortable areas
326 var orderData = {
327 action: 'accua-form-fields-order',
328 _nonce_edit_form: $('#_nonce_edit_form').val(),
329 sidebars: self.getCurrentOrder()
330 };
331
332 // Save field order via AJAX
333 $.post(ajaxurl, orderData, function(response) {
334 if (typeof callback === 'function') {
335 callback(true);
336 }
337 }).fail(function() {
338 console.error('Failed to save field order');
339 if (typeof callback === 'function') {
340 callback(false);
341 }
342 });
343
344 self.resize();
345 },
346
347 //Salvataggio stato widget
348 save : function(widget, del, animate, order, callback) {
349 var sb = widget.closest('div.widgets-sortables').attr('id'), data = widget.find('form').serialize(), a;
350 widget = $(widget);
351
352 a = {
353 action: 'accua-save-form-field',
354 _nonce_edit_form: $('#_nonce_edit_form').val(),
355 sidebar: sb
356 };
357
358 if ( del )
359 a['delete_widget'] = 1;
360
361 data += '&' + $.param(a);
362
363 $.post( ajaxurl, data, function(r){
364 var id;
365
366 if ( del ) {
367 if ( !$('input.widget_number', widget).val() ) {
368 id = $('input.widget-id', widget).val();
369 $('#available-widgets').find('input.widget-id').each(function(){
370 if ( $(this).val() == id )
371 $(this).closest('div.widget').show();
372 });
373 }
374
375 if ( animate ) {
376 order = 0;
377 widget.slideUp('fast', function(){
378 $(this).remove();
379 // Refresh preview
380 accuaWidgets.refreshPreviewWithCurrentOrder();
381 });
382 } else {
383 widget.remove();
384 accuaWidgets.resize();
385 }
386 if (callback) callback(true);
387 } else {
388 if ( r && r.length > 2 ) {
389 $('div.widget-content', widget).html(r);
390 accuaWidgets.appendTitle(widget);
391 accuaWidgets.fixLabels(widget);
392 }
393 if (callback) callback(true);
394 }
395 // Don't save order here - order is saved when user clicks global Save button
396 }).fail(function() {
397 if (callback) callback(false);
398 });
399 },
400
401 // Save field to draft without replacing widget content (for auto-preview)
402 saveSilent : function(widget, callback) {
403 var sb = widget.closest('div.widgets-sortables').attr('id'),
404 data = widget.find('form').serialize(),
405 a = {
406 action: 'accua-save-form-field',
407 _nonce_edit_form: $('#_nonce_edit_form').val(),
408 sidebar: sb
409 };
410
411 data += '&' + $.param(a);
412
413 $.post(ajaxurl, data, function() {
414 if (callback) callback(true);
415 }).fail(function() {
416 if (callback) callback(false);
417 });
418 },
419
420 //Aggiunta titolo
421 appendTitle : function(widget) {
422 var title = $('input[id*="-title"]', widget);
423 if ( title = title.val() ) {
424 title = title.replace(/<[^<>]+>/g, '').replace(/</g, '&lt;').replace(/>/g, '&gt;');
425 $(widget).children('.widget-top').children('.widget-title').children()
426 .children('.in-widget-title').html(': ' + title);
427 }
428 },
429
430 resize : function() {
431 /*
432 $('div.widgets-sortables').not('#wp_inactive_widgets').each(function(){
433 var t = $(this);
434 var h = 50, H = t.children('.widget').length;
435 h = h + parseInt(H * 48, 10);
436 t.css( 'minHeight', h + 'px' );
437 });
438 */
439 },
440
441 fixWebkit : function(n) {
442 n = n ? 'none' : '';
443 $('body').css({
444 WebkitUserSelect: n,
445 KhtmlUserSelect: n
446 });
447 },
448
449 fixLabels : function(widget) {
450 widget.children('.widget-inside').find('label').each(function(){
451 var t = $(this);
452 var f = t.attr('for');
453 if ( f && f == $('input', this).attr('id') ) {
454 t.removeAttr('for');
455 }
456 });
457 },
458
459 //Chiusura widget
460 close : function(widget) {
461 // Use CSS transition instead of jQuery slideUp
462 widget.removeClass('open');
463 widget.find('a.widget-action').attr('aria-expanded', 'false');
464 }
465 };
466
467 $(document).ready(function($){ accuaWidgets.init(); });
468
469 })(jQuery);
470