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 += '';
+ }
- 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 += '';
}
- 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 += '';
- jQuery.each(item['children'], function(i, e) {
+ jQuery.each(item["children"], function(i, e) {
if (e != null) strLeftMenu += FHC_NavigationWidget._buildLeftMenuStructure(e, ++depth);
});
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;
}
};