diff --git a/public/css/AjaxLib.css b/public/css/AjaxLib.css index 61c9f9234..46711a2d9 100644 --- a/public/css/AjaxLib.css +++ b/public/css/AjaxLib.css @@ -1,4 +1,4 @@ -.veil { +.fhc-ajaxclient-veil { position: absolute; z-index: 9999; top: 0; @@ -11,3 +11,26 @@ background-repeat: no-repeat; background-position: center; } + +.fhc-ajaxclient-error-td { + padding-right: 10px; +} + +.no-close .ui-dialog-titlebar-close { + display: none; +} + +.ui-dialog-buttonset { + padding-top: 10px; + width: 100%; + text-align: center; +} + +.ui-dialog-buttonset button { + width: 50%; + font-weight: bold; +} + +.ui-front { + z-index: 9999; +} diff --git a/public/css/NavigationWidget.css b/public/css/NavigationWidget.css index b6d6c800e..0baaa684a 100644 --- a/public/css/NavigationWidget.css +++ b/public/css/NavigationWidget.css @@ -41,7 +41,6 @@ padding-right: 20px; padding-left: 7px; font-size: 18px; - line-height: 20px; } .navbar-brand-icon { diff --git a/public/js/AjaxLib.js b/public/js/AjaxLib.js index 431d251b6..b47654041 100644 --- a/public/js/AjaxLib.js +++ b/public/js/AjaxLib.js @@ -128,7 +128,7 @@ var FHC_AjaxClient = { * Retrives error message from response object */ getError: function(response) { - var error = 'Generic error'; + var error = "Generic error"; if (jQuery.type(response) == "object" && !jQuery.isEmptyObject(response) && response.hasOwnProperty(RESPONSE)) { @@ -182,13 +182,13 @@ var FHC_AjaxClient = { */ getUrlParameter: function(sParam) { var sPageURL = decodeURIComponent(window.location.search.substring(1)), - sURLVariables = sPageURL.split('&'), + sURLVariables = sPageURL.split("&"), sParameterName, i; for (var i = 0; i < sURLVariables.length; i++) { - sParameterName = sURLVariables[i].split('='); + sParameterName = sURLVariables[i].split("="); if (sParameterName[0] === sParam) { @@ -260,11 +260,81 @@ var FHC_AjaxClient = { FHC_AjaxClient._printDebug(this._data, null, errorThrown); // debug time! - // Call the error callback saved in _errorCallback property - // NOTE: this is not referred to FHC_AjaxClient but to the ajax object + // Call the error callback saved in _errorCallback property + // NOTE: this is not referred to FHC_AjaxClient but to the ajax object this._errorCallback(jqXHR, textStatus, errorThrown); }, + /** + * Method to call after the ajax call has ended + */ + _onComplete: function(jqXHR, textStatus) { + + FHC_AjaxClient._printDebug(this._data, null, jqXHR.responseJSON); // debug time! + + // Call the complete callback if it was saved in the _completeCallback property + // NOTE: this is not referred to FHC_AjaxClient but to the ajax object. + // It's known that it's a function because it was already checked before in the + // _checkAndGenerateAjaxParams method + if (this.hasOwnProperty("_completeCallback")) + { + this._completeCallback(jqXHR, textStatus); + } + + FHC_AjaxClient._hideVeil(); // finally hide the veil + }, + + /** + * If an error callback is not given, this is the default error callback that is used + * to display useful info about the occurred error. It uses the JQuery UI dialog + */ + _defaultErrorCallback: function(jqXHR, textStatus, errorThrown) { + + // Row table format + var tableRowFormat = "%1s: %2s"; + var strDivDialog = "
"; // dialog div and open the error table + + // If textStatus is usable then place it in the table + if (textStatus != null) strDivDialog += tableRowFormat.replace(/%1s/g, "Error").replace(/%2s/g, textStatus); + + // If errorThrown is usable then place it in the table + if (errorThrown != null) strDivDialog += tableRowFormat.replace(/%1s/g, "Error text").replace(/%2s/g, errorThrown); + + // If jqXHR.status is usable then place it in the table + if (jqXHR != null && jqXHR.hasOwnProperty("status")) + { + strDivDialog += tableRowFormat.replace(/%1s/g, "HTTP status").replace(/%2s/g, jqXHR.status); + } + + // If jqXHR.responseText is usable then place it in the table + if (jqXHR != null && jqXHR.hasOwnProperty("responseText")) + { + strDivDialog += tableRowFormat.replace(/%1s/g, "HTTP response").replace(/%2s/g, jqXHR.responseText); + } + + strDivDialog += "
"; // close table and div + + $(strDivDialog).appendTo("body"); // append the dialog div to the body + + // Dialog definition + $("#fhc-ajaxclient-dialog").dialog({ + title: "Error occurred", + dialogClass: "no-close", + autoOpen: true, + modal: true, + resizable: false, + height: "auto", + width: 700, + closeOnEscape: false, + buttons: [{ + text: "Ok", + click: function() { + $(this).dialog("close"); + } + }] + }); + }, + /** * Instantiate a new object and copy in it the properties from the parameter */ @@ -285,7 +355,7 @@ var FHC_AjaxClient = { _showVeil: function() { if (FHC_AjaxClient._veilCallersCounter == 0) { - $("
").appendTo('body'); + $("
").appendTo("body"); } FHC_AjaxClient._veilCallersCounter++; @@ -305,7 +375,7 @@ var FHC_AjaxClient = { if (FHC_AjaxClient._veilCallersCounter == 0) { - $(".veil").remove(); + $(".fhc-ajaxclient-veil").remove(); } } }, @@ -388,6 +458,11 @@ var FHC_AjaxClient = { valid = false; } } + else // if is not given then call the default errorCallback + { + ajaxParameters._errorCallback = FHC_AjaxClient._defaultErrorCallback; // save as property the callback error + ajaxParameters.error = FHC_AjaxClient._onError; // function to call if an error occurred + } // If present, successCallback must be a function if (ajaxCallParameters.hasOwnProperty("successCallback")) @@ -404,14 +479,27 @@ var FHC_AjaxClient = { } } - // If present, veilTimeout must be a number and cannot be less then 0 or greater then 60000 - if (ajaxCallParameters.hasOwnProperty("veilTimeout") && typeof ajaxCallParameters.veilTimeout == "number") + // If present, completeCallback must be a function + if (ajaxCallParameters.hasOwnProperty("completeCallback")) { + if (typeof ajaxCallParameters.completeCallback == "function") + { + ajaxParameters._completeCallback = ajaxCallParameters.completeCallback; // save as property the callback complete + } + else + { + console.error("Invalid completeCallback, it must be a function"); + valid = false; + } + } + + // If present, veilTimeout must be a number and cannot be less then 0 or greater then 60000 + if (ajaxCallParameters.hasOwnProperty("veilTimeout") && typeof ajaxCallParameters.veilTimeout == "number") + { if (ajaxCallParameters.veilTimeout > 0 && ajaxCallParameters.veilTimeout < 60000) { ajaxParameters._veilTimeout = ajaxCallParameters.veilTimeout; ajaxParameters.beforeSend = FHC_AjaxClient._showVeil; - ajaxParameters.complete = FHC_AjaxClient._hideVeil; } else if(ajaxCallParameters.veilTimeout == 0) { @@ -422,13 +510,15 @@ var FHC_AjaxClient = { console.error("Invalid veilTimeout parameter, must be a number >= 0 and <= 60000"); valid = false; } - } + } else // is not present or the value is invalid { ajaxParameters._veilTimeout = VEIL_TIMEOUT; ajaxParameters.beforeSend = FHC_AjaxClient._showVeil; - ajaxParameters.complete = FHC_AjaxClient._hideVeil; } + + // Function to call after the ajax call is ended, is it here because it must be always called + ajaxParameters.complete = FHC_AjaxClient._onComplete; } if (valid === false) diff --git a/public/js/NavigationWidget.js b/public/js/NavigationWidget.js index ee9adb83d..4e388db23 100644 --- a/public/js/NavigationWidget.js +++ b/public/js/NavigationWidget.js @@ -32,7 +32,7 @@ var FHC_NavigationWidget = { if (FHC_AjaxClient.hasData(data)) { - var strHeaderMenu = ''; + var strHeaderMenu = ""; jQuery.each(FHC_AjaxClient.getData(data), function(i, e) { if (e != null) strHeaderMenu += FHC_NavigationWidget._buildHeaderMenuStructure(e); @@ -63,7 +63,7 @@ var FHC_NavigationWidget = { { FHC_NavigationWidget._printCollapseIcon(); // Applies bootstrap SB Admin 2 theme elements to the left menu - var strLeftMenu = ''; + var strLeftMenu = ""; // Builds left menu jQuery.each(FHC_AjaxClient.getData(data), function(i, e) { @@ -140,17 +140,49 @@ var FHC_NavigationWidget = { */ _buildHeaderMenuStructure: function(item) { - var strHeaderMenu = ''; + var strHeaderMenu = ""; - if (item['icon'] != 'undefined' && item['icon'] != '') + if (item["icon"] != "undefined" && item["icon"] != "") { - strHeaderMenu += ''; + strHeaderMenu += ''; } - var target = ''; - if (item['target'] != null) target = item['target']; + if (item["children"] != null && Object.keys(item["children"]).length > 0) + { + strHeaderMenu += '' + item['description'] + ''; + var target = ""; + if (item["target"] != null) target = item["target"]; + + if (item["children"] != null && Object.keys(item["children"]).length > 0) + { + strHeaderMenu += item["description"] + " "; + strHeaderMenu += ''; + strHeaderMenu += ''; + } + else + { + strHeaderMenu += '' + item["description"] + ''; + } return strHeaderMenu; }, @@ -161,45 +193,45 @@ var FHC_NavigationWidget = { _buildLeftMenuStructure: function(item, depth = 1) { strLeftMenu = ""; - var expanded = item['expand'] != null && item['expand'] === true ? ' active' : ''; + var expanded = item["expand"] != null && item["expand"] === true ? ' active' : ""; strLeftMenu += '
  • '; - if (item['subscriptLinkClass'] != null && item['subscriptDescription'] != null) + if (item["subscriptLinkClass"] != null && item["subscriptDescription"] != null) { strLeftMenu += ''; } - var target = ''; - if (item['target'] != null) target = item['target']; + var target = ""; + if (item["target"] != null) target = item["target"]; - strLeftMenu += ''; + strLeftMenu += ''; - if (item['icon'] != 'undefined') + if (item["icon"] != "undefined") { - strLeftMenu += ' '; + strLeftMenu += ' '; } - strLeftMenu += item['description']; + strLeftMenu += item["description"]; - if (item['children'] != null && Object.keys(item['children']).length > 0) + if (item["children"] != null && Object.keys(item["children"]).length > 0) { strLeftMenu += ''; } strLeftMenu += ''; - if (item['subscriptLinkClass'] != null && item['subscriptDescription'] != null) + if (item["subscriptLinkClass"] != null && item["subscriptDescription"] != null) { - strLeftMenu += '' + - ' (' + item['subscriptDescription'] + ')' + + strLeftMenu += '' + + ' (' + item["subscriptDescription"] + ')' + ''; strLeftMenu += ''; } - if (item['children'] != null && Object.keys(item['children']).length > 0) + if (item["children"] != null && Object.keys(item["children"]).length > 0) { - var level = ''; + var level = ""; if (depth === 1) { level = 'second'; @@ -211,7 +243,7 @@ var FHC_NavigationWidget = { strLeftMenu += '