First commit waiting for Budget Alert
This commit is contained in:
252
sophal/js/form/form.input.number.js
Normal file
252
sophal/js/form/form.input.number.js
Normal file
@ -0,0 +1,252 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2005-2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
/* jshint validthis: true */
|
||||
|
||||
"use strict";
|
||||
|
||||
var ui = angular.module('axelor.ui');
|
||||
|
||||
/**
|
||||
* The Numeric input widget.
|
||||
*/
|
||||
ui.formInput('Number', {
|
||||
|
||||
css: 'integer-item',
|
||||
|
||||
widgets: ['Integer', 'Long', 'Decimal'],
|
||||
|
||||
template_readonly: '<span class="display-text">{{localeValue()}}</span>',
|
||||
|
||||
link: function(scope, element, attrs, model) {
|
||||
|
||||
var props = scope.field,
|
||||
minSize = +props.minSize,
|
||||
maxSize = +props.maxSize;
|
||||
|
||||
var isDecimal = props.serverType === "decimal" || props.widget === "decimal",
|
||||
pattern = isDecimal ? /^(-)?\d+(\.\d+)?$/ : /^\s*-?[0-9]*\s*$/;
|
||||
|
||||
function scale() {
|
||||
var value = scope.attr('scale');
|
||||
if (value) {
|
||||
return value;
|
||||
}
|
||||
if ((props.widgetAttrs||{}).scale) {
|
||||
return props.widgetAttrs.scale;
|
||||
}
|
||||
return props.scale || 2;
|
||||
}
|
||||
|
||||
function precision() {
|
||||
var value = scope.attr('precision');
|
||||
if (value) {
|
||||
return value;
|
||||
}
|
||||
if ((props.widgetAttrs||{}).precision) {
|
||||
return props.widgetAttrs.precision;
|
||||
}
|
||||
return props.precision || 18;
|
||||
}
|
||||
|
||||
scope.isNumber = function(value) {
|
||||
return _.isEmpty(value) || _.isNumber(value) || pattern.test(value);
|
||||
};
|
||||
|
||||
scope.validate = scope.isValid = function(value) {
|
||||
var valid = scope.isNumber(value);
|
||||
if (valid && isDecimal && _.isString(value)) {
|
||||
value = scope.format(value);
|
||||
valid = _.string.trim(value, '-').length - 1 <= precision();
|
||||
value = +value;
|
||||
}
|
||||
|
||||
if (valid && (minSize || minSize === 0)) {
|
||||
valid = value >= minSize;
|
||||
}
|
||||
if (valid && (maxSize || maxSize === 0)) {
|
||||
valid = value <= maxSize;
|
||||
}
|
||||
|
||||
return valid;
|
||||
};
|
||||
|
||||
scope.localeValue = function localeValue() {
|
||||
var value = scope.getValue();
|
||||
var field = isDecimal ? _.extend({}, scope.field, {
|
||||
scale: scale(),
|
||||
precision: precision()
|
||||
}) : scope.field;
|
||||
return isDecimal
|
||||
? ui.formatters.decimal(field, value)
|
||||
: ui.formatters.integer(field, value);
|
||||
};
|
||||
|
||||
scope.format = function format(value) {
|
||||
if (isDecimal && _.isString(value) && value.trim().length > 0) {
|
||||
return parseFloat(value).toFixed(scale());
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
scope.parse = function(value) {
|
||||
if (isDecimal) return value;
|
||||
if (value && _.isString(value)) return +value;
|
||||
return value;
|
||||
};
|
||||
|
||||
scope.$on("on:attrs-changed", function (e, attr) {
|
||||
if (attr.name === 'scale' || attr.name === 'precision') {
|
||||
model.$render();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
link_editable: function(scope, element, attrs, model) {
|
||||
|
||||
var props = scope.field;
|
||||
|
||||
var options = {
|
||||
step: 1
|
||||
};
|
||||
|
||||
element.on("spin", onSpin);
|
||||
element.on("spinchange", function(e, row) {
|
||||
updateModel(element.val());
|
||||
});
|
||||
element.on("grid:check", function(e, row) {
|
||||
updateModel(element.val());
|
||||
});
|
||||
|
||||
var pendingChange = false;
|
||||
|
||||
function handleChange(changed) {
|
||||
var onChange = scope.$events.onChange;
|
||||
if (onChange && (changed || pendingChange)) {
|
||||
pendingChange = false;
|
||||
setTimeout(onChange);
|
||||
}
|
||||
}
|
||||
|
||||
function equals(a, b) {
|
||||
if (a === b) return true;
|
||||
if (angular.equals(a, b)) return true;
|
||||
if (a === "" && b === undefined) return true;
|
||||
if (b === "" && a === undefined) return true;
|
||||
if (a === undefined || b === undefined) return false;
|
||||
if (a === null || b === null) return false;
|
||||
if (!scope.isNumber(a) || !scope.isNumber(b)) return false;
|
||||
a = a === "" ? a : ((+a) || 0);
|
||||
b = b === "" ? b : ((+b) || 0);
|
||||
return a === b;
|
||||
}
|
||||
|
||||
function updateModel(value, handle) {
|
||||
if (!scope.isNumber(value)) {
|
||||
return model.$setViewValue(value); // force validation
|
||||
}
|
||||
var val = scope.parse(value);
|
||||
var old = scope.getValue();
|
||||
var text = scope.format(value);
|
||||
|
||||
element.val(text);
|
||||
|
||||
if (equals(val, old)) {
|
||||
return handleChange();
|
||||
}
|
||||
|
||||
scope.setValue(val);
|
||||
scope.$applyAsync();
|
||||
|
||||
pendingChange = true;
|
||||
|
||||
if (handle !== false) {
|
||||
handleChange();
|
||||
}
|
||||
}
|
||||
|
||||
function onSpin(event, ui) {
|
||||
|
||||
var text = this.value,
|
||||
value = ui.value,
|
||||
orig = element.spinner('value'),
|
||||
parts, integer, decimal, min, max, dir = 0;
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
if (!scope.isNumber(text)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value < orig)
|
||||
dir = -1;
|
||||
if (value > orig)
|
||||
dir = 1;
|
||||
|
||||
parts = text.split(/\./);
|
||||
integer = +parts[0];
|
||||
decimal = parts[1];
|
||||
|
||||
integer += dir;
|
||||
if (parts.length > 1) {
|
||||
value = integer + '.' + decimal;
|
||||
}
|
||||
|
||||
min = options.min;
|
||||
max = options.max;
|
||||
|
||||
if (_.isNumber(min) && value < min)
|
||||
value = min;
|
||||
if (_.isNumber(max) && value > max)
|
||||
value = max;
|
||||
|
||||
updateModel(value, false);
|
||||
}
|
||||
|
||||
if (props.minSize !== undefined)
|
||||
options.min = +props.minSize;
|
||||
if (props.maxSize !== undefined)
|
||||
options.max = +props.maxSize;
|
||||
|
||||
setTimeout(function(){
|
||||
element.spinner(options);
|
||||
scope.$elem_editable = element.parent();
|
||||
model.$render = function() {
|
||||
var value = model.$viewValue;
|
||||
if (value) {
|
||||
value = scope.format(value);
|
||||
}
|
||||
element.val(value);
|
||||
scope.initValue(value);
|
||||
};
|
||||
model.$render();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// fix spinner repeat issue
|
||||
var oldRepeat = $.ui.spinner.prototype._repeat;
|
||||
$.ui.spinner.prototype._repeat = function () {
|
||||
if (this.element.scope().isReadonly()) {
|
||||
return this._stop();
|
||||
}
|
||||
return oldRepeat.apply(this, arguments);
|
||||
};
|
||||
|
||||
})();
|
||||
Reference in New Issue
Block a user