]> git.mxchange.org Git - mailer.git/blob - js/ajax-common.js
Heacy rewrite/cleanup:
[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 - 2013 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 defaultTabId       = null;
32 var footerElements     = new Array();
33 var changedElements    = new Array();
34 var data               = new Array();
35 var formChanged        = false;
36 var saveChangesId      = null;
37 var lastErrorMessage   = null;
38 var saveChangesPending = false;
39
40 // Counter for success steps
41 var counterSuccess = 0;
42
43 // Add all footer navigation elements
44 footerElements[0] = 'next';
45 footerElements[1] = 'previous';
46
47 // Setter for current tab id
48 function setCurrentTabId (tabId) {
49         // Set it
50         //* DEBUG: */ alert('currentTabId=' + currentTabId + ',tabId=' + tabId);
51         currentTabId = tabId;
52 }
53
54 // Checks whether a given element is visible by checking 'display: none'
55 function isElementVisible (prefix, element) {
56         //* DEBUG: */ alert('isElementVisible(' + prefix + ',' + element + ') Called!');
57
58         // Get element
59         var el = document.getElementById(prefix + '_' + element);
60         //* DEBUG: */ alert('isElementVisible(): el=' + el);
61
62         // Is element set?
63         if ((el === null) || (el == undefined)) {
64                 throw new ('prefix=' + prefix + ',element=' + element + ' does not exist.');
65         } else if ((el.style.display == undefined) || (el.style.display == '')) {
66                 throw new ('prefix=' + prefix + ',element=' + element + ' has no style.display element.');
67         }
68
69         // Default is visible
70         var isVisible = (el.style.display != 'none');
71         //* DEBUG: */ alert(prefix + '_' + element + ':' + el.style.display + '=' + isVisible);
72
73         // Return status
74         return isVisible;
75 }
76
77 // Marks a tab navigation entry
78 function markTabNavigation (prefix, tab) {
79         // Is progress working?
80         if (isElementVisible(prefix, 'progress')) {
81                 // Then exit silently
82                 return;
83         } // END - if
84
85         // Get all li-tags
86         var li = document.getElementsByTagName('li');
87
88         // Set current tab name
89         var currentTabName = 'tab_enabled';
90
91         // Set tab name
92         var tabName = prefix + '_' + tab;
93
94         // Search for all menus
95         for (var i = 0; i < li.length; i++) {
96                 // Debug message
97                 //* DEBUG: */ document.write('className=' + li[i].className + ',prefix=' + prefix + ',tab=' + tab + '<br />');
98
99                 // Check for valid tab
100                 if (li[i].className.substr(0, currentTabName.length) == currentTabName) {
101                         // Okay does match (don't change any others)
102                         if (li[i].id == tabName) {
103                                 // Mark this menu
104                                 $('li#' + tabName).addClass('tab_active');
105                                 //li[i].className += ' tab_active';
106                         } else {
107                                 // Unmark this menu
108                                 $('li#' + li[i].id).removeClass('tab_active');
109                                 //li[i].className = currentTabName;
110                         }
111                 } // END - if
112         } // END - for
113 }
114
115 // Enables a given element
116 function enableElement (element) {
117         // Remove class and attribute
118         $(element).removeClass('disabled');
119         $(element).removeAttr('disabled');
120 }
121
122 // Disables a given element
123 function disableElement (element) {
124         // Add class and attribute
125         $(element).addClass('disabled');
126         $(element).attr('disabled', 'disabled');
127
128         // Blur the element
129         $(element).blur();
130 }
131
132 // Enables a given footer navigation element
133 function enableFooterNavigationPage (element) {
134         // Is it 'finish'?
135         if (element == 'finish') {
136                 // Then without '_page' suffix
137                 enableElement('input#finish');
138         } else {
139                 // Regular element with '_page' suffix
140                 enableElement('input#' + element + '_page');
141
142                 // Disable 'finish' element
143                 disableElement('input#finish');
144         }
145 }
146
147 // Resets footer navigation by adding CSS class 'disabled'
148 function resetFooterNavigation () {
149         // Remove the 'disabled' class and attribute
150         for (var i = 0; i < footerElements.length; i++) {
151                 disableElement('input#' + footerElements[i] + '_page');
152         } // END - for
153
154         // Disable this element
155         disableElement('input#finish');
156 }
157
158 // Getter for AJAX content
159 function getAjaxContent () {
160         // Is it defined?
161         if (data['ajax_content'] == undefined) {
162                 // Not set
163                 throw new('ajax_content requested but not set.');
164         } // END - if
165
166         // Return it
167         return data['ajax_content'];
168 }
169
170 // Setter for AJAX content
171 function setAjaxContent (ajax_content) {
172         data['ajax_content'] = ajax_content;
173 }
174
175 // "Setter" for AJAX content but does decode the content
176 function setAjaxDecodedContent (ajax_content) {
177         // Decode URL-encoded data ...
178         var decoded = decodeUrlEncoding(ajax_content);
179
180         // ... and set it
181         setAjaxContent(decoded);
182 }
183
184 // Getter for AJAX success
185 function getAjaxSuccess () {
186         return data['ajax_success'];
187 }
188
189 // Setter for AJAX success
190 function setAjaxSuccess (success) {
191         data['ajax_success'] = success;
192 }
193
194 // Set AJAX reply and decode JSON if requested
195 function setAjaxReply (reply, isJson) {
196         // Is it JSON URL-encoded content?
197         //* DEBUG: */ alert('setAjaxReply(): reply=' + reply + ',isJson=' + isJson);
198         if ((isJson != undefined) && (isJson === true)) {
199                 // Decode URL-encoding (for some reason it must be here ...)
200                 var localReply = decodeUrlEncoding(reply);
201
202                 // Then decode it, replace '%20' with space before because '%20' breakes JSON content
203                 var obj = jQuery.parseJSON(localReply.replace('%20', ' '));
204
205                 // ... and set it
206                 setAjaxContent(obj);
207         } else {
208                 // Handle the content over to decode it
209                 setAjaxDecodedContent(reply);
210         }
211 }
212
213 // Sends out an AJAX request
214 function sendAjaxRequest (level, doValue, extra, isJson) {
215         // By default all requests failed
216         setAjaxSuccess(false);
217
218         // Reset AJAX content
219         setAjaxContent('');
220
221         // Send out the raw request
222         $.ajax({
223                 url: 'ajax.php',
224                 type: 'POST',
225                 data: 'level=' + level + '&do=' + doValue + extra,
226                 dataType: 'json',
227                 async: false,
228                 timeout: 10000,
229
230                 // Called on success
231                 success: function (ajax_content) {
232                         // Is ajax_content set?
233                         if (ajax_content.reply_content == undefined) {
234                                 // This shall not happen
235                                 throw new('ajax_content.reply_content not returned from ajax.php, please fix your scripts. (1)');
236                         } else if (ajax_content.reply_content === null) {
237                                 // This shall not happen, too
238                                 throw new('ajax_content.reply_content=null from ajax.php, please fix your scripts. (2)');
239                         }
240
241                         // Set AJAX reply
242                         setAjaxReply(ajax_content.reply_content, isJson);
243
244                         // Mark it as success
245                         setAjaxSuccess(true);
246
247                         // Was there a redirect?
248                         if ((ajax_content.redirect != undefined) && (ajax_content.redirect != null)) {
249                                 // Redirect URL detected
250                                 // @TODO Need this be secured?
251                                 document.location.href = ajax_content.redirect;
252                         } // END - if
253                 },
254
255                 // Called in case of an error (e.g. HTTP response status not '200 OK')
256                 error: function (ajax_content) {
257                         // Is ajax_content set?
258                         if (ajax_content.reply_content == undefined) {
259                                 // Is 'responseText' there?
260                                 if (ajax_content.responseText != undefined) {
261                                         // Then parse it
262                                         var obj = jQuery.parseJSON(ajax_content.responseText.replace('%20', ' '));
263
264                                         // Is 'reply_content' set?
265                                         if (obj.reply_content == undefined) {
266                                                 // This shall not happen
267                                                 throw new('obj.reply_content not returned from ajax.php, please fix your scripts. (3)');
268                                         } // END - if
269
270                                         // Set it
271                                         setAjaxReply(obj.reply_content, false);
272                                         return false;
273                                 } else {
274                                         // This shall not happen
275                                         throw new('ajax_content.reply_content not returned from ajax.php, please fix your scripts. (4)');
276                                 }
277                         } else if (ajax_content.reply_content === null) {
278                                 // This shall not happen, too
279                                 throw new('ajax_content.reply_content=null from ajax.php, please fix your scripts. (5)');
280                         }
281
282                         // Set AJAX reply
283                         setAjaxReply(ajax_content.reply_content, isJson);
284
285                         // Was there a redirect?
286                         if ((ajax_content.redirect != undefined) && (ajax_content.redirect != null)) {
287                                 // Redirect URL detected
288                                 // @TODO Need this be secured?
289                                 document.location.href = ajax_content.redirect;
290                         } // END - if
291                 }
292         });
293
294         // Return status
295         //* DEBUG: */ alert(getAjaxSuccess() + ':' + level + ',' + doValue + ',' + extra + ',' + isJson);
296         return getAjaxSuccess();
297 }
298
299 // Enables footer navigation buttons
300 function enableFooterNavigation (prefix, tabId) {
301         // Is progress working?
302         if (isElementVisible(prefix, 'progress')) {
303                 // Then exit silently
304                 return;
305         } // END - if
306
307         // Reset both footer navigation first
308         resetFooterNavigation();
309
310         // Do the AJAX request (JSON as content is enabled)
311         if (sendAjaxRequest(prefix, 'footer_navigation', '&tab=' + tabId, true) === true) {
312                 // Parse the content
313                 $.each(getAjaxContent(), function (i, value) {
314                         // Enable current element
315                         enableFooterNavigationPage(value);
316                 });
317         } else {
318                 // Display error window
319                 displayErrorWindow(prefix, getAjaxContent());
320         }
321 }
322
323 // Requests an AJAX content
324 function requestAjaxContent (prefix, htmlId, tabId, footerNavigation) {
325         // Is progress working?
326         if (isElementVisible(prefix, 'progress')) {
327                 // Then exit silently
328                 return;
329         } // END - if
330
331         // Check if this request is disabled
332         if ($('#' + prefix + '_' + tabId).hasClass('tab_disabled')) {
333                 // Clicked on a disabled tabId so blur it
334                 //* DEBUG: */ alert('requestAjaxContent(): prefix=' + prefix + ',htmlId=' + htmlId + ',tabId=' + tabId + ' - DISABLED!');
335                 return;
336         } else if (formChanged === true) {
337                 // Has changed form , so output message to browser
338                 //* DEBUG: */ alert('requestAjaxContent(): prefix=' + prefix + ',htmlId=' + htmlId + ',tabId=' + tabId + ' - FORM CHANGED!');
339                 displayChangedWarningWindow(prefix, tabId);
340
341                 // Abort here
342                 return;
343         }
344
345         // Only request if content is different
346         //* DEBUG: */ alert('requestAjaxContent(): prefix=' + prefix + ',htmlId=' + htmlId + ',tabId=' + tabId + ',currentTabId=' + currentTabId);
347         if (tabId != currentTabId) {
348                 // Set tabId as current
349                 //* DEBUG: */ alert('requestAjaxContent(): prefix=' + prefix + ',htmlId=' + htmlId + ',tabId=' + tabId + ' - Calling setCurrentTabId()');
350                 setCurrentTabId(tabId);
351
352                 // Fade the old content out
353                 $('#' + htmlId).fadeOut('fast', function() {
354                         // Send AJAX request
355                         if (sendAjaxRequest(prefix, 'request_content', '&tab=' + tabId, false) === true) {
356                                 // Add the HTML content
357                                 $('#' + htmlId).html(getAjaxContent());
358
359                                 // Fade the content in
360                                 $('#' + htmlId).fadeIn('fast', function() {
361                                         // This differs, so mark the menu and request content
362                                         markTabNavigation(prefix, tabId);
363
364                                         // Is the footer navigation enabled?
365                                         if (footerNavigation === true) {
366                                                 // Change footer navigation as well
367                                                 enableFooterNavigation(prefix, tabId);
368                                         } // END - if
369                                 });
370                         } else {
371                                 // Display error window
372                                 displayErrorWindow(prefix, getAjaxContent());
373                         }
374                 });
375         } else {
376                 // Same id
377                 //* DEBUG: */ alert('SAME!');
378         }
379 }
380
381 // Displays a test window
382 function displayTestWindow (prefix, element) {
383         // Register click-event for error window
384         $('#' + prefix + '_error_close').click(function () {
385                 // Close the window
386                 closeErrorWindow(prefix, true, false);
387         });
388
389         // Register click-event for warning window
390         $('#' + prefix + '_warning_close').click(function () {
391                 // Close the window
392                 //* DEBUG: */ alert('displayTestWindow(): prefix=' + prefix + ' - calling closeWarningWindow()');
393                 closeWarningWindow(prefix, true, false);
394         });
395
396         // Request it from the AJAX backend
397         if (sendAjaxRequest(prefix, 'test', '', false) === true) {
398                 // Transfer the returned content to the prefix_warning_content id
399                 setWarningContent(prefix, getAjaxContent());
400
401                 // Fade the warning in
402                 $('#' + prefix + '_warning').fadeIn('slow', function() {
403                         // Enable element
404                         enableElement(element);
405                 });
406         } else {
407                 // Display error message
408                 displayErrorWindow(prefix, getAjaxContent());
409         }
410 }
411
412 // Fades slowly in given window
413 function fadeInWindow (prefix, id) {
414         // Do the fade-in
415         $('#' + prefix + '_' + id).fadeIn('slow', function() {
416                 // Do nothing for now
417         });
418 }
419
420 // Displays a warning window above the form to warn about changed&unsafed fields
421 function displayChangedWarningWindow (prefix, button) {
422         //* DEBUG: */ alert('displayChangedWarningWindow(): prefix=' + prefix + ',button=' + button + ' - calling closeWarningWindow()');
423         // Fade all windows out
424         closeAllWindows(prefix);
425
426         // Abort here if warningDisplayed is still true
427         //* DEBUG: */ alert('displayChangedWarningWindow(): Calling isElementVisible(' + prefix + ', warning)');
428         if (isElementVisible(prefix, 'warning')) {
429                 // Make sure this doesn't happen
430                 //* DEBUG: */ alert('displayChangedWarningWindow(): isElementVisible(' + prefix + ', warning)=true');
431                 return;
432         } // END - if
433
434         // Request it from the AJAX backend
435         //* DEBUG: */ alert('displayChangedWarningWindow(): Calling sendAjaxRequest(' + prefix + ', button=' + button  + ',changedElements()=' + changedElements.join(':') + ')');
436         if (sendAjaxRequest(prefix, 'change_warning', '&button=' + button + '&elements=' + changedElements.join(':')) === true) {
437                 // Transfer the returned content to the prefix_warning_content id
438                 setWarningContent(prefix, getAjaxContent());
439
440                 // Fade the warning in
441                 fadeInWindow(prefix, 'warning');
442         } else {
443                 // Display error message
444                 displayErrorWindow(prefix, getAjaxContent());
445         }
446 }
447
448 // Displays the error window for given prefix and content
449 function displayErrorWindow (prefix, ajax_content) {
450         //* DEBUG: */ alert('displayErrorWindow(): prefix=' + prefix + ',ajax_content=' + ajax_content + ' - calling closeWarningWindow()');
451         // Fade all windows out
452         closeAllWindows(prefix);
453
454         // Abort here if errorDisplayed is still true
455         if (isElementVisible(prefix, 'error')) {
456                 // Make sure this doesn't happen
457                 return;
458         } // END - if
459
460         // Copy the response text to the error variable
461         if (ajax_content.reply_content != undefined) {
462                 setErrorContent(prefix, ajax_content.reply_content);
463         } else {
464                 setErrorContent(prefix, ajax_content);
465         }
466
467         // Fade the error in
468         fadeInWindow(prefix, 'error');
469 }
470
471 // Displays the progress window for given prefix and content
472 function displayProgressWindow (prefix, ajax_content) {
473         //* DEBUG: */ alert('displayProgressWindow(): prefix=' + prefix + ' - calling closeWarningWindow()');
474         // Fade all windows out
475         closeAllWindows(prefix);
476
477         // Abort here if progressDisplayed is still true
478         if (isElementVisible(prefix, 'progress')) {
479                 // Make sure this doesn't happen
480                 return;
481         } // END - if
482
483         // Copy the response text to the progress variable
484         if (ajax_content.reply_content != undefined) {
485                 // Set HTML content
486                 setProgressContent(prefix, ajax_content.reply_content);
487         } else {
488                 setProgressContent(prefix, ajax_content);
489         }
490
491         // Fade the progress in
492         fadeInWindow(prefix, 'progress');
493 }
494
495 // Displays the success window for given prefix and content
496 function displaySuccessWindow (prefix, ajax_content) {
497         //* DEBUG: */ alert('displaySuccessWindow(): prefix=' + prefix + ' - calling closeWarningWindow()');
498         // Fade all windows out
499         closeAllWindows(prefix);
500
501         // Abort here if successDisplayed is still true
502         if (isElementVisible(prefix, 'success')) {
503                 // Make sure this doesn't happen
504                 return;
505         } // END - if
506
507         // Copy the response text to the success variable
508         if (ajax_content.reply_content != undefined) {
509                 // Set HTML content
510                 setSuccessContent(prefix, ajax_content.reply_content);
511         } else {
512                 setSuccessContent(prefix, ajax_content);
513         }
514
515         // Fade the success in
516         fadeInWindow(prefix, 'success');
517 }
518
519 // Sets "warning content"
520 function setWarningContent (prefix, content) {
521         // Set HTML content
522         $('#' + prefix + '_warning_content').html(content);
523 }
524
525 // Sets "error content"
526 function setErrorContent (prefix, content) {
527         // Set HTML content
528         $('#' + prefix + '_error_content').html(content);
529 }
530
531 // Sets "progress content"
532 function setProgressContent (prefix, content) {
533         // Set HTML content
534         $('#' + prefix + '_progress_content').html(content);
535 }
536
537 // Sets "success content"
538 function setSuccessContent (prefix, content) {
539         // Set HTML content
540         $('#' + prefix + '_success_content').html(content);
541 }
542
543 // Close all windows
544 function closeAllWindows (prefix) {
545         //* DEBUG: */ alert('closeAllWindows(): Calling closeWarningWindow(' + prefix + ', true, false)');
546         closeWarningWindow(prefix, true, false);
547         //* DEBUG: */ alert('closeAllWindows(): Calling closeErrorWindow(' + prefix + ', true, false)');
548         closeErrorWindow(prefix, true, false);
549         //* DEBUG: */ alert('closeAllWindows(): Calling closeProgressWindow(' + prefix + ', true, false)');
550         closeProgressWindow(prefix, true, false);
551         //* DEBUG: */ alert('closeAllWindows(): Calling closeSuccessWindow(' + prefix + ', true, false)');
552         closeSuccessWindow(prefix, true, false);
553         //* DEBUG: */ alert('closeAllWindows(): EXIT!');
554 }
555
556 // Waits until the window has been closed
557 function closeErrorLocked (prefix) {
558         // Has all been loaded?
559         if (!isElementVisible(prefix, 'error')) {
560                 // Then release ready()
561                 $.holdReady(false);
562         } else {
563                 // Recursive call again
564                 window.setTimeout('closeErrorLocked("' + prefix + '")', 10);
565         }
566 }
567
568 // Closes an error window
569 function closeErrorWindow (prefix, waitClose, resetCurrentTabId) {
570         // Is the error displayed?
571         if (isElementVisible(prefix, 'error')) {
572                 // Shall we wait ("sync") until the animation has completed?
573                 if (waitClose === true) {
574                         // Hold the ready status
575                         $.holdReady(true);
576                 } // END - if
577
578                 // Yes, then fade it out
579                 $('#' + prefix + '_error').fadeOut('fast', function() {
580                         // Set current tab id to default
581                         if (resetCurrentTabId === true) {
582                                 setCurrentTabId(defaultTabId);
583                         } // END - if
584                 });
585
586                 // Shall this animation be "synchronized"?
587                 if (waitClose === true) {
588                         // Wait for the window has been closed
589                         closeErrorLocked(prefix);
590                 } // END - if
591         } // END - if
592 }
593
594 // Waits until the window has been closed
595 function closeProgressLocked (prefix) {
596         // Has all been loaded?
597         if (!isElementVisible(prefix, 'progress')) {
598                 // Then release ready()
599                 $.holdReady(false);
600         } else {
601                 // Recursive call again
602                 window.setTimeout('closeProgressLocked("' + prefix + '")', 10);
603         }
604 }
605
606 // Closes an progress window
607 function closeProgressWindow (prefix, waitClose, resetCurrentTabId) {
608         // Is the progress displayed?
609         if (isElementVisible(prefix, 'progress')) {
610                 // Shall we wait ("sync") until the animation has completed?
611                 if (waitClose === true) {
612                         // Hold the ready status
613                         $.holdReady(true);
614                 } // END - if
615
616                 // Yes, then fade it out
617                 $('#' + prefix + '_progress').fadeOut('fast', function() {
618                         // Set current tab id to default
619                         if (resetCurrentTabId === true) {
620                                 setCurrentTabId(defaultTabId);
621                         } // END - if
622                 });
623
624                 // Shall this animation be "synchronized"?
625                 if (waitClose === true) {
626                         // Wait for the window has been closed
627                         closeProgressLocked(prefix);
628                 } // END - if
629         } // END - if
630 }
631
632 // Waits until the window has been closed
633 function closeSuccessLocked (prefix) {
634         // Has all been loaded?
635         if (!isElementVisible(prefix, 'success')) {
636                 // Then release ready()
637                 $.holdReady(false);
638         } else {
639                 // Recursive call again
640                 window.setTimeout('closeSuccessLocked("' + prefix + '")', 10);
641         }
642 }
643
644 // Closes an success window
645 function closeSuccessWindow (prefix, waitClose, resetCurrentTabId) {
646         // Is the success displayed?
647         //* DEBUG: */ alert('closeSuccessWindow(): prefix=' + prefix + ',waitClose=' + waitClose + ',resetCurrentTabId=' + resetCurrentTabId + ' - ENTERED!');
648         if (isElementVisible(prefix, 'success')) {
649                 // Shall we wait ("sync") until the animation has completed?
650                 if (waitClose === true) {
651                         // Hold the ready status
652                         $.holdReady(true);
653                 } // END - if
654
655                 // Yes, then fade it out
656                 $('#' + prefix + '_success').fadeOut('fast', function() {
657                         // Set current tab id to default
658                         if (resetCurrentTabId === true) {
659                                 setCurrentTabId(defaultTabId);
660                         } // END - if
661                 });
662
663                 // Shall this animation be "synchronized"?
664                 if (waitClose === true) {
665                         // Wait for the window has been closed
666                         closeSuccessLocked(prefix);
667                 } // END - if
668         } // END - if
669         //* DEBUG: */ alert('closeSuccessWindow(): prefix=' + prefix + ',waitClose=' + waitClose + ',resetCurrentTabId=' + resetCurrentTabId + ' - EXIT!');
670 }
671
672 // Waits until the window has been closed
673 function closeWarningLocked (prefix) {
674         // Has all been loaded?
675         if (!isElementVisible(prefix, 'warning')) {
676                 // Then release ready()
677                 $.holdReady(false);
678         } else {
679                 // Recursive call again
680                 window.setTimeout('closeWarningLocked("' + prefix + '")', 10);
681         }
682 }
683
684 // Closes an warning window
685 function closeWarningWindow (prefix, waitClose, resetCurrentTabId) {
686         //* DEBUG: */ alert('prefix=' + prefix + ',waitClose=' + waitClose + ' - ENTERED!');
687         // Is the warning displayed?
688         if (isElementVisible(prefix, 'warning')) {
689                 // Shall we wait ("sync") until the animation has completed?
690                 //* DEBUG: */ alert('prefix=' + prefix + ',waitClose=' + waitClose + ',warningDisplayed=true');
691                 if (waitClose === true) {
692                         // Hold the ready status
693                         $.holdReady(true);
694                 } // END - if
695
696                 // Yes, then fade it out
697                 $('#' + prefix + '_warning').fadeOut('fast', function() {
698                         // Set current tab id to default
699                         if (resetCurrentTabId === true) {
700                                 setCurrentTabId(defaultTabId);
701                         } // END - if
702                 });
703
704                 // Shall this animation be "synchronized"?
705                 if (waitClose === true) {
706                         // Wait for the window has been closed
707                         //* DEBUG: */ alert('prefix=' + prefix + ',waitClose=' + waitClose + ' - LOCKED!');
708                         closeWarningLocked(prefix);
709                 } // END - if
710         } // END - if
711 }
712
713 // A footer navigation button has been clicked
714 function doFooterPage (prefix, htmlId, button) {
715         //* DEBUG: */ alert('doFooterPage(): prefix=' + prefix + ',htmlId=' + htmlId + ',button=' + button + ' - ENTERED!');
716         // Has something being changed?
717         if (formChanged === true) {
718                 // Output message to browser
719                 displayChangedWarningWindow(prefix, button);
720
721                 // Abort here
722                 return;
723         } // END - if
724
725         // Is progress working?
726         if (isElementVisible(prefix, 'progress')) {
727                 // Then exit silently
728                 return;
729         } // END - if
730
731         // Is there a 'next' entry?
732         //* DEBUG: */ alert('doFooterPage(): button=' + button + ',currentTabId=' + currentTabId + ',nextPage[currentTabId]=' + nextPage[currentTabId]);
733         if ((button == 'next') && (nextPage[currentTabId] !== null)) {
734                 // Then call the AJAX requester
735                 var page = nextPage[currentTabId];
736         } else if ((button == 'previous') && (previousPage[currentTabId] !== null)) {
737                 // Then call the AJAX requester
738                 var page = previousPage[currentTabId];
739         }
740
741         // Request AJAX content
742         requestAjaxContent(prefix, htmlId, page);
743
744         // Change the footer navigation
745         enableFooterNavigation(prefix, page);
746 }
747
748 // Allows to save made changes (this will be called if the onchange event has been triggered)
749 function allowSaveChanges (element) {
750         // Mark element as changed, unmark as failed
751         $('#' + element).addClass('field_changed');
752         $('#' + element).removeClass('field_failed');
753
754         // Is the element not there?
755         if (!in_array(element, changedElements)) {
756                 // Mark the form as changed
757                 formChanged = true;
758
759                 // Make the 'Save changes' button clickable
760                 enableElement('#' + saveChangesId);
761
762                 // Remember this for later AJAX call
763                 changedElements.push(element);
764         } // END - if
765 }
766
767 // Marks all elements as unchanged/not failed
768 function markAllElementsAsUnchanged () {
769         // Remove status from all fields
770         for (var i = 0; i < changedElements.length; i++) {
771                 // Mark the element as changed
772                 $('#' + changedElements[i]).removeClass('field_changed');
773                 $('#' + changedElements[i]).removeClass('field_failed');
774         } // END - for
775 }
776
777 // Function to reset the form
778 function resetMailerAjaxForm () {
779         // Debug message
780         //* DEBUG: */ alert('resetMailerAjaxForm(): changedElements()=' + changedElements.length + ',saveChangesId=' + saveChangesId + ' - ENTERED!');
781
782         // Mark all elements as unchanged
783         markAllElementsAsUnchanged();
784
785         // Clear all changed elements
786         disableElement('input#' + saveChangesId);
787
788         // Reset changed elements and mark form as not changed
789         changedElements = new Array();
790         formChanged     = false;
791 }
792
793 // Mark given fields as failed
794 function markFormFieldsFailed (failedFields) {
795         // Mark all elements as failed
796         $.each(failedFields, function (i, field) {
797                 // Mark the element as 'failed'
798                 $('#' + field).removeClass('field_changed');
799                 $('#' + field).addClass('field_failed');
800
801                 // Also register it as 'changed', if not found
802                 if (!in_array(field, changedElements)) {
803                         // Okay, not yet added, so push it on the array
804                         changedElements.push(field);
805                 } // END - if
806         });
807 }
808
809 // Progresses the content from AJAX call
810 function progressAjaxResponseContent (prefix, ajax_content) {
811         // By default all is failed
812         var isResponseDone = false;
813
814         // Is 'status' and 'message' set?
815         if ((ajax_content.status == undefined) || (ajax_content.message == undefined)) {
816                 // No status/message set
817                 lastErrorMessage = 'Returned content does not provide &#36;status&#36; or &#36;message&#36; which is required.';
818         } else if ((ajax_content.status != 'done') && (ajax_content.status != 'failed')) {
819                 // This is also not good, only 'failed' or 'done' is supported
820                 lastErrorMessage = ajax_content.message + '<br />\nAdditionally an unknown status ' + ajax_content.status + ' was detected.';
821         } else if (ajax_content.status == 'failed') {
822                 // Something bad went wrong so copy the message
823                 lastErrorMessage = ajax_content.message;
824         } else {
825                 // All fine
826                 isResponseDone = true;
827         }
828
829         // Return status
830         return isResponseDone;
831 }
832
833 // Saves changes by sending the data to the AJAX backend script
834 function saveChanges (prefix) {
835         // Is progress working?
836         if (isElementVisible(prefix, 'progress')) {
837                 // Then exit silently
838                 return;
839         } // END - if
840
841         // Mark all elements as unchanged
842         markAllElementsAsUnchanged();
843
844         // Is there changed elements
845         if (changedElements.length == 0) {
846                 // This should not happen
847                 displayErrorWindow(prefix, '<div class="ajax_error_message">saveChanges() called with no changed elements.</div>');
848         } else if (saveChangesId === null) {
849                 // saveChangesId is not det
850                 displayErrorWindow(prefix, '<div class="ajax_error_message">saveChangesId is not set. Please add <em>saveChanges = \'foo_bar\';</em> to your code.</div>');
851         }
852
853         // Serialize the whole form
854         var serializedData = $('form').serialize();
855
856         // Hold the ready status
857         $.holdReady(true);
858         saveChangesPending = true;
859
860         /*
861          * Send the request to the AJAX backend, it doesn't matter from which page
862          * this was requested.
863          */
864         if (sendAjaxRequest(prefix, 'save_changes', '&tab=' + currentTabId + '&' + serializedData, true) === true) {
865                 // Get the content
866                 var ajax_content = getAjaxContent();
867
868                 // Progress the returned content
869                 if (progressAjaxResponseContent(prefix, ajax_content) === true) {
870                         // Mark all elements as unchanged
871                         markAllElementsAsUnchanged();
872
873                         // Reset form
874                         resetMailerAjaxForm();
875                 } else {
876                         // Is there 'failed_fields' set?
877                         if ((ajax_content.failed_fields != undefined) && (ajax_content.message != undefined)) {
878                                 // Mark all fields as 'failed'
879                                 markFormFieldsFailed(ajax_content.failed_fields);
880
881                                 // Display the error message
882                                 displayErrorWindow(prefix, '<div class="ajax_error_message">' + ajax_content.message + '</div>');
883                         } else {
884                                 // This didn't work, why?
885                                 displayErrorWindow(prefix, '<div class="ajax_error_message">progressAjaxResponseContent() failed, please fix this.<br />\n' + lastErrorMessage + '</div>');
886                         }
887                 }
888
889                 // Saving changes may have worked
890                 saveChangesPending = false;
891         } else {
892                 // Mark all elements as unchanged
893                 markAllElementsAsUnchanged();
894
895                 // Display error message
896                 displayErrorWindow(prefix, getAjaxContent());
897
898                 // Saving changes didn't work
899                 saveChangesPending = false;
900         }
901
902         // Wait for all has finished
903         saveChangesLocked();
904 }
905
906 // Waiting for resources being loaded
907 function saveChangesLocked () {
908         // Has all been loaded?
909         if (saveChangesPending === false) {
910                 // Then release ready()
911                 $.holdReady(false);
912         } else {
913                 // Recursive call again
914                 window.setTimeout('saveChangesLocked()', 10);
915         }
916 }
917
918 // Saves changed settings and continues with given page (next/previous)
919 function doSaveChangesPage (prefix, htmlId, page) {
920         // Save the changes
921         saveChanges(prefix);
922
923         // Close the window
924         //* DEBUG: */ alert('doSaveChangesPage(): prefix=' + prefix + ',htmlId=' + htmlId + ',page=' + page + ' - calling closeWarningWindow()');
925         closeWarningWindow(prefix, true, false);
926
927         // Load requested page
928         doFooterPage(prefix, htmlId, page);
929 }
930
931 // Saves changed settings and continues with given tab
932 function doSaveChangesContinue (prefix, htmlId, tab) {
933         // Is progress working?
934         if (isElementVisible(prefix, 'progress')) {
935                 // Then exit silently
936                 return;
937         } // END - if
938
939         // Save the changes
940         saveChanges(prefix);
941
942         // Close the window
943         //* DEBUG: */ alert('doSaveChangesContinue(): prefix=' + prefix + ',htmlId=' + htmlId + ',tab=' + tab + ' - calling closeWarningWindow()');
944         closeWarningWindow(prefix, true, false);
945
946         // Load requested content
947         requestAjaxContent(prefix, htmlId, tab);
948 }
949
950 // Registers common things (close button, drap&drop)
951 function registerCommons (prefix) {
952         //-----------------------------------------
953         //             Close buttons
954         //-----------------------------------------
955         $('#' + prefix + '_error_close').click(function () {
956                 // Close the window
957                 closeErrorWindow(prefix);
958         });
959
960         $('#' + prefix + '_warning_close').click(function () {
961                 // Close the window
962                 closeWarningWindow(prefix);
963         });
964
965         $('#' + prefix + '_success_close').click(function () {
966                 // Close the window
967                 closeSuccessWindow(prefix);
968         });
969
970         //-----------------------------------------
971         //              Drag'N'Drop
972         //-----------------------------------------
973         $('#' + prefix + '_progress').draggable({
974                 opacity: 0.85
975         });
976
977         $('#' + prefix + '_warning').draggable({
978                 opacity: 0.85
979         });
980
981         $('#' + prefix + '_success').draggable({
982                 opacity: 0.85
983         });
984
985         $('#' + prefix + '_error').draggable({
986                 opacity: 0.85
987         });
988 }
989
990 // Update progress bar
991 function updateProgressBar (maxValue) {
992         // Increment counter
993         counterSuccess++;
994
995         // Do only update <= 100% values
996         if (counterSuccess <= maxValue) {
997                 // Update progress bar
998                 $('#progressbar').progressbar({
999                         value: (counterSuccess / maxValue * 100)
1000                 });
1001         } // END - if
1002 }
1003
1004 // Updates a given "status" field
1005 function updateStatusField (id, cssClass, statusMessage) {
1006         // Set message
1007         $('#' + id).html(statusMessage);
1008
1009         // Is a cssClass set?
1010         if (cssClass != '') {
1011                 // Add it
1012                 $('#' + id).addClass(cssClass);
1013         } else {
1014                 // Remove all classes
1015                 $('#' + id).removeClass();
1016         }
1017 }