Installation NG continued (still not fully working)
[mailer.git] / js / ajax-common.js
1 /**
2  * Common JavaScript functions for AJAX requests (they are general purpose).
3  * --------------------------------------------------------------------
4  * $Revision::                                                        $
5  * $Date::                                                            $
6  * $Tag:: 0.2.1-FINAL                                                 $
7  * $Author::                                                          $
8  * --------------------------------------------------------------------
9  * Copyright (c) 2003 - 2009 by Roland Haeder
10  * Copyright (c) 2009 - 2012 by Mailer Developer Team
11  * For more information visit: http://mxchange.org
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
26  * MA  02110-1301  USA
27  */
28
29 // Init variables
30 var currentTabId       = null;
31 var processDisplayed   = false;
32 var errorDisplayed     = false;
33 var warningDisplayed   = false;
34 var defaultTabId       = null;
35 var footerElements     = new Array();
36 var changedElements    = new Array();
37 var formChanged        = false;
38 var saveChangesId      = null;
39 var lastErrorMessage   = null;
40 var saveChangesPending = false;
41
42 // Add all footer navigation elements
43 footerElements[0] = 'next';
44 footerElements[1] = 'previous';
45
46 // Setter for current tab id
47 function setCurrentTabId (tabId) {
48         // Set it
49         //* DEBUG: */ alert('currentTabId=' + currentTabId + ',tabId=' + tabId);
50         currentTabId = tabId;
51 }
52
53 // Marks a tab navigation entry
54 function markTabNavigation (prefix, tab) {
55         // Is process working?
56         if (processDisplayed == true) {
57                 // Then exit silently
58                 return;
59         } // END - if
60
61         // Get all li-tags
62         var li = document.getElementsByTagName('li');
63
64         // Set current tab name
65         var currentTabName = 'tab_enabled';
66
67         // Set tab name
68         var tabName = prefix + '_' + tab;
69
70         // Search for all menus
71         for (var i = 0; i < li.length; i++) {
72                 // Debug message
73                 //* DEBUG: */ document.write('className=' + li[i].className + ',prefix=' + prefix + ',tab=' + tab + '<br />');
74
75                 // Check for valid tab
76                 if (li[i].className.substr(0, currentTabName.length) == currentTabName) {
77                         // Okay does match (don't change any others)
78                         if (li[i].id == tabName) {
79                                 // Mark this menu
80                                 $('li#' + tabName).addClass('tab_active');
81                                 //li[i].className += ' tab_active';
82                         } else {
83                                 // Unmark this menu
84                                 $('li#' + li[i].id).removeClass('tab_active');
85                                 //li[i].className = currentTabName;
86                         }
87                 } // END - if
88         } // END - for
89 }
90
91 // Enables a given element
92 function enableElement (element) {
93         // Remove class and attribute
94         $(element).removeClass('disabled');
95         $(element).removeAttr('disabled');
96 }
97
98 // Disables a given element
99 function disableElement (element) {
100         // Add class and attribute
101         $(element).addClass('disabled');
102         $(element).attr('disabled', 'disabled');
103
104         // Blur the element
105         $(element).blur();
106 }
107
108 // Enables a given footer navigation element
109 function enableFooterNavigationPage (element) {
110         // Remove the 'disabled' class and attribute
111         if (element == 'finish') {
112                 enableElement('input#finish');
113         } else {
114                 enableElement('input#' + element + '_page');
115                 disableElement('input#finish');
116         }
117 }
118
119 // Resets footer navigation by adding CSS class 'disabled'
120 function resetFooterNavigation () {
121         // Remove the 'disabled' class and attribute
122         for (var i = 0; i < footerElements.length; i++) {
123                 $('input#' + footerElements[i] + '_page').addClass('disabled');
124                 $('input#' + footerElements[i] + '_page').attr('disabled', 'disabled');
125                 $('input#' + footerElements[i] + '_page').blur();
126         } // END - for
127 }
128
129 // Getter for AJAX content
130 function getAjaxContent () {
131         // Is it defined?
132         if ($('body').data('ajax_content') == undefined) {
133                 // Not set
134                 throw new 'ajax_content requested but not set.';
135         } // END - if
136
137         // Return it
138         return $('body').data('ajax_content');
139 }
140
141 // "Setter" for AJAX content but does decode the content
142 function setAjaxDecodedContent (ajax_content) {
143         // Decode URL-encoded data ...
144         var decoded = decodeUrlEncoding(ajax_content);
145
146         // ... and set it
147         setAjaxContent(decoded);
148 }
149
150 // Setter for AJAX content
151 function setAjaxContent (ajax_content) {
152         $('body').data('ajax_content', ajax_content);
153 }
154
155 // Getter for AJAX success
156 function getAjaxSuccess () {
157         return $('body').data('ajax_success');
158 }
159
160 // Setter for AJAX success
161 function setAjaxSuccess (success) {
162         $('body').data('ajax_success', success);
163 }
164
165 // Set AJAX reply and decode JSON if requested
166 function setAjaxReply (reply, isJson) {
167         // Is it JSON URL-encoded content?
168         if ((isJson != undefined) && (isJson == true)) {
169                 // Decode URL-encoding (for some reason it must be here ...)
170                 var localReply = decodeUrlEncoding(reply);
171
172                 // Then decode it, replace '%20' with space before because '%20' breakes JSON content
173                 var obj = jQuery.parseJSON(localReply.replace('%20', ' '));
174
175                 // ... and set it
176                 setAjaxContent(obj);
177         } else {
178                 // Handle the content over to decode it
179                 setAjaxDecodedContent(reply);
180         }
181 }
182
183 // Sends out an AJAX request
184 function sendAjaxRequest (level, doValue, extra, isJson) {
185         // By default all requests failed
186         setAjaxSuccess(false);
187
188         // Reset AJAX content
189         setAjaxContent('');
190
191         // Send out the raw request
192         $.ajax({
193                 url: 'ajax.php',
194                 type: 'POST',
195                 data: 'level=' + level + '&do=' + doValue + extra,
196                 dataType: 'json',
197                 async: false,
198
199                 // Called on success
200                 success: function (ajax_content) {
201                         // Is ajax_content set?
202                         if (ajax_content.reply_content == undefined) {
203                                 // This shall not happen
204                                 throw new 'ajax_content.reply_content not returned from ajax.php, please fix your scripts. (1)';
205                         } else if (ajax_content.reply_content == null) {
206                                 // This shall not happen, too
207                                 throw new 'ajax_content.reply_content=null from ajax.php, please fix your scripts. (2)';
208                         }
209
210                         // Set AJAX reply
211                         setAjaxReply(ajax_content.reply_content, isJson);
212
213                         // Mark it as success
214                         setAjaxSuccess(true);
215                 },
216
217                 // Called in case of an error (e.g. HTTP response status not '200 OK')
218                 error: function (ajax_content) {
219                         // Is ajax_content set?
220                         if (ajax_content.reply_content == undefined) {
221                                 // Is 'responseText' there?
222                                 if (ajax_content.responseText != undefined) {
223                                         // Then parse it
224                                         var obj = jQuery.parseJSON(ajax_content.responseText.replace('%20', ' '));
225
226                                         // Is 'reply_content' set?
227                                         if (obj.reply_content == undefined) {
228                                                 // This shall not happen
229                                                 throw new 'obj.reply_content not returned from ajax.php, please fix your scripts. (3)';
230                                         } // END - if
231
232                                         // Set it
233                                         setAjaxReply(obj.reply_content, false);
234                                         return false;
235                                 } else {
236                                         // This shall not happen
237                                         throw new 'ajax_content.reply_content not returned from ajax.php, please fix your scripts. (4)';
238                                 }
239                         } else if (ajax_content.reply_content == null) {
240                                 // This shall not happen, too
241                                 throw new 'ajax_content.reply_content=null from ajax.php, please fix your scripts. (5)';
242                         }
243
244                         // Set AJAX reply
245                         setAjaxReply(ajax_content.reply_content, isJson);
246                 }
247         });
248
249         // Return status
250         return getAjaxSuccess();
251 }
252
253 // Enables footer navigation buttons
254 function enableFooterNavigation (prefix, tabId) {
255         // Is process working?
256         if (processDisplayed == true) {
257                 // Then exit silently
258                 return;
259         } // END - if
260
261         // Reset both footer navigation first
262         resetFooterNavigation();
263
264         // Do the AJAX request (JSON as content is enabled)
265         if (sendAjaxRequest(prefix, 'footer_navigation', '&tab=' + tabId, true) == true) {
266                 // Parse the content
267                 $.each(getAjaxContent(), function (i, value) {
268                         // Enable current element
269                         enableFooterNavigationPage(value);
270                 });
271         } else {
272                 // Display error window
273                 displayErrorWindow(prefix, getAjaxContent());
274         }
275 }
276
277 // Requests an AJAX content
278 function requestAjaxContent (prefix, htmlId, tabId, footerNavigation) {
279         // Is process working?
280         if (processDisplayed == true) {
281                 // Then exit silently
282                 return;
283         } // END - if
284
285         // Check if this request is disabled
286         if ($('#' + prefix + '_' + tabId).hasClass('tab_disabled')) {
287                 // Clicked on a disabled tabId so blur it
288                 //* DEBUG: */ alert('requestAjaxContent(): prefix=' + prefix + ',htmlId=' + htmlId + ',tabId=' + tabId + ' - DISABLED!');
289                 return;
290         } else if (formChanged == true) {
291                 // Has changed form , so output message to browser
292                 //* DEBUG: */ alert('requestAjaxContent(): prefix=' + prefix + ',htmlId=' + htmlId + ',tabId=' + tabId + ' - FORM CHANGED!');
293                 displayChangedWarningWindow(prefix, tabId);
294
295                 // Abort here
296                 return;
297         }
298
299         // Only request if content is different
300         //* DEBUG: */ alert('requestAjaxContent(): prefix=' + prefix + ',htmlId=' + htmlId + ',tabId=' + tabId + ',currentTabId=' + currentTabId);
301         if (tabId != currentTabId) {
302                 // Set tabId as current
303                 //* DEBUG: */ alert('requestAjaxContent(): prefix=' + prefix + ',htmlId=' + htmlId + ',tabId=' + tabId + ' - Calling setCurrentTabId()');
304                 setCurrentTabId(tabId);
305
306                 // Fade the old content out
307                 $('#' + htmlId).fadeOut('fast', function() {
308                         // Send AJAX request
309                         if (sendAjaxRequest(prefix, 'request_content', '&tab=' + tabId, false) == true) {
310                                 // Add the HTML content
311                                 $('#' + htmlId).html(getAjaxContent());
312
313                                 // Fade the content in
314                                 $('#' + htmlId).fadeIn('fast', function() {
315                                         // This differs, so mark the menu and request content
316                                         markTabNavigation(prefix, tabId);
317
318                                         // Is the footer navigation enabled?
319                                         if (footerNavigation == true) {
320                                                 // Change footer navigation as well
321                                                 enableFooterNavigation(prefix, tabId);
322                                         } // END - if
323                                 });
324                         } else {
325                                 // Display error window
326                                 displayErrorWindow(prefix, getAjaxContent());
327                         }
328                 });
329         } else {
330                 // Same id
331                 //* DEBUG: */ alert('SAME!');
332         }
333 }
334
335 // Displays a test window
336 function displayTestWindow (prefix, element) {
337         // Register click-event for error window
338         $('#' + prefix + '_error_close').click(function () {
339                 // Close the window
340                 closeErrorWindow(prefix);
341         });
342
343         // Register click-event for warning window
344         $('#' + prefix + '_warning_close').click(function () {
345                 // Close the window
346                 //* DEBUG: */ alert('displayTestWindow(): prefix=' + prefix + ' - calling closeWarningWindow()');
347                 closeWarningWindow(prefix);
348         });
349
350         // Request it from the AJAX backend
351         if (sendAjaxRequest(prefix, 'test', '', false) == true) {
352                 // Transfer the returned content to the prefix_warning_content id
353                 $('#' + prefix + '_warning_content').html(getAjaxContent());
354
355                 // Fade the warning in
356                 $('#' + prefix + '_warning').fadeIn('slow', function() {
357                         // Enable element
358                         enableElement(element);
359                 });
360
361                 // Mark 'warning' as displayed
362                 warningDisplayed = true;
363         } else {
364                 // Display error message
365                 displayErrorWindow(prefix, getAjaxContent());
366         }
367 }
368
369 // Displays a warning window above the form to warn about changed&unsafed fields
370 function displayChangedWarningWindow (prefix, button) {
371         // Fade out warning window, if open
372         //* DEBUG: */ alert('displayChangedWarningWindow(): prefix=' + prefix + ',button=' + button + ' - calling closeWarningWindow()');
373         closeWarningWindow(prefix);
374
375         // Fade error out for eye-candy, if open
376         closeErrorWindow(prefix);
377
378         // Abort here if warningDisplayed is still true
379         if (warningDisplayed == true) {
380                 // Make sure this doesn't happen
381                 return;
382         } // END - if
383
384         // Request it from the AJAX backend
385         if (sendAjaxRequest(prefix, 'change_warning', '&button=' + button + '&elements=' + changedElements.join(':')) == true) {
386                 // Transfer the returned content to the prefix_warning_content id
387                 $('#' + prefix + '_warning_content').html(getAjaxContent());
388
389                 // Fade the warning in
390                 $('#' + prefix + '_warning').fadeIn('slow', function() {
391                         // Mark warning as displayed
392                         warningDisplayed = true;
393                 });
394         } else {
395                 // Display error message
396                 displayErrorWindow(prefix, getAjaxContent());
397         }
398 }
399
400 // Displays the error window for given prefix and content
401 function displayErrorWindow (prefix, ajax_content) {
402         // Fade out warning window, if open
403         //* DEBUG: */ alert('displayErrorWindow(): prefix=' + prefix + ' - calling closeWarningWindow()');
404         closeWarningWindow(prefix);
405
406         // Fade it out for eye-candy
407         closeErrorWindow(prefix);
408
409         // Abort here if errorDisplayed is still true
410         if (errorDisplayed == true) {
411                 // Make sure this doesn't happen
412                 return;
413         } // END - if
414
415         // Copy the response text to the error variable
416         if (ajax_content.reply_content != undefined) {
417                 $('#' + prefix + '_error_content').html(ajax_content.reply_content);
418         } else {
419                 $('#' + prefix + '_error_content').html(ajax_content);
420         }
421
422         // Fade the error in
423         $('#' + prefix + '_error').fadeIn('slow', function() {
424                 // Mark error as displayed
425                 errorDisplayed = true;
426         });
427 }
428
429 // Displays the process window for given prefix and content
430 function displayProcessWindow (prefix, ajax_content) {
431         // Fade out warning window, if open
432         //* DEBUG: */ alert('displayProcessWindow(): prefix=' + prefix + ' - calling closeWarningWindow()');
433         closeWarningWindow(prefix);
434
435         // Fade it out for eye-candy
436         closeErrorWindow(prefix);
437
438         // Fade it out for eye-candy
439         closeProcessWindow(prefix);
440
441         // Abort here if processDisplayed is still true
442         if (processDisplayed == true) {
443                 // Make sure this doesn't happen
444                 return;
445         } // END - if
446
447         // Copy the response text to the process variable
448         if (ajax_content.reply_content != undefined) {
449                 $('#' + prefix + '_process_content').html(ajax_content.reply_content);
450         } else {
451                 $('#' + prefix + '_process_content').html(ajax_content);
452         }
453
454         // Fade the process in
455         $('#' + prefix + '_process').fadeIn('slow', function() {
456                 // Mark process as displayed
457                 processDisplayed = true;
458         });
459 }
460
461 // Waits until the window has been closed
462 function closeErrorLocked () {
463         // Has all been loaded?
464         if (errorDisplayed == false) {
465                 // Then release ready()
466                 $.holdReady(false);
467         } else {
468                 // Recursive call again
469                 window.setTimeout('closeErrorLocked()', 10);
470         }
471 }
472
473 // Waits until the window has been closed
474 function closeProcessLocked () {
475         // Has all been loaded?
476         if (processDisplayed == false) {
477                 // Then release ready()
478                 $.holdReady(false);
479         } else {
480                 // Recursive call again
481                 window.setTimeout('closeProcessLocked()', 10);
482         }
483 }
484
485 // Closes an error window
486 function closeErrorWindow (prefix, waitClose, resetCurrentTabId) {
487         // Is the error displayed?
488         if (errorDisplayed == true) {
489                 // Shall we wait ("sync") until the animation has completed?
490                 if (waitClose == true) {
491                         // Hold the ready status
492                         $.holdReady(true);
493                 } // END - if
494
495                 // Yes, then fade it out
496                 $('#' + prefix + '_error').fadeOut('fast', function() {
497                         // Set current tab id to default
498                         if (resetCurrentTabId == true) {
499                                 setCurrentTabId(defaultTabId);
500                         } // END - if
501
502                         // Mark it as closed
503                         errorDisplayed = false;
504                 });
505
506                 // Shall this animation be "synchronized"?
507                 if (waitClose == true) {
508                         // Wait for the window has been closed
509                         closeErrorLocked();
510                 } // END - if
511         } // END - if
512 }
513
514 // Closes an process window
515 function closeProcessWindow (prefix, waitClose, resetCurrentTabId) {
516         // Is the process displayed?
517         if (processDisplayed == true) {
518                 // Shall we wait ("sync") until the animation has completed?
519                 if (waitClose == true) {
520                         // Hold the ready status
521                         $.holdReady(true);
522                 } // END - if
523
524                 // Yes, then fade it out
525                 $('#' + prefix + '_process').fadeOut('fast', function() {
526                         // Set current tab id to default
527                         if (resetCurrentTabId == true) {
528                                 setCurrentTabId(defaultTabId);
529                         } // END - if
530
531                         // Mark it as closed
532                         processDisplayed = false;
533                 });
534
535                 // Shall this animation be "synchronized"?
536                 if (waitClose == true) {
537                         // Wait for the window has been closed
538                         closeProcessLocked();
539                 } // END - if
540         } // END - if
541 }
542
543 // Waits until the window has been closed
544 function closeWarningLocked () {
545         // Has all been loaded?
546         if (warningDisplayed == false) {
547                 // Then release ready()
548                 $.holdReady(false);
549         } else {
550                 // Recursive call again
551                 window.setTimeout('closeWarningLocked()', 10);
552         }
553 }
554
555 // Closes an warning window
556 function closeWarningWindow (prefix, waitClose, resetCurrentTabId) {
557         //* DEBUG: */ alert('prefix=' + prefix + ',waitClose=' + waitClose + ' - ENTERED!');
558         // Is the warning displayed?
559         if (warningDisplayed == true) {
560                 // Shall we wait ("sync") until the animation has completed?
561                 //* DEBUG: */ alert('prefix=' + prefix + ',waitClose=' + waitClose + ',warningDisplayed=true');
562                 if (waitClose == true) {
563                         // Hold the ready status
564                         $.holdReady(true);
565                 } // END - if
566
567                 // Yes, then fade it out
568                 $('#' + prefix + '_warning').fadeOut('fast', function() {
569                         // Set current tab id to default
570                         //* DEBUG: */ alert('closeWarningWindow(): prefix=' + prefix + ',waitClose=' + waitClose + ',defaultTab=' + defaultTabId + ' - Calling setCurrentTabId()');
571                         if (resetCurrentTabId == true) {
572                                 setCurrentTabId(defaultTabId);
573                         } // END - if
574
575                         // Mark it as closed
576                         warningDisplayed = false;
577                         //* DEBUG: */ alert('closeWarningWindow(): waitClose=' + waitClose + ',resetCurrentTabId=' + resetCurrentTabId + ',warningDisplayed=false');
578                 });
579
580                 // Shall this animation be "synchronized"?
581                 if (waitClose == true) {
582                         // Wait for the window has been closed
583                         //* DEBUG: */ alert('prefix=' + prefix + ',waitClose=' + waitClose + ' - LOCKED!');
584                         closeWarningLocked();
585                 } // END - if
586         } // END - if
587 }
588
589 // A footer navigation button has been clicked
590 function doFooterPage (prefix, htmlId, button) {
591         //* DEBUG: */ alert('doFooterPage(): prefix=' + prefix + ',htmlId=' + htmlId + ',button=' + button + ' - ENTERED!');
592         // Has something being changed?
593         if (formChanged == true) {
594                 // Output message to browser
595                 displayChangedWarningWindow(prefix, button);
596
597                 // Abort here
598                 return;
599         } // END - if
600
601         // Is process working?
602         if (processDisplayed == true) {
603                 // Then exit silently
604                 return;
605         } // END - if
606
607         // Is there a 'next' entry?
608         //* DEBUG: */ alert('doFooterPage(): button=' + button + ',currentTabId=' + currentTabId + ',nextPage[currentTabId]=' + nextPage[currentTabId]);
609         if ((button == 'next') && (nextPage[currentTabId] != null)) {
610                 // Then call the AJAX requester
611                 var page = nextPage[currentTabId];
612         } else if ((button == 'previous') && (previousPage[currentTabId] != null)) {
613                 // Then call the AJAX requester
614                 var page = previousPage[currentTabId];
615         }
616
617         // Request AJAX content
618         requestAjaxContent(prefix, htmlId, page);
619
620         // Change the footer navigation
621         enableFooterNavigation(prefix, page);
622 }
623
624 // Allows to save made changes (this will be called if the onchange event has been triggered)
625 function allowSaveChanges (element) {
626         // Mark element as changed, unmark as failed
627         $('#' + element).addClass('field_changed');
628         $('#' + element).removeClass('field_failed');
629
630         // Is the element not there?
631         if (!in_array(element, changedElements)) {
632                 // Mark the form as changed
633                 formChanged = true;
634
635                 // Make the 'Save changes' button clickable
636                 enableElement('#' + saveChangesId);
637
638                 // Remember this for later AJAX call
639                 changedElements.push(element);
640         } // END - if
641 }
642
643 // Marks all elements as unchanged/not failed
644 function markAllElementsAsUnchanged () {
645         // Remove status from all fields
646         for (var i = 0; i < changedElements.length; i++) {
647                 // Mark the element as changed
648                 $('#' + changedElements[i]).removeClass('field_changed');
649                 $('#' + changedElements[i]).removeClass('field_failed');
650         } // END - for
651 }
652
653 // Function to reset the form
654 function resetMailerAjaxForm () {
655         // Debug message
656         //* DEBUG: */ alert('resetMailerAjaxForm(): changedElements()=' + changedElements.length + ',saveChangesId=' + saveChangesId + ' - ENTERED!');
657
658         // Mark all elements as unchanged
659         markAllElementsAsUnchanged();
660
661         // Clear all changed elements
662         disableElement('input#' + saveChangesId);
663
664         // Reset changed elements and mark form as not changed
665         changedElements = new Array();
666         formChanged     = false;
667 }
668
669 // Mark given fields as failed
670 function markFormFieldsFailed (failedFields) {
671         // Mark all elements as failed
672         $.each(failedFields, function (i, field) {
673                 // Mark the element as 'failed'
674                 $('#' + field).removeClass('field_changed');
675                 $('#' + field).addClass('field_failed');
676
677                 // Also register it as 'changed', if not found
678                 if (!in_array(field, changedElements)) {
679                         // Okay, not yet added, so push it on the array
680                         changedElements.push(field);
681                 } // END - if
682         });
683 }
684
685 // Processes the content from AJAX call
686 function processAjaxResponseContent (prefix, ajax_content) {
687         // By default all is failed
688         var isResponseDone = false;
689
690         // Is 'status' and 'message' set?
691         if ((ajax_content.status == undefined) || (ajax_content.message == undefined)) {
692                 // No status/message set
693                 lastErrorMessage = 'Returned content does not provide &#36;status&#36; or &#36;message&#36; which is required.';
694         } else if ((ajax_content.status != 'done') && (ajax_content.status != 'failed')) {
695                 // This is also not good, only 'failed' or 'done' is supported
696                 lastErrorMessage = ajax_content.message + '<br />\nAdditionally an unknown status ' + ajax_content.status + ' was detected.';
697         } else if (ajax_content.status == 'failed') {
698                 // Something bad went wrong so copy the message
699                 lastErrorMessage = ajax_content.message;
700         } else {
701                 // All fine
702                 isResponseDone = true;
703         }
704
705         // Return status
706         return isResponseDone;
707 }
708
709 // Saves changes by sending the data to the AJAX backend script
710 function saveChanges (prefix) {
711         // Is process working?
712         if (processDisplayed == true) {
713                 // Then exit silently
714                 return;
715         } // END - if
716
717         // Mark all elements as unchanged
718         markAllElementsAsUnchanged();
719
720         // Is there changed elements
721         if (changedElements.length == 0) {
722                 // This should not happen
723                 displayErrorWindow(prefix, '<div class="ajax_error_message">saveChanges() called with no changed elements.</div>');
724         } else if (saveChangesId == null) {
725                 // saveChangesId is not det
726                 displayErrorWindow(prefix, '<div class="ajax_error_message">saveChangesId is not set. Please add <em>saveChanges = \'foo_bar\';</em> to your code.</div>');
727         }
728
729         // Serialize the whole form
730         var serializedData = $('form').serialize();
731
732         // Hold the ready status
733         $.holdReady(true);
734         saveChangesPending = true;
735
736         /*
737          * Send the request to the AJAX backend, it doesn't matter from which page
738          * this was requested.
739          */
740         if (sendAjaxRequest(prefix, 'save_changes', '&tab=' + currentTabId + '&' + serializedData, true) == true) {
741                 // Get the content
742                 var ajax_content = getAjaxContent();
743
744                 // Process the returned content
745                 if (processAjaxResponseContent(prefix, ajax_content) == true) {
746                         // Mark all elements as unchanged
747                         markAllElementsAsUnchanged();
748
749                         // Reset form
750                         resetMailerAjaxForm();
751                 } else {
752                         // Is there 'failed_fields' set?
753                         if ((ajax_content.failed_fields != undefined) && (ajax_content.message != undefined)) {
754                                 // Mark all fields as 'failed'
755                                 markFormFieldsFailed(ajax_content.failed_fields);
756
757                                 // Display the error message
758                                 displayErrorWindow(prefix, '<div class="ajax_error_message">' + ajax_content.message + '</div>');
759                         } else {
760                                 // This didn't work, why?
761                                 displayErrorWindow(prefix, '<div class="ajax_error_message">processAjaxResponseContent() failed, please fix this.<br />\n' + lastErrorMessage + '</div>');
762                         }
763                 }
764
765                 // Saving changes may have worked
766                 saveChangesPending = false;
767         } else {
768                 // Mark all elements as unchanged
769                 markAllElementsAsUnchanged();
770
771                 // Display error message
772                 displayErrorWindow(prefix, getAjaxContent());
773
774                 // Saving changes didn't work
775                 saveChangesPending = false;
776         }
777
778         // Wait for all has finished
779         saveChangesLocked();
780 }
781
782 // Waiting for resources being loaded
783 function saveChangesLocked () {
784         // Has all been loaded?
785         if (saveChangesPending == false) {
786                 // Then release ready()
787                 $.holdReady(false);
788         } else {
789                 // Recursive call again
790                 window.setTimeout('saveChangesLocked()', 10);
791         }
792 }
793
794 // Saves changed settings and continues with given page (next/previous)
795 function doSaveChangesPage (prefix, htmlId, page) {
796         // Save the changes
797         saveChanges(prefix);
798
799         // Close the window
800         //* DEBUG: */ alert('doSaveChangesPage(): prefix=' + prefix + ',htmlId=' + htmlId + ',page=' + page + ' - calling closeWarningWindow()');
801         closeWarningWindow(prefix, true, false);
802
803         // Load requested page
804         doFooterPage(prefix, htmlId, page);
805 }
806
807 // Saves changed settings and continues with given tab
808 function doSaveChangesContinue (prefix, htmlId, tab) {
809         // Is process working?
810         if (processDisplayed == true) {
811                 // Then exit silently
812                 return;
813         } // END - if
814
815         // Save the changes
816         saveChanges(prefix);
817
818         // Close the window
819         //* DEBUG: */ alert('doSaveChangesPage(): prefix=' + prefix + ',htmlId=' + htmlId + ',tab=' + tab + ' - calling closeWarningWindow()');
820         closeWarningWindow(prefix, true, false);
821
822         // Load requested content
823         requestAjaxContent(prefix, htmlId, tab);
824 }