// ----------------------------------------------------------------
// EwCore
// ----------------------------------------------------------------
var EwCore = new function () {
var self = this;
this.lang = "";
this.applicationPath = "/";
this.getEwUrl = function (ewAppUrl) {
return this.applicationPath + ewAppUrl;
};
this.ajaxContentAdded = function (element) {
$(element).ajaxFormParse();
};
var ajaxUrlInternal = function (ajaxItemPath, command, addUniqueId) {
var url = self.getEwUrl("ew/ajax/" + command + "?path=" + EwUtils.urlEncode(ajaxItemPath.replace("\\", "/")));
if (addUniqueId) {
var uniqueId = EwCore.newUniqueId("ajax");
url += "&uniqueId=" + EwUtils.urlEncode(uniqueId);
}
return url;
};
this.ajaxUrlGet = function (ajaxItemPath, model) {
var requestData = this.createDataRequestBasic();
if (model != undefined) {
$.extend(requestData, { model: model });
}
var requestDataParam = JSON.stringify(requestData);
return ajaxUrlInternal(ajaxItemPath, "get", true) + "&data=" + EwUtils.urlEncode(requestDataParam);
};
this.createDataRequestBasic = function () {
var ret = {
lang: self.lang,
masterTemplateName: self.masterTemplateName
};
if (self.templateContextGuid != undefined) {
ret.templateContextGuid = self.templateContextGuid;
}
return ret;
};
var ajaxBaseCall = function (url, optsInternal, opts) {
var requestData = self.createDataRequestBasic();
if (opts != undefined && opts.model != undefined) {
$.extend(requestData, { model: opts.model });
}
if (optsInternal.requestExt != undefined) {
$.extend(requestData, optsInternal.requestExt);
}
var ajaxParams = {
type: 'POST',
cache: false,
url: url,
dataType: optsInternal.dataType,
contentType: 'application/json',
data: JSON.stringify(requestData),
success: optsInternal.success,
complete: function (xhr) {
var location = xhr.getResponseHeader("Location");
if (location) {
window.location = location;
}
}
};
if (opts != undefined) {
$.extend(ajaxParams, {
error: opts.error,
async: opts.async
});
}
$.ajax(ajaxParams);
};
this.ajaxLoad = function (ajaxItemPath, opts) {
var ajaxCallSuccess = function (htmlContent) {
if (opts != undefined && opts.success != undefined) {
opts.success(htmlContent);
}
if (opts != undefined && opts.targetId != undefined) {
var $target = $("#" + opts.targetId);
$target.html(htmlContent);
self.ajaxContentAdded($target[0]);
}
};
var url = ajaxUrlInternal(ajaxItemPath, "post", true);
ajaxBaseCall(url, { success: ajaxCallSuccess, dataType: "html" }, opts);
};
this.ajaxAction = function (ajaxItemPath, actionName, actionData, opts) {
var ajaxCallSuccess = function (responseData) {
var htmlContent = responseData.htmlContent;
if (opts != undefined && opts.success != undefined) {
opts.success(htmlContent, responseData);
}
if (opts != undefined && opts.targetId != undefined) {
var $target = $("#" + opts.targetId);
$target.html(htmlContent);
self.ajaxContentAdded($target[0]);
}
self.processAjaxControlActionResponse(responseData);
};
var url = ajaxUrlInternal(ajaxItemPath, "action", false);
ajaxBaseCall(url, { requestExt: { actionName: actionName, actionData: actionData }, success: ajaxCallSuccess, dataType: "json" }, opts);
};
this.ajaxData = function (ajaxItemPath, methodName, methodData, opts) {
var ajaxCallSuccess = function (data) {
if (opts != undefined && opts.success != undefined) {
opts.success(data);
}
};
var url = ajaxUrlInternal(ajaxItemPath, "data");
ajaxBaseCall(url, { requestExt: { methodName: methodName, methodData: methodData }, success: ajaxCallSuccess, dataType: "json" }, opts);
};
// todo:
/*
this.ajaxPostBackAction = function (actionName, actionData, opts) {
};
this.ajaxPageData = function (methodName, methodData, opts) {
};
*/
this.ajaxLoadError = undefined;
this.processAjaxControlActionResponse = function (responseData) {
if (responseData.resultErrorMessages != undefined) {
var message = "";
for (var i = 0; i < responseData.resultErrorMessages.length; i++) {
var mes = responseData.resultErrorMessages[i];
if (mes != "") {
if (message != "") {
message += "
";
}
message += "" + mes + "";
}
}
EwDialogs.userMessage(message);
}
if (responseData.resultJavaScriptCode != undefined) {
var caller = function () { eval(responseData.resultJavaScriptCode); };
caller.call(responseData);
}
if (responseData.actionResultRedirectToUrl != undefined) {
window.location = responseData.actionResultRedirectToUrl;
} else if (responseData.actionResultReload) {
window.location.reload(true);
}
};
var uniqueIdIndex = 0;
this.newUniqueId = function (prefix) {
if (prefix == null) { prefix = "default"; };
return prefix + "-ewUniqueId-" + (++uniqueIdIndex);
};
};
$(function () {
$(document).ajaxError(function (event, jqxhr, settings, exception) {
if (settings.error == undefined) {
if (EwCore.ajaxLoadError == undefined) {
EwDialogs.errorMessage("Ajax request error '" + exception + "' on url '" + settings.url + "'!");
} else {
if (EwCore.ajaxLoadError != null) {
EwCore.ajaxLoadError(event, jqxhr, settings, exception);
}
}
}
});
});
// ----------------------------------------------------------------
// EwUtils
// ----------------------------------------------------------------
var EwUtils = new function () {
this.updateQueryStringParameter = function (url, key, value, setItEmpty) {
var re = new RegExp("([?|&])" + key + "=.*?(&|$)", "i");
var clearEmpty = (setItEmpty != true && (value == undefined || value == ''));
if (url.match(re)) {
if (clearEmpty) {
return url.replace(re, '$1').replace(/[&|?]+$/, "");
}
return url.replace(re, '$1' + key + "=" + value + '$2');
} else {
if (clearEmpty) {
return url;
} else {
var separator = url.indexOf('?') !== -1 ? "&" : "?";
return url + separator + key + "=" + value;
}
}
};
this.notUndefined = function (value) {
if (value != undefined) {
return value;
}
return "";
};
this.utf8Encode = function (string) {
string = string.replace(/\r\n/g, "\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if ((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
};
this.utf8Decode = function (utftext) {
var string = "";
var i = 0;
var c, c2, c3;
while (i < utftext.length) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
} else if ((c > 191) && (c < 224)) {
c2 = utftext.charCodeAt(i + 1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
} else {
c2 = utftext.charCodeAt(i + 1);
c3 = utftext.charCodeAt(i + 2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return string;
};
this.urlEncode = function (string) {
return escape(this.utf8Encode(string));
};
this.urlDecode = function (urlParam) {
return this.utf8Decode(unescape(urlParam));
};
this.htmlEncode = function (value) {
return $('
').text(value).html();
};
this.htmlDecode = function (value) {
return $('').html(value).text();
};
var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
this.base64Encode = function (input) {
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
input = this.utf8Encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output +
keyStr.charAt(enc1) + keyStr.charAt(enc2) +
keyStr.charAt(enc3) + keyStr.charAt(enc4);
}
return output;
};
this.base64Decode = function (input) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (i < input.length) {
enc1 = keyStr.indexOf(input.charAt(i++));
enc2 = keyStr.indexOf(input.charAt(i++));
enc3 = keyStr.indexOf(input.charAt(i++));
enc4 = keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
}
output = this.utf8Decode(output);
return output;
};
this.setCookie = function (name, value, opts) {
var expires = "";
var seconds = undefined;
if (opts != undefined) {
if (opts.seconds != undefined) {
seconds = opts.seconds;
}
if (opts.minutes != undefined) {
if (!seconds) seconds = 0;
seconds += opts.minutes * 60;
}
if (opts.hours != undefined) {
if (!seconds) seconds = 0;
seconds += opts.hours * 60 * 60;
}
if (opts.days != undefined) {
if (!seconds) seconds = 0;
seconds += opts.days * 24 * 60 * 60;
}
}
if (typeof (seconds) != 'undefined') {
var date = new Date();
date.setTime(date.getTime() + (seconds * 1000));
expires = "; expires=" + date.toGMTString();
}
document.cookie = name + "=" + value + expires + "; path=/";
};
this.getCookie = function (name) {
name = name + "=";
var carray = document.cookie.split(';');
for (var i = 0; i < carray.length; i++) {
var c = carray[i];
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
if (c.indexOf(name) == 0) return c.substring(name.length, c.length);
}
return null;
};
this.deleteCookie = function (name) {
this.setCookie(name, "", -1);
};
this.getUrlParamsAsJson = function () {
var urlParams = {};
var d = function (s) { return decodeURIComponent(s.replace(/\+/g, " ")); };
var q = window.location.search.substring(1);
var r = /([^&=]+)=?([^&]*)/g;
var e;
while (e = r.exec(q)) {
urlParams[d(e[1])] = d(e[2]);
}
return urlParams;
//var search = location.search.substring(1);
//return JSON.parse('{"' + decodeURI(search).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g, '":"') + '"}');
};
this.getUrlParameter = function (name) {
return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || [, ""])[1].replace(/\+/g, '%20')) || null;
};
this.parseValue = function (originalValue, type, defaultValue) {
if (originalValue === undefined) {
return defaultValue;
}
switch (type) {
case "string": {
return originalValue + "";
}
case "number": {
switch (typeof originalValue) {
case "boolean": return originalValue ? 1 : 0;
case "function": return parseFloat((originalValue() + "").replace(',', '.').replace(/\s/g, ''));
case "number": return originalValue;
case "object": {
if (originalValue instanceof HTMLElement) {
originalValue = $(originalValue).val();
}
originalValue = (originalValue + "").replace(',', '.').replace(/\s/g, '');
if (isNaN(originalValue)) {
return defaultValue;
}
return parseFloat(originalValue);
}
case "string": return parseFloat(originalValue.replace(',', '.').replace(/\s/g, ''));
}
}
case "boolean":
case "bool": {
switch (typeof originalValue) {
case "boolean": return originalValue;
case "function": return originalValue() != undefined;
case "number": return originalValue != 0;
case "object": {
if (originalValue instanceof HTMLElement) {
originalValue = $(originalValue).val();
}
return originalValue != null;
}
case "string": return originalValue.length > 0;
}
}
default: {
throw "EwUtils.parseValue(): unsupported type '" + type + "'";
}
}
};
};
// ----------------------------------------------------------------
// DataViewManager
// ----------------------------------------------------------------
var DataViewManager = new function () {
this.firstPageUrl = [];
this.isAjaxView = [];
this.setFirstPageUrl = function (dataViewManagerInstance, url) {
this.isAjaxView[dataViewManagerInstance] = false;
this.firstPageUrl[dataViewManagerInstance] = url;
};
this.setAjaxView = function (dataViewManagerInstance) {
this.isAjaxView[dataViewManagerInstance] = true;
};
this.navigateViewWithParameterUpdate = function (dataViewManagerInstance, key, value, setIfEmpty, firstPath) {
var isAjaxView = this.isAjaxView[dataViewManagerInstance];
if (!isAjaxView) {
if (firstPath == undefined || firstPath) {
var url = this.firstPageUrl[dataViewManagerInstance];
window.location.href = EwUtils.updateQueryStringParameter(url, key, value, setIfEmpty);
} else {
window.location.href = EwUtils.updateQueryStringParameter(window.location.href, key, value, setIfEmpty);
}
}
};
this.navigateViewWithParameterUpdateFromCombo = function (dataViewManagerInstance, key, obj, setIfEmpty, firstPath) {
this.navigateViewWithParameterUpdate(dataViewManagerInstance, key, obj.options[obj.selectedIndex].value, setIfEmpty, firstPath);
};
};
// ----------------------------------------------------------------
// Partial render controls support
// ----------------------------------------------------------------
var PartialRenderControls = new function () {
var self = this;
var partialControls = [];
var actionCallInternal = function (controlDivId, controls, actionName, actionData, actionInitiator) {
var dataBasic = EwCore.createDataRequestBasic();
var actionControl = self.getInstanceByControlDivId(controlDivId);
if (actionControl == undefined) {
throw { toString: function () { return "Partial render control #" + controlDivId + " is not registered!"; } };
}
var controlsArray = [];
controlsArray.push(actionControl);
if (controls != undefined) {
for (var i = 0; i < controls.length; i++) {
var partialRenderInfo = controls[i];
if (partialRenderInfo.controlDivId != controlDivId) {
controlsArray.push(partialRenderInfo);
}
}
}
var requestData = $.extend({ controls: controlsArray, actionName: actionName, actionData: actionData }, dataBasic);
if (actionInitiator != undefined) {
requestData.actionInitiator = actionInitiator;
}
var reloadUrl = self.getPartialRenderHandlerUrl("action");
self.jsonRequest(reloadUrl, requestData);
};
var reloadInternal = function (requestData) {
var reloadUrl = self.getPartialRenderHandlerUrl("reload");
self.jsonRequest(reloadUrl, requestData);
};
var removeByControlDivId = function (controlDivId) {
for (var i = partialControls.length - 1; i >= 0; i--) {
if (partialControls[i].controlDivId == controlDivId) {
partialControls.splice(i, 1);
}
}
};
var checkControlDivIdIsValid = function (controlDivId) {
return $('#' + controlDivId).length > 0;
};
this.reloadByTags = function (tags) {
reloadInternal(this.createDataRequestReloadByTags(tags));
};
this.reloadByControlDivIds = function (controlDivIds) {
reloadInternal(this.createDataRequestReloadByControlDivIds(controlDivIds));
};
this.reloadAll = function () {
this.reloadByTags();
};
this.actionCallSimple = function (controlDivId, actionName, actionData, actionInitiator) {
actionCallInternal(controlDivId, undefined, actionName, actionData, actionInitiator);
};
this.actionCallAndRefreshByTags = function (controlDivId, refreshTags, actionName, actionData, actionInitiator) {
var controls = this.getInstancesByTags(refreshTags);
actionCallInternal(controlDivId, controls, actionName, actionData, actionInitiator);
};
this.actionCallAndRefreshByIds = function (controlDivId, refreshControlDivIds, actionName, actionData, actionInitiator) {
var controls = this.getInstancesByControlDivIds(refreshControlDivIds);
actionCallInternal(controlDivId, controls, actionName, actionData, actionInitiator);
};
this.requestCallAndRefreshByTags = function (url, refreshTags, data) {
var dataRequest = PartialRenderControls.createDataRequestReloadByTags(refreshTags);
this.jsonRequest(url, $.extend(dataRequest, data));
};
this.requestCallAndRefreshByIds = function (url, refreshControlDivIds, data) {
var dataRequest = PartialRenderControls.createDataRequestReloadByIds(refreshControlDivIds);
this.jsonRequest(url, $.extend(dataRequest, data));
};
this.getPartialRenderHandlerUrl = function (command) {
return EwCore.getEwUrl("ew/partial_render/" + command);
};
this.registerPartialRenderControlInstance = function (controlDivId, controlType, renderParams, tags) {
removeByControlDivId(controlDivId);
partialControls.push({ controlDivId: controlDivId, controlType: controlType, renderParams: renderParams, tags: tags });
};
this.getInstancesByTags = function (tags, checkValitity) {
var ret = [];
var tagsArray;
if (tags != undefined && tags.length > 0) {
tagsArray = tags.split(",");
}
for (var i = 0; i < partialControls.length; i++) {
var partialRenderInfo = partialControls[i];
var tagsMatch = false;
if (tagsArray == undefined) {
tagsMatch = true;
} else {
if (partialRenderInfo.tags != undefined) {
var n = partialRenderInfo.tags.split(",");
for (var j = 0; j < tagsArray.length; j++) {
var tagCheck = tagsArray[j];
if ($.inArray(tagCheck, n) != -1) {
tagsMatch = true;
break;
}
}
}
}
if (tagsMatch) {
if (!checkValitity || checkControlDivIdIsValid(partialRenderInfo.controlDivId)) {
ret.push(partialRenderInfo);
}
}
}
return ret;
};
this.getInstancesByControlDivIds = function (controlDivIds, checkValitity) {
var ret = [];
var controlDivIdArray;
if (controlDivIds != undefined && controlDivIds.length > 0) {
controlDivIdArray = controlDivIds.split(",");
for (var i = 0; i < partialControls.length; i++) {
var partialRenderInfo = partialControls[i];
if ($.inArray(partialRenderInfo.controlDivId, controlDivIdArray) != -1) {
if (!checkValitity || checkControlDivIdIsValid(partialRenderInfo.controlDivId)) {
ret.push(partialRenderInfo);
}
}
}
}
return ret;
};
this.getInstanceByControlDivId = function (controlDivId) {
for (var i = 0; i < partialControls.length; i++) {
var partialRenderInfo = partialControls[i];
if (partialRenderInfo.controlDivId == controlDivId) {
return partialRenderInfo;
}
}
return undefined;
};
this.createDataRequestReloadByTags = function (tags) {
var dataBasic = EwCore.createDataRequestBasic();
var controls = this.getInstancesByTags(tags, true);
return $.extend({ controls: controls }, dataBasic);
};
this.createDataRequestReloadByControlDivIds = function (controlDivIds) {
var dataBasic = EwCore.createDataRequestBasic();
var controls = this.getInstancesByControlDivIds(controlDivIds, true);
return $.extend({ controls: controls }, dataBasic);
};
this.jsonRequest = function (url, requestData, opts) {
var error = (opts != undefined) ? opts.error : undefined;
var success = (opts != undefined) ? opts.success : undefined;
var complete = (opts != undefined) ? opts.complete : undefined;
var postBackWriteContent = function (dataResponse) {
if (dataResponse != undefined && dataResponse.controls != undefined) {
for (var i = 0; i < dataResponse.controls.length; i++) {
var partialRenderData = dataResponse.controls[i];
var $target = $("#" + partialRenderData.controlDivId);
$target.html(partialRenderData.htmlContent);
EwCore.ajaxContentAdded($target[0]);
}
}
EwCore.processAjaxControlActionResponse(dataResponse);
if (typeof success == 'function') {
success();
}
};
var ajaxParams = {
type: 'POST',
url: url,
dataType: "json",
contentType: 'application/json',
data: JSON.stringify(requestData),
success: postBackWriteContent,
complete: function (xhr) {
var location = xhr.getResponseHeader("Location");
if (location) {
window.location = location;
} else {
if (typeof complete == 'function') {
complete();
}
}
}
};
if (error != undefined) {
$.extend(ajaxParams, { error: error });
}
$.ajax(ajaxParams);
};
};
// ----------------------------------------------------------------
// EwDialog
// ----------------------------------------------------------------
var EwDialogs = new function () {
// to override by a plugin (custom dialogs design)
this.customUserMessage = undefined;
this.customErrorMessage = undefined;
this.customConfirm = undefined;
var checkOverrideFunctionExists = function (funcName) {
// ReSharper disable UseOfImplicitGlobalInFunctionScope
return (typeof EwDialogsOverride !== 'undefined' && EwDialogsOverride[funcName] != undefined);
// ReSharper restore UseOfImplicitGlobalInFunctionScope
};
var stripHtml = function (html) {
return $("" + EwUtils.htmlEncode(html) + "
").text();
};
this.errorMessage = function (msg) {
if (this.customErrorMessage != undefined) {
this.customErrorMessage(msg);
} else {
if (checkOverrideFunctionExists("errorMessage")) {
// ReSharper disable UseOfImplicitGlobalInFunctionScope
EwDialogsOverride.errorMessage(msg);
// ReSharper restore UseOfImplicitGlobalInFunctionScope
} else {
alert(stripHtml(msg));
}
}
};
this.userMessage = function (msg) {
if (this.customUserMessage != undefined) {
this.customUserMessage(msg);
} else {
if (checkOverrideFunctionExists("userMessage")) {
// ReSharper disable UseOfImplicitGlobalInFunctionScope
EwDialogsOverride.userMessage(msg);
// ReSharper restore UseOfImplicitGlobalInFunctionScope
} else {
alert(stripHtml(msg));
}
}
};
this.confirm = function (msg, opts) {
if (this.customConfirm != undefined) {
this.customConfirm(msg, opts);
} else {
if (checkOverrideFunctionExists("confirm")) {
// ReSharper disable UseOfImplicitGlobalInFunctionScope
EwDialogsOverride.confirm(msg, opts);
// ReSharper restore UseOfImplicitGlobalInFunctionScope
} else {
if (confirm(stripHtml(msg))) {
opts.submit();
}
}
}
};
};
// ----------------------------------------------------------------
// AjaxForms
// ----------------------------------------------------------------
var AjaxForms = (function ($, window) {
'use strict';
var fieldModelSelector = 'ajaxFormFieldModel',
forms = [],
formSelector = '*[data-ajax-form=true], form:not(#aspnetForm)',
keys = { tab: 9, enter: 13, shift: 16, ctrl: 17, alt: 18 },
validators = {},
viewModelSelector = 'ajaxFormViewModel',
getField = function (formModel, fieldName) {
var field = formModel.fields[fieldName];
if (field === undefined) {
throw 'Error: Unable to find field with name ' + fieldName + ' in current form (' + formModel.name + ')!';
}
return field;
},
getForm = function (element) {
var $element = $(element);
if (!$element.is(formSelector)) {
$element = $element.closest(formSelector);
}
return $element;
},
gotFocus = function (formModel) {
var dateBlur = formModel.prevFieldBlur;
if (dateBlur != null && new Date().getTime() - dateBlur < 20) {
formModel.prevFieldBlur = null;
var $prev = formModel.$prevField;
var prevModel = $prev.data(fieldModelSelector);
if (formModel.options.validationMode === 'focusOut' || (formModel.options.validationMode === 'focusOutWhenChanged' && prevModel.getValue() !== $prev.data("valueOnFocus"))) {
prevModel.validate();
}
}
},
defaults = {
autoErrorClass: true,
autoValidatorClass: true,
autoValidatorClassPrefix: 'val_',
errorClass: 'error',
onChangeVisibility: function (targetElement, visible) {
if (visible) {
$(targetElement).show();
} else {
$(targetElement).hide();
}
},
onRefreshLayout: function (formModel, initPhase) {
var i, cond, visible,
fn = initPhase ? defaults.onChangeVisibility : formModel.options.onChangeVisibility;
for (i = 0; i < formModel.conditionals.length; i++) {
cond = formModel.conditionals[i];
visible = eval(cond.condition);
fn(cond.$element[0], visible);
cond.$element.data('valEnabled', visible);
}
},
onValidateChanged: function (fieldElement, isValid, validatorName) {
var $errorSpan, fieldName,
errorClass = this.viewModel.options.errorClass;
if (isValid) {
if (this.$errorSpan !== undefined) {
this.errorMessage = null;
if (this.$errorSpan.data('valMessageFor') === undefined) {
this.$errorSpan.remove();
this.$errorSpan = undefined;
} else {
this.$errorSpan.html('');
}
}
this.$errorMarkers.removeClass(errorClass);
if (this.viewModel.options.autoErrorClass) {
this.$forElements.removeClass(errorClass);
this.$element.removeClass(errorClass);
}
} else {
$errorSpan = this.$errorSpan;
fieldName = this.$element.data('field');
if ($errorSpan === undefined) {
$errorSpan = $('*[data-val-message-for="' + fieldName + '"]', getForm(fieldElement));
if ($errorSpan.length === 0) {
$errorSpan = undefined;
}
}
if ($errorSpan === undefined) {
$errorSpan = $('');
$errorSpan.addClass(errorClass);
this.$element.after($errorSpan);
}
if ($errorSpan === null) {
throw 'unable create error span for field ' + fieldName;
}
this.errorMessage = this.validators[validatorName].message;
$errorSpan.html(this.errorMessage);
this.$errorSpan = $errorSpan;
this.$errorMarkers.addClass(errorClass);
if (this.viewModel.options.autoErrorClass) {
this.$forElements.addClass(errorClass);
this.$element.addClass(errorClass);
}
}
},
onValidatorEnabledChanged: function (fieldElement, validatorName, enabled) {
var field, validatorClass,
$field = $(fieldElement),
fieldName = $field.data('field');
if (!enabled) {
this.options.onValidateChanged.call(this.fields[fieldName], fieldElement, true);
}
if (this.options.autoValidatorClass) {
field = getField(this, fieldName);
validatorClass = this.options.autoValidatorClassPrefix + validatorName;
if (enabled) {
field.$forElements.addClass(validatorClass);
$field.addClass(validatorClass);
} else {
field.$forElements.removeClass(validatorClass);
$field.removeClass(validatorClass);
}
}
},
validateOnChange: false,validateOnKeyUp: false,
validationMode: 'focusOut' //'focusOutWhenChanged'
},
createFieldModel = function (formModel, $field) {
var validatorName, msg,
fieldName = $field.data('field'),
fieldModel = {
errorMessage: null,
$element: $field,
viewModel: formModel,
validators: {},
$errorMarkers: $("*[data-val-marker='" + fieldName + "']"),
$forElements: $("*[data-label-for='" + fieldName + "'],*[data-val-message-for='" + fieldName + "']"),
getValue: function () {
var evalFn, evalWrapper,
value = $field.data('fieldValue');
if (value !== undefined) {
return value;
}
evalFn = $field.data('fieldEval');
if (evalFn !== undefined) {
// ReSharper disable UnusedParameter
evalWrapper = function (field) {
// ReSharper restore UnusedParameter
value = eval(evalFn);
};
evalWrapper(this.$element[0]);
if (value !== undefined) {
return value;
}
}
if ($field.is('input')) {
switch ($field.attr('type').toLowerCase()) {
case 'checkbox':
return $field.is(':checked');
}
}
return $field.val();
},
setValue: function (value) {
var fieldSetFn;
if ($field.data('fieldValue') !== undefined) {
$field.data('fieldValue', value);
return;
}
fieldSetFn = $field.data('fieldSet');
if (fieldSetFn !== undefined) {
eval(fieldSetFn);
return;
}
if ($field.is('input')) {
switch ($field.attr('type').toLowerCase()) {
case 'checkbox': {
if (value === true) {
$field.attr("checked", "checked");
} else {
$field.attr("checked", null);
}
break;
}
}
}
$field.val(value);
},
validate: function (data) {
var i, valInst,
wasValid = this.errorMessage === null,
$el = this.$element,
sortedValidators = [];
this.errorMessage = null;
while ($el.data(viewModelSelector) === undefined) {
if ($el.data('valEnabled') === false) {
return true;
}
$el = $el.parent();
}
for (i in this.validators) {
if (this.validators.hasOwnProperty(i)) {
sortedValidators.push({ validator: this.validators[i], name: i });
}
}
sortedValidators = sortedValidators.sort(function (first, second) { return second.validator.priority - first.validator.priority; });
for (i = 0; i < sortedValidators.length; i++) {
valInst = sortedValidators[i].validator;
if (valInst.enabled && !valInst.func(this, data)) {
if (wasValid || this.errorMessage !== sortedValidators[i].validator.message) {
this.viewModel.options.onValidateChanged.call(this, $field[0], false, sortedValidators[i].name);
}
return false;
}
}
if (!wasValid) {
this.viewModel.options.onValidateChanged.call(this, $field[0], true);
}
return true;
}
};
for (validatorName in validators) {
if (validators.hasOwnProperty(validatorName)) {
msg = $field.data('val' + validatorName.charAt(0).toUpperCase() + validatorName.slice(1));
if (msg !== undefined) {
fieldModel.validators[validatorName] = $.extend({}, validators[validatorName], { message: msg, enabled: true });
}
}
}
$field.data(fieldModelSelector, fieldModel);
$field.change(function () {
var thisFieldModel = $(this).data(fieldModelSelector);
if (thisFieldModel.viewModel.options.validateOnChange) {
thisFieldModel.validate();
}
if (fieldModel.$element.data('layoutChangeNotify') === true) {
thisFieldModel.viewModel.options.onRefreshLayout(thisFieldModel.viewModel, false);
}
});
return fieldModel;
},
initializeButtons = function ($target) {
$('*[data-form-button]', $target).each(function () {
$(this).click(function () {
var $this = $(this),
buttonAction = $this.data('formButton'),
form = $this.ajaxForm();
if (form !== undefined && form !== null) {
form.executeButtonAction(buttonAction, $this.data('initiator'));
}
return undefined;
}).focus(function () {
gotFocus($(this).ajaxForm());
});
});
},
initializeFields = function (formModel) {
$('*[data-field]', $(formModel.form)).each(function () {
var $field = $(this),
fieldName = $field.data('field'),
fieldModel = createFieldModel(formModel, $field);
formModel.fields[fieldName] = fieldModel;
$field.focus(function () {
var $this = $(this);
$this.data("valueOnFocus", $this.data(fieldModelSelector).getValue());
gotFocus(formModel);
}).blur(function () {
formModel.$prevField = $(this);
formModel.prevFieldBlur = new Date().getTime();
});
if ($field.is('input') && ($field.attr('type').toLowerCase() === 'text' || $field.attr('type').toLowerCase() === 'password')) {
$field.keydown(function (e) {
var $this = $(this);
if ((e.keyCode || e.which) === keys.enter) {
$this.data("valueOnKeyDownEnter", $this.data(fieldModelSelector).getValue());
}
}).keyup(function (e) {
var $this = $(this),
form = $this.ajaxForm(),
thisFieldModel = $this.data(fieldModelSelector),
valueEquals = thisFieldModel.getValue() === $this.data("valueOnKeyDownEnter"),
keyCode = e.keyCode || e.which;
if (keyCode === keys.enter) {
if (valueEquals) {
e.preventDefault();
if (form !== undefined && form !== null) {
form.submit();
}
}
} else if (form.options.validateOnKeyUp && keyCode !== keys.tab && keyCode !== keys.shift && keyCode !== keys.ctrl && keyCode !== keys.alt) {
if (!valueEquals) {
thisFieldModel.validate({ initiator: "keyUp", keyCode: keyCode });
}
}
});
}
});
},
initializeValidators = function (formModel) {
var i, j, field;
for (i in formModel.fields) {
if (formModel.fields.hasOwnProperty(i)) {
field = formModel.fields[i];
for (j in field.validators) {
if (field.validators.hasOwnProperty(j)) {
formModel.options.onValidatorEnabledChanged.call(formModel, field.$element[0], j, true);
}
}
}
}
},
initializeVisibleConditions = function (formModel, $target) {
$('*[data-form-visible-condition]', $target).each(function () {
var $this = $(this),
formVisibleCondition = $this.data('formVisibleCondition');
if (formVisibleCondition !== undefined && formVisibleCondition !== null) {
formVisibleCondition = formVisibleCondition.replace(/\{:(.*?):\}/g, function (group, fieldName) {
getField(formModel, fieldName);
return 'formModel.fields["' + fieldName + '"].getValue()';
});
}
formModel.conditionals.push({ $element: $this, condition: formVisibleCondition });
});
},
registerBasicButtonActions = function (formModel) {
registerButtonAction(formModel, 'submit', function (initiator) {
formModel.submit(initiator);
});
registerButtonAction(formModel, 'reset', function () {
formModel.reset();
});
registerButtonAction(formModel, 'validate', function () {
formModel.validate();
});
},
registerBasicValidators = function () {
registerValidator('required', 200, function (field, data) {
if (data !== undefined) { return undefined; }
var initialValue = field.$element.data('valRequiredInitialValue')
if (initialValue === undefined) {
if (field.$element.is("input[type=checkbox]")) {
initialValue = true;
} else {
initialValue = '';
}
}
return field.getValue() !== initialValue;
});
registerValidator('length', 190, function (field, data) {
if (data !== undefined) { return undefined; }
var length = field.getValue().length,
minLength = field.$element.data('valLengthMin'),
maxLength = field.$element.data('valLengthMax');
return (minLength === undefined || parseInt(minLength, 10) <= length) && (maxLength === undefined || parseInt(maxLength, 10) >= length);
});
registerValidator('email', 110, function (field, data) {
if (data !== undefined) { return undefined; }
var val = field.getValue(),
regexEmail = /^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+(?:[a-zA-Z]{2}|com|org|net|gov|mil|biz|edu|info|mobi|name|aero|asia|cat|coop|int|jobs|museum|post|pro|tel|travel|xxx)\b$/;
return val === '' || regexEmail.test(val);
});
registerValidator('regex', 110, function (field, data) {
if (data !== undefined) { return undefined; }
var val = field.getValue(),
expr = field.$element.data('valRegexExpr'),
match = expr.match(new RegExp('^/?(.*?)/?(g?i?m?y?)$')),
regex = match[2] === undefined ? new RegExp(match[1]) : new RegExp(match[1], match[2]);
return val === '' || regex.test(val);
});
registerValidator('range', 110, function (field, data) {
if (data !== undefined) { return undefined; }
var val = field.getValue(),
value = parseFloat(val),
minValue = field.$element.data('valRangeMin'),
maxValue = field.$element.data('valRangeMax');
return val === '' || ((minValue === undefined || parseFloat(minValue) <= value) && (maxValue === undefined || parseFloat(maxValue) >= value));
});
registerValidator('custom', 100, function (field, data) {
if (data !== undefined) { return undefined; }
var caller,
value = field.getValue(),
fnCustom = field.$element.data('valCustomCode'),
result = true;
if (fnCustom !== undefined) {
// ReSharper disable UnusedParameter
caller = function (fieldElement, actualValue) {
// ReSharper restore UnusedParameter
result = eval(fnCustom);
};
caller(field.$element[0], value);
}
return result;
});
},
registerButtonAction = function (formModel, actionName, func) {
formModel.buttonActions[actionName] = func;
},
registerValidator = function (name, priority, validateFunc) {
validators[name] = {
priority: priority,
func: validateFunc
};
},
readChangeVisibilityAttribute = function (formModel, $target, opts) {
var override, base;
override = $target.data('onChangeVisibility');
if (override !== undefined) {
base = opts.onChangeVisibility;
opts.onChangeVisibility = function (target, visible) {
if (eval(override) !== false) {
base.call(formModel, target, visible);
}
};
}
},
readOptionsFromAttributes = function (formModel) {
var override,
opts = $.extend({}, defaults),
$target = $(formModel.form);
readChangeVisibilityAttribute(formModel, $target, opts);
readValidateChangedAttribute(formModel, $target, opts);
readRefreshLayoutAttribute($target, opts);
readValidatorEnabledChangedAttribute(formModel, $target, opts);
override = $target.data('autoErrorClass');
if (override !== undefined) {
opts.autoErrorClass = override === 'true';
}
override = $target.data('autoValidatorClass');
if (override !== undefined) {
opts.autoValidatorClass = override === 'true';
}
override = $target.data('autoValidatorClassPrefix');
if (override !== undefined) {
opts.autoValidatorClassPrefix = override;
}
override = $target.data('errorClass');
if (override !== undefined) {
opts.errorClass = override;
}
override = $target.data('validationMode');
if (override !== undefined) {
opts.validationMode = override;
}
override = $target.data('validateOnKeyUp');
if (override !== undefined) {
opts.validateOnKeyUp = override === 'true';
}
override = $target.data('validateOnChange');
if (override !== undefined) {
opts.validateOnChange = override === 'true';
}
return opts;
},
readRefreshLayoutAttribute = function ($target, opts) {
var override, base;
override = $target.data('onRefreshLayout');
if (override !== undefined) {
base = opts.onRefreshLayout;
opts.onRefreshLayout = function (formModel, initPhase) {
if (eval(override) !== false) {
base(formModel, initPhase);
}
};
}
},
readValidateChangedAttribute = function (formModel, $target, opts) {
var override, base, field;
override = $target.data('onValidateChanged');
if (override !== undefined) {
base = opts.onValidateChanged;
opts.onValidateChanged = function (fieldElement, isValid, validatorName) {
if (eval(override) !== false) {
field = getField(formModel, $(fieldElement).data('field'));
base.call(field, fieldElement, isValid, validatorName);
}
};
}
},
readValidatorEnabledChangedAttribute = function (formModel, $target, opts) {
var override, base;
override = $target.data('onValidatorEnabledChanged');
if (override !== undefined) {
base = opts.onValidatorEnabledChanged;
opts.onValidatorEnabledChanged = function (fieldElement, validatorName, enabled) {
if (eval(override) !== false) {
base.call(formModel, fieldElement, validatorName, enabled);
}
};
}
},
updateOptionsFromParams = function (formModel) {
var i, data = $(formModel.form).data();
for (i in data) {
if (data.hasOwnProperty(i)) {
if (i.indexOf('option') === 0) {
formModel.options[i.substr(6)] = data[i];
}
}
}
};
// ReSharper disable InconsistentNaming
function AjaxForm(formTarget, options) {
// ReSharper restore InconsistentNaming
registerBasicValidators();
var $target = $(formTarget),
formName = $target.data('formName');
forms[formName] = this;
$.extend(this, {
form: formTarget,
name: formName,
fields: {},
buttonActions: {},
conditionals: [],
$validationSummary: $('*[data-val-summary-for="' + formName + '"]')
});
this.options = $.extend({}, readOptionsFromAttributes(this), options);
this.$prevField = null,
this.prevFieldBlur = null,
registerBasicButtonActions(this);
updateOptionsFromParams(this);
initializeFields(this);
initializeValidators(this);
initializeButtons($target);
initializeVisibleConditions(this, $target);
this.options.onRefreshLayout(this, true);
}
$.extend(AjaxForm.prototype, {
buildData: function () {
var i, json = {};
for (i in this.fields) {
if (this.fields.hasOwnProperty(i)) {
json[i] = this.fields[i].getValue();
}
}
return json;
},
executeButtonAction: function (action, initiator) {
var handler = this.buttonActions[action];
if (handler === undefined || handler === null) {
throw "Error: Unable resolve button action '" + action + "'!";
}
handler.call(this, initiator);
},
getFieldValue: function (fieldName) {
var field = getField(this, fieldName);
return field.getValue();
},
setFieldValue: function(fieldName, value) {
var field = getField(this, fieldName);
field.setValue(value);
},
getFieldElement: function (fieldName) {
var field = getField(this, fieldName);
return field.$element[0];
},
refreshLayout: function () {
this.options.onRefreshLayout(this, false);
},
registerButtonAction: function (actionName, func) {
registerButtonAction(this, actionName, func);
},
reset: function () {
$(':input', $(this.form)).filter('*[data-field]').each(function () {
$(this).val(undefined);
});
},
setValidatorEnabled: function (validatorName, enabled, fieldName) {
var i, self = this,
setValidator = function (field) {
var validator = field.validators[validatorName];
if (validator !== undefined && validator !== null) {
if (validator.enabled !== enabled) {
validator.enabled = enabled;
self.options.onValidatorEnabledChanged.call(self, field.$element[0], validatorName, enabled);
}
}
};
if (fieldName === undefined) {
for (i in this.fields) {
if (this.fields.hasOwnProperty(i)) {
setValidator(this.fields[i]);
}
}
} else {
setValidator(this.fields[fieldName]);
}
},
submit: function (initiator) {
var actionUrl, handler, caller, location,
$target = $(this.form);
var submitData = this.submitGetData(initiator);
if (submitData == undefined) {
return;
}
actionUrl = $target.data('actionUrl');
if (actionUrl !== undefined) {
$.ajax({
type: 'POST',
url: actionUrl,
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify(submitData),
success: function (data) {
handler = $target.data('onSuccess');
if (handler !== undefined) {
// ReSharper disable UnusedParameter
// ReSharper disable DuplicatingLocalDeclaration
caller = function (data, initiator, formModel) {
// ReSharper restore DuplicatingLocalDeclaration
// ReSharper restore UnusedParameter
eval(handler);
};
caller(data, initiator, this);
}
},
error: function (data) {
handler = $target.data('onError');
if (handler !== undefined) {
// ReSharper disable UnusedParameter
// ReSharper disable DuplicatingLocalDeclaration
caller = function (data, initiator, formModel) {
// ReSharper restore DuplicatingLocalDeclaration
// ReSharper restore UnusedParameter
eval(handler);
};
caller(data, initiator, this);
} else {
throw 'Error: Form ' + $target.data('formName') + ' submit error! - Response: ' + data.responseText;
}
},
complete: function (xhr) {
location = xhr.getResponseHeader('Location');
if (location) {
window.location = location;
}
}
});
return;
}
handler = $target.data('onSubmit');
if (handler !== undefined) {
// ReSharper disable UnusedParameter
// ReSharper disable DuplicatingLocalDeclaration
caller = function (data, initiator, formModel) {
// ReSharper restore DuplicatingLocalDeclaration
// ReSharper restore UnusedParameter
eval(handler);
};
caller(submitData.data, initiator, this);
return;
}
throw 'Error: Can\'t submit form ' + $target.data('formName') + '!';
},
submitGetData: function (initiator) {
if (!this.validate()) {
return undefined;
}
return { data: this.buildData(), initiator: initiator };
},
validate: function (fieldName, data) {
var i, handler, caller, errorMessage, ul,
isFormValid = true,
errors = [];
if (fieldName !== undefined) {
if (!this.fields[fieldName].validate(data)) {
isFormValid = false;
}
} else {
for (i in this.fields) {
if (this.fields.hasOwnProperty(i)) {
if (!this.fields[i].validate(data)) {
isFormValid = false;
}
}
}
}
handler = $(this.form).data('onValidate');
if (handler !== undefined) {
// ReSharper disable UnusedParameter
caller = function (formModel, isValid) {
// ReSharper restore UnusedParameter
if (!eval(handler)) {
isFormValid = false;
}
};
caller(this, isFormValid);
}
this.$validationSummary.html('');
if (!isFormValid) {
for (i in this.fields) {
if (this.fields.hasOwnProperty(i)) {
errorMessage = this.fields[i].errorMessage;
if (errorMessage !== null && errorMessage !== undefined) {
errors.push(errorMessage);
}
}
}
ul = $("");
$.each(errors, function (index, item) {
$("").html(item).appendTo(ul);
});
ul.appendTo(this.$validationSummary);
}
return isFormValid;
}
});
$.fn.ajaxForm = function () {
var result, form, actual;
this.each(function () {
form = getForm(this);
if (form !== undefined && form !== null) {
actual = form.data(viewModelSelector);
if (result !== undefined && actual !== result) {
throw "Error: unable resolve single form from selected elements!";
}
result = actual;
}
});
return result;
};
$.fn.ajaxFormParse = function (options) {
$(formSelector, this).each(function () {
if (!$.data(this, viewModelSelector)) {
$.data(this, viewModelSelector, new AjaxForm(this, options || {}));
}
});
$("*[data-form-button][data-form-name]", $(formSelector)).click(function () {
var form = AjaxForms.getByName($(this).data("formName"));
if (form !== undefined && form !== null) {
form.executeButtonAction($(this).data("formButton"), $(this).data("initiator"));
}
});
};
$(function () {
$(window.document).ajaxFormParse();
});
return {
getByName: function (formName) {
return forms[formName];
},
registerValidator: registerValidator
};
}(jQuery, window));
// ----------------------------------------------------------------
// jQuery extensions
// ----------------------------------------------------------------
(function ($) {
// [name] is the name of the event "click", "mouseover", ..
// same as you'd pass it to bind()
// [fn] is the handler function
$.fn.bindFirst = function (name, fn) {
// bind as you normally would
// don't want to miss out on any jQuery magic
this.on(name, fn);
// Thanks to a comment by @Martin, adding support for
// namespaced events too.
this.each(function () {
var handlers = $._data(this, 'events')[name.split('.')[0]];
// take out the handler we just inserted from the end
var handler = handlers.pop();
// move it at the beginning
handlers.splice(0, 0, handler);
});
};
$.fn.uniqueId = function (prefix, overwrite) {
return this.each(function () {
if (!this.id || overwrite) {
this.id = EwCore.newUniqueId(prefix);
}
});
};
}(jQuery));
// ----------------------------------------------------------------
// Compatibility fixes
// ----------------------------------------------------------------
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (obj, start) {
for (var i = (start || 0), j = this.length; i < j; i++) {
if (this[i] === obj) { return i; }
}
return -1;
};
};
// disable default ajax cache for get requests
$(function () {
$.ajaxSetup({ cache: false });
});