X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=js%2Fajax-common.js;fp=js%2Fajax-common.js;h=01c56a9febc6df85b6fdd0c099e5828c71a046af;hb=63f159414369b5ea19a8ca75d8cd8033c45d8341;hp=0000000000000000000000000000000000000000;hpb=a454def0bfba8288ffc839d034c710f034cf4728;p=mailer.git diff --git a/js/ajax-common.js b/js/ajax-common.js new file mode 100644 index 0000000000..01c56a9feb --- /dev/null +++ b/js/ajax-common.js @@ -0,0 +1,693 @@ +/** + * Common JavaScript functions for AJAX requests (they are general purpose). + * -------------------------------------------------------------------- + * $Revision:: $ + * $Date:: $ + * $Tag:: 0.2.1-FINAL $ + * $Author:: $ + * -------------------------------------------------------------------- + * Copyright (c) 2003 - 2009 by Roland Haeder + * Copyright (c) 2009 - 2012 by Mailer Developer Team + * For more information visit: http://mxchange.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +// Init variables +var currentTabId = null; +var errorDisplayed = false; +var warningDisplayed = false; +var defaultTabId = null; +var footerElements = new Array(); +var changedElements = new Array(); +var formChanged = false; +var saveChangesId = null; +var lastErrorMessage = null; +var saveChangesPending = false; + +// Add all footer navigation elements +footerElements[0] = 'next'; +footerElements[1] = 'previous'; + +// Setter for current tab id +function setCurrentTabId (tabId) { + // Set it + //* DEBUG: */ alert('currentTabId=' + currentTabId + ',tabId=' + tabId); + currentTabId = tabId; +} + +// Marks a tab navigation entry +function markTabNavigation (prefix, tab) { + // Get all li-tags + var li = document.getElementsByTagName('li'); + + // Set current tab name + var currentTabName = 'tab_enabled'; + + // Set tab name + var tabName = prefix + '_' + tab; + + // Search for all menus + for (var i = 0; i < li.length; i++) { + // Debug message + //* DEBUG: */ document.write('className=' + li[i].className + ',prefix=' + prefix + ',tab=' + tab + '
'); + + // Check for valid tab + if (li[i].className.substr(0, currentTabName.length) == currentTabName) { + // Okay does match (don't change any others) + if (li[i].id == tabName) { + // Mark this menu + $('li#' + tabName).addClass('tab_active'); + //li[i].className += ' tab_active'; + } else { + // Unmark this menu + $('li#' + li[i].id).removeClass('tab_active'); + //li[i].className = currentTabName; + } + } // END - if + } // END - for +} + +// Enables a given element +function enableElement (element) { + // Remove class and attribute + $(element).removeClass('disabled'); + $(element).removeAttr('disabled'); +} + +// Disables a given element +function disableElement (element) { + // Add class and attribute + $(element).addClass('disabled'); + $(element).attr('disabled', 'disabled'); + + // Blur the element + $(element).blur(); +} + +// Enables a given footer navigation element +function enableFooterNavigationPage (element) { + // Remove the 'disabled' class and attribute + enableElement('input#' + element + '_page'); +} + +// Resets footer navigation by adding CSS class 'disabled' +function resetFooterNavigation () { + // Remove the 'disabled' class and attribute + for (var i = 0; i < footerElements.length; i++) { + $('input#' + footerElements[i] + '_page').addClass('disabled'); + $('input#' + footerElements[i] + '_page').attr('disabled', 'disabled'); + $('input#' + footerElements[i] + '_page').blur(); + } // END - for +} + +// Getter for AJAX content +function getAjaxContent () { + // Is it defined? + if ($('body').data('ajax_content') == undefined) { + // Not set + throw new 'ajax_content requested but not set.'; + } // END - if + + // Return it + return $('body').data('ajax_content'); +} + +// "Setter" for AJAX content but does decode the content +function setAjaxDecodedContent (ajax_content) { + // Decode URL-encoded data ... + var decoded = decodeUrlEncoding(ajax_content); + + // ... and set it + setAjaxContent(decoded); +} + +// Setter for AJAX content +function setAjaxContent (ajax_content) { + $('body').data('ajax_content', ajax_content); +} + +// Getter for AJAX success +function getAjaxSuccess () { + return $('body').data('ajax_success'); +} + +// Setter for AJAX success +function setAjaxSuccess (success) { + $('body').data('ajax_success', success); +} + +// Set AJAX reply and decode JSON if requested +function setAjaxReply (reply, isJson) { + // Copy reply to local variable + var localReply = reply; + + // Is it JSON URL-encoded content? + if ((isJson != undefined) && (isJson == true)) { + // Then decode it, replace '%20' with space before because '%20' breakes JSON content + var obj = jQuery.parseJSON(reply.replace('%20', ' ')); + + // Is reply_content there + if (obj.reply_content == undefined) { + // Not defined + throw new 'obj.reply_content not returned from ajax.php, please fix your scripts.'; + } // END - if + + // ... and set it + setAjaxDecodedContent(obj.reply_content); + } else { + // Handle the content over to decode it + setAjaxDecodedContent(localReply); + } +} + +// Sends out an AJAX request +function sendAjaxRequest (level, doValue, extra, isJson) { + // By default all requests failed + setAjaxSuccess(false); + + // Reset AJAX content + setAjaxContent(''); + + // Send out the raw request + $.ajax({ + url: 'ajax.php', + type: 'POST', + data: 'level=' + level + '&do=' + doValue + extra, + dataType: 'json', + async: false, + + // Called on success + success: function (ajax_content) { + // Is ajax_content set? + if (ajax_content.responseText == undefined) { + // This shall not happen + throw new 'ajax_content.responseText not returned from ajax.php, please fix your scripts.'; + } else if (ajax_content.responseText == null) { + // This shall not happen, too + throw new 'ajax_content.responseText=null from ajax.php, please fix your scripts.'; + } + + // Set AJAX reply + setAjaxReply(ajax_content.responseText, isJson); + + // Mark it as success + setAjaxSuccess(true); + }, + + // Called in case of an error (e.g. HTTP response status not '200 OK') + error: function (ajax_content) { + // Is ajax_content set? + if (ajax_content.responseText == undefined) { + // This shall not happen + throw new 'ajax_content.responseText not returned from ajax.php, please fix your scripts.'; + } else if (ajax_content.responseText == null) { + // This shall not happen, too + throw new 'ajax_content.responseText=null from ajax.php, please fix your scripts.'; + } + + // Set AJAX reply + setAjaxReply(ajax_content.responseText, isJson); + } + }); + + // Return status + return getAjaxSuccess(); +} + +// Enables footer navigation buttons +function enableFooterNavigation (prefix, tabId) { + // Reset both footer navigation first + resetFooterNavigation(); + + // Do the AJAX request (JSON as content is enabled) + if (sendAjaxRequest(prefix, 'footer_navigation', '&tab=' + tabId, true) == true) { + // Parse the content + $.each(getAjaxContent(), function (i, value) { + // Enable current element + enableFooterNavigationPage(value); + }); + } else { + // Display error window + displayErrorWindow(prefix, getAjaxContent()); + } +} + +// Requests an AJAX content +function requestAjaxContent (prefix, htmlId, tabId, footerNavigation) { + // Check if this request is disabled + if ($('#' + prefix + '_' + tabId).hasClass('tab_disabled')) { + // Clicked on a disabled tabId so blur it + //* DEBUG: */ alert('requestAjaxContent(): prefix=' + prefix + ',htmlId=' + htmlId + ',tabId=' + tabId + ' - DISABLED!'); + return; + } else if (formChanged == true) { + // Has changed form , so output message to browser + //* DEBUG: */ alert('requestAjaxContent(): prefix=' + prefix + ',htmlId=' + htmlId + ',tabId=' + tabId + ' - FORM CHANGED!'); + displayChangedWarningWindow(prefix, tabId); + + // Abort here + return; + } + + // Only request if content is different + //* DEBUG: */ alert('requestAjaxContent(): prefix=' + prefix + ',htmlId=' + htmlId + ',tabId=' + tabId + ',currentTabId=' + currentTabId); + if (tabId != currentTabId) { + // Set tabId as current + //* DEBUG: */ alert('requestAjaxContent(): prefix=' + prefix + ',htmlId=' + htmlId + ',tabId=' + tabId + ' - Calling setCurrentTabId()'); + setCurrentTabId(tabId); + + // Fade the old content out + $('#' + htmlId).fadeOut('fast', function() { + // Send AJAX request + if (sendAjaxRequest(prefix, 'request_content', '&tab=' + tabId, true) == true) { + // Add the HTML content + $('#' + htmlId).html(getAjaxContent()); + + // Fade the content in + $('#' + htmlId).fadeIn('fast', function() { + // This differs, so mark the menu and request content + markTabNavigation(prefix, tabId); + + // Is the footer navigation enabled? + if (footerNavigation == true) { + // Change footer navigation as well + enableFooterNavigation(prefix, tabId); + } // END - if + }); + } else { + // Display error window + displayErrorWindow(prefix, getAjaxContent()); + } + }); + } else { + // Same id + //* DEBUG: */ alert('SAME!'); + } +} + +// Displays a test window +function displayTestWindow (prefix, element) { + // Register click-event for error window + $('#' + prefix + '_error_close').click(function () { + // Close the window + closeErrorWindow(prefix); + }); + + // Register click-event for warning window + $('#' + prefix + '_warning_close').click(function () { + // Close the window + //* DEBUG: */ alert('displayTestWindow(): prefix=' + prefix + ' - calling closeWarningWindow()'); + closeWarningWindow(prefix); + }); + + // Request it from the AJAX backend + if (sendAjaxRequest(prefix, 'test', '') == true) { + // Transfer the returned content to the prefix_warning_content id + $('#' + prefix + '_warning_content').html(getAjaxContent()); + + // Fade the warning in + $('#' + prefix + '_warning').fadeIn('slow', function() { + // Enable element + enableElement(element); + }); + + // Mark 'warning' as displayed + warningDisplayed = true; + } else { + // Display error message + displayErrorWindow(prefix, getAjaxContent()); + } +} + +// Displays a warning window above the form to warn about changed&unsafed fields +function displayChangedWarningWindow (prefix, button) { + // Fade out warning window, if open + //* DEBUG: */ alert('displayChangedWarningWindow(): prefix=' + prefix + ',button=' + button + ' - calling closeWarningWindow()'); + closeWarningWindow(prefix); + + // Fade error out for eye-candy, if open + closeErrorWindow(prefix); + + // Abort here if warningDisplayed is still true + if (warningDisplayed == true) { + // Make sure this doesn't happen + return; + } // END - if + + // Request it from the AJAX backend + if (sendAjaxRequest(prefix, 'change_warning', '&button=' + button + '&elements=' + changedElements.join(':')) == true) { + // Transfer the returned content to the prefix_warning_content id + $('#' + prefix + '_warning_content').html(getAjaxContent()); + + // Fade the warning in + $('#' + prefix + '_warning').fadeIn('slow', function() { + // Mark warning as displayed + warningDisplayed = true; + }); + } else { + // Display error message + displayErrorWindow(prefix, getAjaxContent()); + } +} + +// Displays the error window for given prefix and content +function displayErrorWindow (prefix, ajax_content) { + // Fade out warning window, if open + //* DEBUG: */ alert('displayErrorWindow(): prefix=' + prefix + ' - calling closeWarningWindow()'); + closeWarningWindow(prefix); + + // Fade it out for eye-candy + closeErrorWindow(prefix); + + // Abort here if errorDisplayed is still true + if (errorDisplayed == true) { + // Make sure this doesn't happen + return; + } // END - if + + // Copy the response text to the error variable + if (ajax_content.responseText != undefined) { + $('#' + prefix + '_error_content').html(ajax_content.responseText); + } else { + $('#' + prefix + '_error_content').html(ajax_content); + } + + // Fade the error in + $('#' + prefix + '_error').fadeIn('slow', function() { + // Mark error as displayed + errorDisplayed = true; + }); +} + +// Waits until the window has been closed +function closeErrorLocked () { + // Has all been loaded? + if (errorDisplayed == false) { + // Then release ready() + $.holdReady(false); + } else { + // Recursive call again + window.setTimeout('closeErrorLocked()', 10); + } +} + +// Closes an error window +function closeErrorWindow (prefix, waitClose, resetCurrentTabId) { + // Is the error displayed? + if (errorDisplayed == true) { + // Shall we wait ("sync") until the animation has completed? + if (waitClose == true) { + // Hold the ready status + $.holdReady(true); + } // END - if + + // Yes, then fade it out + $('#' + prefix + '_error').fadeOut('fast', function() { + // Set current tab id to default + if (resetCurrentTabId == true) { + setCurrentTabId(defaultTabId); + } // END - if + + // Mark it as closed + errorDisplayed = false; + }); + + // Shall this animation be "synchronized"? + if (waitClose == true) { + // Wait for the window has been closed + closeErrorLocked(); + } // END - if + } // END - if +} + +// Waits until the window has been closed +function closeWarningLocked () { + // Has all been loaded? + if (warningDisplayed == false) { + // Then release ready() + $.holdReady(false); + } else { + // Recursive call again + window.setTimeout('closeWarningLocked()', 10); + } +} + +// Closes an warning window +function closeWarningWindow (prefix, waitClose, resetCurrentTabId) { + //* DEBUG: */ alert('prefix=' + prefix + ',waitClose=' + waitClose + ' - ENTERED!'); + // Is the warning displayed? + if (warningDisplayed == true) { + // Shall we wait ("sync") until the animation has completed? + //* DEBUG: */ alert('prefix=' + prefix + ',waitClose=' + waitClose + ',warningDisplayed=true'); + if (waitClose == true) { + // Hold the ready status + $.holdReady(true); + } // END - if + + // Yes, then fade it out + $('#' + prefix + '_warning').fadeOut('fast', function() { + // Set current tab id to default + //* DEBUG: */ alert('closeWarningWindow(): prefix=' + prefix + ',waitClose=' + waitClose + ',defaultTab=' + defaultTabId + ' - Calling setCurrentTabId()'); + if (resetCurrentTabId == true) { + setCurrentTabId(defaultTabId); + } // END - if + + // Mark it as closed + warningDisplayed = false; + //* DEBUG: */ alert('closeWarningWindow(): waitClose=' + waitClose + ',resetCurrentTabId=' + resetCurrentTabId + ',warningDisplayed=false'); + }); + + // Shall this animation be "synchronized"? + if (waitClose == true) { + // Wait for the window has been closed + //* DEBUG: */ alert('prefix=' + prefix + ',waitClose=' + waitClose + ' - LOCKED!'); + closeWarningLocked(); + } // END - if + } // END - if +} + +// A footer navigation button has been clicked +function doFooterPage (prefix, htmlId, button) { + //* DEBUG: */ alert('doFooterPage(): prefix=' + prefix + ',htmlId=' + htmlId + ',button=' + button + ' - ENTERED!'); + // Has something being changed? + if (formChanged == true) { + // Output message to browser + displayChangedWarningWindow(prefix, button); + + // Abort here + return; + } // END - if + + // Do we have a 'next' entry? + //* DEBUG: */ alert('doFooterPage(): button=' + button + ',currentTabId=' + currentTabId + ',nextPage[currentTabId]=' + nextPage[currentTabId]); + if ((button == 'next') && (nextPage[currentTabId] != null)) { + // Then call the AJAX requester + requestAjaxContent(prefix, htmlId, nextPage[currentTabId]); + } else if ((button == 'previous') && (previousPage[currentTabId] != null)) { + // Then call the AJAX requester + requestAjaxContent(prefix, htmlId, previousPage[currentTabId]); + } +} + +// Allows to save made changes (this will be called if the onchange event has been triggered) +function allowSaveChanges (element) { + // Mark element as changed, unmark as failed + $('#' + element).addClass('field_changed'); + $('#' + element).removeClass('field_failed'); + + // Is the element not there? + if (!in_array(element, changedElements)) { + // Mark the form as changed + formChanged = true; + + // Make the 'Save changes' button clickable + enableElement('#' + saveChangesId); + + // Remember this for later AJAX call + changedElements.push(element); + } // END - if +} + +// Marks all elements as unchanged/not failed +function markAllElementsAsUnchanged () { + // Remove status from all fields + for (var i = 0; i < changedElements.length; i++) { + // Mark the element as changed + $('#' + changedElements[i]).removeClass('field_changed'); + $('#' + changedElements[i]).removeClass('field_failed'); + } // END - for +} + +// Function to reset the form +function resetMailerAjaxForm () { + // Debug message + //* DEBUG: */ alert('resetMailerAjaxForm(): changedElements()=' + changedElements.length + ',saveChangesId=' + saveChangesId + ' - ENTERED!'); + + // Mark all elements as unchanged + markAllElementsAsUnchanged(); + + // Clear all changed elements + disableElement('input#' + saveChangesId); + + // Reset changed elements and mark form as not changed + changedElements = new Array(); + formChanged = false; +} + +// Mark given fields as failed +function markFormFieldsFailed (failedFields) { + // Mark all elements as failed + $.each(failedFields, function (i, field) { + // Mark the element as 'failed' + $('#' + field).removeClass('field_changed'); + $('#' + field).addClass('field_failed'); + + // Also register it as 'changed', if not found + if (!in_array(field, changedElements)) { + // Okay, not yet added, so push it on the array + changedElements.push(field); + } // END - if + }); +} + +// Processes the content from AJAX call +function processAjaxResponseContent (prefix, ajax_content) { + // By default all is failed + var isResponseDone = false; + + // Is 'status' and 'message' set? + if ((ajax_content.status == undefined) || (ajax_content.message == undefined)) { + // No status/message set + lastErrorMessage = 'Returned content does not provide $status$ or $message$ which is required.'; + } else if ((ajax_content.status != 'done') && (ajax_content.status != 'failed')) { + // This is also not good, only 'failed' or 'done' is supported + lastErrorMessage = ajax_content.message + '
\nAdditionally an unknown status ' + ajax_content.status + ' was detected.'; + } else if (ajax_content.status == 'failed') { + // Something bad went wrong so copy the message + lastErrorMessage = ajax_content.message; + } else { + // All fine + isResponseDone = true; + } + + // Return status + return isResponseDone; +} + +// Saves changes by sending the data to the AJAX backend script +function saveChanges (prefix) { + // Mark all elements as unchanged + markAllElementsAsUnchanged(); + + // Do we have changed elements + if (changedElements.length == 0) { + // This should not happen + displayErrorWindow(prefix, '
saveChanges() called with no changed elements.
'); + } else if (saveChangesId == null) { + // saveChangesId is not det + displayErrorWindow(prefix, '
saveChangesId is not set. Please add saveChanges = \'foo_bar\'; to your code.
'); + } + + // Serialize the whole form + var serializedData = $('form').serialize(); + + // Hold the ready status + $.holdReady(true); + saveChangesPending = true; + + /* + * Send the request to the AJAX backend, it doesn't matter from which page + * this was requested. + */ + if (sendAjaxRequest(prefix, 'save_changes', '&tab=' + currentTabId + '&' + serializedData, true) == true) { + // Get the content + var ajax_content = getAjaxContent(); + + // Process the returned content + if (processAjaxResponseContent(prefix, ajax_content) == true) { + // Mark all elements as unchanged + markAllElementsAsUnchanged(); + + // Reset form + resetMailerAjaxForm(); + } else { + // Do we have 'failed_fields' set? + if ((ajax_content.failed_fields != undefined) && (ajax_content.message != undefined)) { + // Mark all fields as 'failed' + markFormFieldsFailed(ajax_content.failed_fields); + + // Display the error message + displayErrorWindow(prefix, '
' + ajax_content.message + '
'); + } else { + // This didn't work, why? + displayErrorWindow(prefix, '
processAjaxResponseContent() failed, please fix this.
\n' + lastErrorMessage + '
'); + } + } + + // Saving changes may have worked + saveChangesPending = false; + } else { + // Mark all elements as unchanged + markAllElementsAsUnchanged(); + + // Display error message + displayErrorWindow(prefix, getAjaxContent()); + + // Saving changes didn't work + saveChangesPending = false; + } + + // Wait for all has finished + saveChangesLocked(); +} + +// Waiting for resources being loaded +function saveChangesLocked () { + // Has all been loaded? + if (saveChangesPending == false) { + // Then release ready() + $.holdReady(false); + } else { + // Recursive call again + window.setTimeout('saveChangesLocked()', 10); + } +} + +// Saves changed settings and continues with given page (next/previous) +function doSaveChangesPage (prefix, htmlId, page) { + // Save the changes + saveChanges(prefix); + + // Close the window + //* DEBUG: */ alert('doSaveChangesPage(): prefix=' + prefix + ',htmlId=' + htmlId + ',page=' + page + ' - calling closeWarningWindow()'); + closeWarningWindow(prefix, true, false); + + // Load requested page + doFooterPage(prefix, htmlId, page); +} + +// Saves changed settings and continues with given tab +function doSaveChangesContinue (prefix, htmlId, tab) { + // Save the changes + saveChanges(prefix); + + // Close the window + //* DEBUG: */ alert('doSaveChangesPage(): prefix=' + prefix + ',htmlId=' + htmlId + ',tab=' + tab + ' - calling closeWarningWindow()'); + closeWarningWindow(prefix, true, false); + + // Load requested content + requestAjaxContent(prefix, htmlId, tab); +}