blob: 9e329d0c5f5669ddb7ae3981eb2cd5f161836ae9 [file] [log] [blame]
/**
* @file 在lib.observable基础上加了写入控制。不满足条件不会写入。
* 暂只支持min、max、多value。暂不支持自定义比较。
* @author sushuang(sushuang@baidu.com)
* @date 2014-05
*/
define(function (require) {
var $ = require('jquery');
var lib = require('../util');
var libPeek = lib.peek;
var fixNumber = lib.fixNumber;
/**
* 对输入的ob进行decorate。建立他们直接的联动或验证。
* 验证规则:
* 设置value时,超出max/min界限时,会调整max min
* 设置maxmin时如果不大于/小于所有value,或者min大于max,则设置失败,返回当前max/min
* 使用方式例如:
* var rangeValueDecorator = require('...');
* var decoratedOb = rangeValueDecorator({
* max: lib.ob(-20),
* min: lib.ob(1000),
* value: [lib.ob(123), lib.ob(987)]
* precision: lib.ob(2)
* });
*
* @param {Object} options
* @param {Object=} options.max lib.ob类型。最值,为空则表示不使用max
* @param {Object=} options.min lib.ob类型最值。为空则表示不使用min
* @param {(Object|Object|Array.{Object}} value lib.ob类型,或者数组中是lib.ob。要包装的值
* @param {(Object|number)=} precision lib.ob类型。如果是2,表示精度为小数点后两位;0表示精度为整数。缺省则不限制精度
* @return {Object} 包装好的ob对象。
*/
function rangeValueDecorator(options) {
options = options || {};
// 闭包中维持的变量
var minOb = options.min;
var maxOb = options.max;
var vals = options.value;
var precision = options.precision; // precision不需包装
var valueMax;
var valueMin;
if (minOb != null) {
minOb.extendWriter(minWriter);
}
if (maxOb) {
maxOb.extendWriter(maxWriter);
}
if ($.isArray(vals)) {
updateMinMaxForArr();
for (var i = 0, len = vals.length; i < len; i++) {
vals[i].extendWriter(
lib.curry(valueWriter, i, updateMinMaxForArr)
);
}
}
else if ($.isPlainObject(vals)) {
updateMinMaxForObj();
for (var key in vals) {
if (vals.hasOwnProperty(key)) {
vals[key].extendWriter(
lib.curry(valueWriter, key, updateMinMaxForObj)
);
}
}
}
else {
updateMinMaxForSingle();
vals.extendWriter(
lib.curry(valueWriter, null, updateMinMaxForSingle)
);
}
return options;
/**
* @inner
*/
function updateMinMaxForArr(val, updateIndex) {
// 这里做了n^2的实现而没考虑性能,
// 是因为绝大部分场景下n很小。
// 这样实现略简单些。
valueMax = Number.MIN_VALUE;
valueMin = Number.MAX_VALUE;
for (var i = 0, len = vals.length; i < len; i++) {
var thisVal = i === updateIndex ? val : libPeek(vals[i]);
if (thisVal < valueMin) {
valueMin = thisVal;
}
if (thisVal > valueMax) {
valueMax = thisVal;
}
}
}
function updateMinMaxForObj(val, updateKey) {
// 这里做了n^2的实现而没考虑性能,
// 是因为绝大部分场景下n很小。
// 这样实现略简单些。
valueMax = Number.MIN_VALUE;
valueMin = Number.MAX_VALUE;
for (var key in vals) {
if (vals.hasOwnProperty(key)) {
var thisVal = key === updateKey ? val : libPeek(vals[i]);
if (thisVal < valueMin) {
valueMin = thisVal;
}
if (thisVal > valueMax) {
valueMax = thisVal;
}
}
}
}
function updateMinMaxForSingle(val) {
valueMin = valueMax = !arguments.length ? libPeek(vals) : val;
}
/**
* @private
*/
function formatNumber(val) {
return fixNumber(parseFloat(val), libPeek(precision));
}
/**
* 写入value。
* val 可能是任意非法的数值,负责校验。
*/
function valueWriter(key, updataMinMax, writer, value, valueInfo, options) {
if (!lib.validateNumeric(value)) {
return;
}
value = formatNumber(value);
updataMinMax(value, key);
// 先设完 valueMin valueMax 才可设置 maxOb minOb
if (maxOb != null && value > libPeek(maxOb)) {
maxOb(value);
}
if (minOb != null && value < libPeek(minOb)) {
minOb(value);
}
// 最后才可更新自身
writer(value, valueInfo, options);
}
/**
* 写入min
*/
function minWriter(writer, value, valueInfo, options) {
if (!lib.validateNumeric(value)) {
return;
}
value = formatNumber(value);
// 合法,才能设置成功
if (value <= valueMin) {
writer(value, valueInfo, options);
}
}
/**
* 写入max
*/
function maxWriter(writer, value, valueInfo, options) {
if (!lib.validateNumeric(value)) {
return;
}
value = formatNumber(value);
// 合法,才能设置成功
if (value >= valueMax) {
writer(value, valueInfo, options);
}
}
} // end of function RangeValueDecorator
return rangeValueDecorator;
});