From c6f1b7beca54b0ad2a9555c9281012f91be75e06 Mon Sep 17 00:00:00 2001 From: Paolo Date: Thu, 5 Jul 2018 17:14:29 +0200 Subject: [PATCH 1/4] 't' method of FHC_PhrasesLib now replace '{}' with '' --- public/js/PhrasesLib.js | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/public/js/PhrasesLib.js b/public/js/PhrasesLib.js index d8c67d4f8..64b10759d 100644 --- a/public/js/PhrasesLib.js +++ b/public/js/PhrasesLib.js @@ -19,12 +19,13 @@ var FHC_PhrasesLib = { /** * Returns the phrase-text in the user's language + * NOTE: the parameter params is an object since associative arrays are NOT supported in JS * @param {String} category : phrase-category * @param {String} phrase : phrase-name - * @param {array} params : String-parameters to be set in variables in phrasentext + * @param {Object} params : parameters to be replaced instead of {} in phraseObj.text * @returns {String} : phrase-text */ - t: function (category, phrase, params = []) { + t: function(category, phrase, params = {}) { // Checks if FHC_JS_PHRASES_STORAGE_OBJECT is an array if ($.isArray(FHC_JS_PHRASES_STORAGE_OBJECT)) @@ -41,11 +42,11 @@ var FHC_PhrasesLib = { && phraseObj.text.trim() != '') { // If params is null or not an array - if (params == null || (params != null && !$.isArray(params))) + if (params == null) { - params = []; + params = {}; } - + return FHC_PhrasesLib._replacePhraseVariable(phraseObj.text, params); // parsing } } @@ -59,15 +60,21 @@ var FHC_PhrasesLib = { /** * Returns phrase with variables being replaced + * NOTE: params is an object but here is treat as an associative array, not that much orthodox but it works fine ;) * @param {String} phrase : phrasen-text (with one ore more variables) - * @param {array} replaceStringArr : String-array to be set in variables in phrasentext (order matters) + * @param {Object} params : parameters to be replaced instead of {} in phrase * @returns {String} : replaced phrasen-text */ - _replacePhraseVariable: function (phrase, replaceStringArr) { - for (var i = 0; i < replaceStringArr.length; i++) + _replacePhraseVariable: function(phrase, params) { + + // Loops + for (var paramName in params) { - phrase = phrase.replace(/\{(.*?)\}/, replaceStringArr[i]); + var paramValue = params[paramName]; + + phrase = phrase.replace('{' + paramName + '}', paramValue); } + return phrase; } }; From 6791f58cb2b79ca9dae65acf4aa88e06537e65cf Mon Sep 17 00:00:00 2001 From: Paolo Date: Fri, 6 Jul 2018 13:30:19 +0200 Subject: [PATCH 2/4] - Renamed the class veil to fhc-ajaxclient-veil in AjaxLib.css - Added new classes to AjaxLib.css to configure the new error dialog box - Adapted AjaxLib.js to use the class fhc-ajaxclient-veil - Added a new private method _defaultErrorCallback to AjaxLib.js - Now if an errorCallback function is not given when AjaxLib.js is used, then _defaultErrorCallback is used as fallback --- public/css/AjaxLib.css | 25 +++++++++++++++- public/js/AjaxLib.js | 66 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 85 insertions(+), 6 deletions(-) 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/js/AjaxLib.js b/public/js/AjaxLib.js index bd2b22689..ae5edbc5b 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 (i = 0; i < sURLVariables.length; i++) { - sParameterName = sURLVariables[i].split('='); + sParameterName = sURLVariables[i].split("="); if (sParameterName[0] === sParam) { @@ -265,6 +265,57 @@ var FHC_AjaxClient = { this._errorCallback(jqXHR, textStatus, errorThrown); }, + /** + * 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 +336,7 @@ var FHC_AjaxClient = { _showVeil: function() { if (FHC_AjaxClient._veilCallersCounter == 0) { - $("
").appendTo('body'); + $("
").appendTo("body"); } FHC_AjaxClient._veilCallersCounter++; @@ -305,7 +356,7 @@ var FHC_AjaxClient = { if (FHC_AjaxClient._veilCallersCounter == 0) { - $(".veil").remove(); + $(".fhc-ajaxclient-veil").remove(); } } }, @@ -388,6 +439,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")) From 4a29c03c399407b02e6fd1f5497e83d738a067bf Mon Sep 17 00:00:00 2001 From: Paolo Date: Mon, 9 Jul 2018 11:24:01 +0200 Subject: [PATCH 3/4] - Added private _onComplete method to AjaxLib that calls the eventually given completeCallback and hides the veil - Changed method _checkAndGenerateAjaxParams to add the possibility to give a completeCallback function as parameter of the Ajax call --- public/js/AjaxLib.js | 48 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/public/js/AjaxLib.js b/public/js/AjaxLib.js index ae5edbc5b..0759f1f60 100644 --- a/public/js/AjaxLib.js +++ b/public/js/AjaxLib.js @@ -260,11 +260,30 @@ 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 @@ -460,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) { @@ -478,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) From 5b1d801a325a8df07c1c9772da959c3fc20b2be9 Mon Sep 17 00:00:00 2001 From: Paolo Date: Mon, 9 Jul 2018 12:15:19 +0200 Subject: [PATCH 4/4] NavigationWidget: implemented drop down menu in the header menu --- public/css/NavigationWidget.css | 1 - public/js/NavigationWidget.js | 78 +++++++++++++++++++++++---------- 2 files changed, 55 insertions(+), 24 deletions(-) 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/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 += '