; (function ($) { /** * 数字控件 * * @example * var editor = new FR.NumberEditor({ * renderEl : 'body', * allowDecimals : true, * allowNegative : true, * decimalPrecision : -1, * autoVerify : true, * decimalSeparator : ".", * value : -233.455 * }); * * @class FR.NumberEditor * @extends FR.EditComp * @cfg {JSON} options 属性配置 * @cfg {Boolean} [options.allowDecimals=true] 是否允许小数 * @cfg {Boolean} [options.allowNegative=true] 是否允许负数 * @cfg {Number} [options.decimalPrecision=-1] 小数精确度 * @cfg {String} [options.decimalSeparator=.] 小数分割符 */ FR.NumberEditor = FR.extend(FR.EditComp, /**@class FR.NumberEditor*/{ _defaultConfig: function () { return $.extend(FR.NumberEditor.superclass._defaultConfig.apply(), { allowDecimals: true, allowNegative: true, decimalPrecision: -1, autoVerify: true, decimalSeparator: '.'// decimal的分隔符 // alex:不添加value:0作为默认值,这样会导致在BS编辑的时候,如果写的是0,发现isDirty == // false,而不赋值 }); }, _init: function () { FR.NumberEditor.superclass._init.apply(this, arguments); var o = this.options; var baseChars = '0123456789'; this.allowed = baseChars + ''; if (o.allowDecimals) { this.allowed += '.'; } if (o.allowNegative) { this.allowed += "-"; } // b:屏蔽输入法 this.editComp.css("ime-mode", "disabled"); var self = this; this.editComp.blur(function () { if ('.' == self.editComp.val().charAt(0)) { self.editComp.val('0' + self.editComp.val()); } }).keydown(function (e) { // wei : 不触发参数界面查询按钮 if (e.keyCode == FR.keyCode.ENTER && !self.options.write) { e.stopPropagation(); } }).keypress(function (e) { // james:下面是抄的Ext的 var k = e.keyCode; if (!$.browser.msie && (FR.isNavKeyPress(e) || FR.isSpecialKey(e) || k == FR.keyCode.BACKSPACE)) { return; } var c = e.charCode || e.keyCode;// james:IE当中要取keyCode var cc = String.fromCharCode(c); // if($.browser.msie && (FR.isSpecialKey(e) || !cc)){ // 过滤掉回车(ASCII为13)和ESC(ASCII为27) if ($.browser.msie && (c === 27 || c === 13)) { return; } if (self.allowed.indexOf(cc) === -1) { // FR.Msg.toast(errorMsg); e.preventDefault(); } if (this.value.indexOf('.') > -1 && cc == '.') { // FR.Msg.toast(errorMsg); e.preventDefault(); } }); }, isValidateInput: function (e) { var c = e.charCode || e.keyCode;// james:IE当中要取keyCode // wei:backspace if (c == FR.keyCode.BACKSPACE || c == FR.keyCode.ENTER) { return true; } // 上面数字键盘是48-57 数字小键盘是96-105 同样小数点也要考虑两个 if (c >= 96 && c <= 105) { c = c - 48; } var cc = String.fromCharCode(c); if (c === 190 || c === 110) { cc = "."; } return (this.allowed.indexOf(cc) > -1) && (cc != '.' || (this.editComp.val().substr(0, this.editComp.val().length - 1)).indexOf('.') === -1); }, _dealValueWithEvents: function (value) { var oldValue = this.getValue(); var txt; if (typeof oldValue == 'string' && oldValue != '') { txt = oldValue; } else { // value = parseFloat(value); txt = String(value); } this.editComp.val( txt.replace(".", this.options.decimalSeparator)); // alex:把老的值保存在this.options.value中,用来判断isDirty if (arguments[1] !== false) { this.fireEvent(FR.Events.CHANGE, value, oldValue); // fire value // change event, // newValue & // oldValue } }, _fixPrecision: function (value) { var nan = isNaN(value); if (!this.options.allowDecimals || this.options.decimalPrecision == -1 || nan || !value) { return nan ? '' : value; } return parseFloat(parseFloat(value).toFixed(this.options.decimalPrecision)); }, // float只能支持到17位,而21位才开始转化成科学计数法, // 17到21位会出错,21位以上位数正常但是会舍掉一部分 todo _parseValue: function (value) { value = parseFloat(String(value).replace(this.options.decimalSeparator, ".")); return isNaN(value) ? '' : value; }, // james:对于数字编辑器的返回值,如果没有值,就返回'',如果输入的是0,就返回0 // 这个地方要看用户的反馈,是否需要提供可配置的地方。 getValue: function () { var txt = this.editComp.val(); if (txt.length > 17) { return txt; } return this._fixPrecision(this._parseValue(txt)); }, verifyDedimals: function () { if (typeof this.editComp.reg == "undefined") { this.editComp.reg = (this.options.allowNegative ? "\-?" : "") + "\\d+" + (this.options.allowDecimals ? ("(\\.\\d{0," + this.options.maxDecLength + "})?") : ""); } var pattern = new RegExp(this.editComp.reg); var result = pattern.exec(this.editComp.val()); if (result != null) { return result[0]; } return ""; }, recoveryValue: function () { this.editComp.val(isNaN(this.options.oldValue) ? '' : String(this.options.oldValue).replace(".", this.options.decimalSeparator)); }, isValidate: function (cValue) { var value = cValue != null && cValue != undefined ? cValue : this.editComp.val(); if(cValue && this.options.isEditable && (''+ cValue).indexOf(',') != -1){ value = value.replace(/,/g, ""); } // richer:不允许为空 // b: 不确定这么改有没有问题 // value==""时如果value=0则表达式为ture,放在最后安全 if (value == null || value == undefined || value === "") { if (this.options.allowBlank !== false) { return true; } else { this.errorMsg = this.options.errorMsg || FR.i18nText("FR-Base_NOT_NULL_Des"); return false; } } value = ('' + value).replace(this.options.decimalSeparator, "."); if (isNaN(value)) { this.errorMsg = this.options.errorMsg || FR.i18nText("Err-The_value_must_be_number"); return false; } // 不允许为小数 // 数字太大parseFloat就变成科学计数法的形式了 而且总位数17以上的小数会被截断 var str = value; var bd = new FR.BigDecimal({ numStr: str }); if (str.indexOf(this.options.decimalSeparator) > 0) { if (!this.options.allowDecimals) { this.errorMsg = this.options.errorMsg || FR.i18nText("Err-The_value_must_be_integer"); return false; } else { if (str.length - str.indexOf(this.options.decimalSeparator) > this.options.maxDecLength + 1) { this.errorMsg = this.options.errorMsg || FR.i18nText("FR-Base_DecimalNumber_Out"); return false; } } } // 不允许为负数 if (!this.options.allowNegative && !bd.isPositive()) { this.errorMsg = this.options.errorMsg || FR.i18nText("FR-Report_Invalid_Cell"); return false; } if (this.options.minValue != null && bd.lessThan(new FR.BigDecimal({numStr: String(this.options.minValue)}))) { this.errorMsg = this.options.errorMsg || FR.i18nText("Err-The_number_is_less_than_the_minimum_value") + this.options.minValue; return false; } if (this.options.maxValue != null && bd.greaterThan(new FR.BigDecimal({numStr: String(this.options.maxValue)}))) { this.errorMsg = this.options.errorMsg || FR.i18nText("Err-The_number_is_larger_than_the_maximum_value") + this.options.maxValue; return false; } return true; }, doResize: function (give) { FR.NumberEditor.superclass.doResize.call(this, give); } }); $.shortcut("number", FR.NumberEditor); /** * 双精度数处理函数 * @param {JSON} config 配置属性 * @constructor */ FR.BigDecimal = function (config) { this.options = $.extend({ numStr: '', decimalSeparator: '.' }, config); var o = this.options; var str = o.numStr; // 正数 this.positive = true; // 整数部分 this.intArray = []; // 小数部分 this.decArray = []; // if (str.indexOf("e") !== -1 || str.indexOf("E") !== -1) { } var i=0; var dealPos = true; if (str.charAt(0).match(/[-+]/)) { this.positive = str.charAt(0) == '+'; i ++; } for (; i<str.length; i++) { var c = str.charAt(i); if (c == o.decimalSeparator) { dealPos = false; continue; } if (dealPos) { this.intArray.push(c); } else { this.decArray.push(c); } } }; $.extend(FR.BigDecimal.prototype, { isPositive: function() { return this.positive; }, equalsTo: function(bigDecimal) { return this.compareTo(bigDecimal) === 0; }, greaterThan: function(bigDecimal) { return this.compareTo(bigDecimal) === 1; }, lessThan: function(bigDecimal) { return this.compareTo(bigDecimal) === -1; }, compareTo: function(bigDecimal) { if (bigDecimal == null) { return null; } if (this.isPositive() && !bigDecimal.isPositive()) { return 1; } if (!this.isPositive() && bigDecimal.isPositive()) { return -1; } var res = 0; var arr = this.intArray; if (arr.length > bigDecimal.intArray.length) { res = 1; } else if (arr.length < bigDecimal.intArray.length) { res = -1; } else { for (var i=0; i<arr.length; i++) { if (arr[i] > bigDecimal.intArray[i]) { res = 1; break; } else if (arr[i] < bigDecimal.intArray[i]) { res = -1; break; } } if (res === 0) { var decArr = this.decArray; var decLen = Math.min(decArr.length, bigDecimal.decArray.length); for (var j= 0; j<decLen; j++) { if (decArr[j] > bigDecimal.decArray[j]) { res = 1; break; } else if (decArr[j] < bigDecimal.decArray[j]) { res = -1; break; } } if (res === 0) { if (decArr[decLen] != null) { res = 1; } else if (bigDecimal.decArray[decLen] != null) { res = -1; } } } } return this.isPositive() ? res : -res; } }); })(jQuery);