You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
460 lines
13 KiB
460 lines
13 KiB
BI.Model = BI.inherit(BI.M, { |
|
_defaultConfig: function () { |
|
return { |
|
"default": "just a default", |
|
"current": void 0 |
|
} |
|
}, |
|
|
|
_static: function () { |
|
return {}; |
|
}, |
|
|
|
_init: function () { |
|
BI.Model.superclass._init.apply(this, arguments); |
|
this.on("change:current", function (obj, val) { |
|
BI.isNotNull(val) && this.refresh(val); |
|
}).on("change", function (changed, prev, context, options) { |
|
if (this._start === true || BI.has(changed, "current")) { |
|
return; |
|
} |
|
this.actionStart(); |
|
if (!this.local()) { |
|
!BI.has(this._tmp, BI.keys(changed)) && this.parent && this.parent._change(this); |
|
this._changing_ = true; |
|
this.change(changed, prev, context, options); |
|
this._changing_ = false; |
|
} |
|
}); |
|
|
|
this._tmp = {};//过渡属性 |
|
|
|
this._hass = {}; |
|
this._gets = [];//记录交互行为 |
|
this._start = false; |
|
this._changing_ = false; |
|
|
|
this._read = BI.debounce(BI.bind(this.fetch, this), 30); |
|
this._save = BI.debounce(BI.bind(this.save, this), 30); |
|
this._F = []; |
|
}, |
|
|
|
toJSON: function () { |
|
var json = BI.Model.superclass.toJSON.apply(this, arguments); |
|
delete json["baseCls"]; |
|
delete json["current"]; |
|
delete json["default"]; |
|
delete json["parent"]; |
|
delete json["rootURL"]; |
|
delete json["id"]; |
|
delete json["tag"]; |
|
BI.each(this._gets, function (i, action) { |
|
delete json[action]; |
|
}); |
|
return json; |
|
}, |
|
|
|
copy: function () { |
|
if (this._start === true || this._changing_ === true) { |
|
this._F.push({f: this.copy, arg: arguments}); |
|
return; |
|
} |
|
this.trigger("copy"); |
|
}, |
|
//子节点的一个类似副本 |
|
similar: function (value, key1, key2, key3) { |
|
return value; |
|
}, |
|
|
|
_map: function (child) { |
|
var self = this; |
|
var map = {}, current = {}; |
|
var mapping = function (key, ch) { |
|
key = key + ""; |
|
if (key === "") { |
|
return; |
|
} |
|
var keys = key.split('.'); |
|
if (!map[keys[0]]) { |
|
map[keys[0]] = self.get(keys[0]); |
|
} |
|
var parent = map, last = void 0; |
|
BI.each(keys, function (i, k) { |
|
last && (parent = parent[last] || (parent[last] = {})); |
|
last = k; |
|
}); |
|
parent[last] = ch.toJSON(); |
|
}; |
|
BI.each(this._childs, function (key, chs) { |
|
if (!BI.isArray(chs)) { |
|
chs = [chs]; |
|
} |
|
BI.each(chs, function (i, ch) { |
|
if (ch === child) { |
|
current[key] = child; |
|
return; |
|
} |
|
//mapping(key, ch); |
|
}) |
|
}); |
|
BI.each(current, function (key, ch) { |
|
mapping(key, ch); |
|
}); |
|
var tmp = {}; |
|
BI.each(this._tmp, function (k) { |
|
if (map[k]) { |
|
tmp[k] = map[k]; |
|
delete map[k]; |
|
} |
|
}); |
|
this.tmp(tmp); |
|
return map; |
|
}, |
|
|
|
_change: function (child) { |
|
this.set(this._map(child)); |
|
return this; |
|
}, |
|
|
|
splice: function (old, key1, key2, key3) { |
|
|
|
}, |
|
|
|
duplicate: function (copy, key1, key2, key3) { |
|
|
|
}, |
|
|
|
change: function (changed, prev) { |
|
|
|
}, |
|
|
|
actionStart: function () { |
|
this._start = true; |
|
return this; |
|
}, |
|
|
|
actionEnd: function () { |
|
var self = this; |
|
this._start = false; |
|
var _gets = this._gets.slice(0), _F = this._F.slice(0); |
|
this._gets = []; |
|
this._hass = {}; |
|
this._F = []; |
|
BI.each(_gets, function (i, action) { |
|
self.unset(action, {silent: true}); |
|
}); |
|
BI.each(_F, function (i, fn) { |
|
fn.f.apply(self, fn.arg); |
|
}); |
|
return this; |
|
}, |
|
|
|
addChild: function (name, child) { |
|
name = name + ""; |
|
var self = this; |
|
this._childs || (this._childs = {}); |
|
if (this._childs[name]) { |
|
if (BI.isArray(this._childs[name])) { |
|
this._childs[name].push(child); |
|
} else { |
|
this._childs[name] = [this._childs[name]].concat(child) |
|
} |
|
} else { |
|
this._childs[name] = child; |
|
} |
|
child && child.on("destroy", function () { |
|
var keys = name.split('.'); |
|
var g = self.get(keys[0]), p, c; |
|
var sset = !!self._tmp[keys[0]] ? "tmp" : "set", unset = "un" + sset; |
|
|
|
BI.each(keys, function (i, k) { |
|
if (i === 0) { |
|
c = g; |
|
return; |
|
} |
|
p = c; |
|
c = c[k]; |
|
}); |
|
self.removeChild(name, child); |
|
var newKeys = BI.clone(keys); |
|
keys.length > 1 ? newKeys.unshift(BI.deepClone(p[keys[keys.length - 1]])) : newKeys.unshift(BI.deepClone(g)); |
|
keys.length > 1 ? (delete p[keys[keys.length - 1]], self[sset](keys[0], g, {silent: true})) : self[unset](name, {silent: true}); |
|
!BI.has(self._tmp, keys[0]) && self.parent && self.parent._change(self); |
|
self.splice.apply(self, newKeys); |
|
self.trigger("splice", newKeys); |
|
}).on("copy", function () { |
|
var keys = name.split('.'); |
|
var g = self.get(keys[0]), p, c; |
|
var sset = !!self._tmp[keys[0]] ? "tmp" : "set"; |
|
BI.each(keys, function (i, k) { |
|
if (i === 0) { |
|
c = g; |
|
return; |
|
} |
|
p = c; |
|
c = c[k]; |
|
}); |
|
var copy = BI.UUID(), newKeys = BI.clone(keys); |
|
keys.length > 1 ? newKeys.unshift(BI.deepClone(p[keys[keys.length - 1]])) : newKeys.unshift(BI.deepClone(g)); |
|
var backup = self.similar.apply(self, newKeys); |
|
keys.length > 1 ? (p[copy] = backup, self[sset](keys[0], g, {silent: true})) : self[sset](copy, backup, {silent: true}); |
|
keys.unshift(copy); |
|
!BI.has(self._tmp, keys[0]) && self.parent && self.parent._change(self); |
|
self.duplicate.apply(self, keys); |
|
self.trigger("duplicate", keys); |
|
}); |
|
}, |
|
|
|
removeChild: function (name, child) { |
|
if (BI.isArray(this._childs[name])) { |
|
BI.remove(this._childs[name], child); |
|
if (BI.isEmpty(this._childs[name])) { |
|
delete this._childs[name]; |
|
} |
|
return; |
|
} |
|
delete this._childs[name]; |
|
}, |
|
|
|
has: function (attr, istemp) { |
|
if (istemp === true) { |
|
return _.has(this.tmp, attr); |
|
} |
|
if (this._start === true && this._changing_ === false) { |
|
this._hass[attr] = true; |
|
} |
|
return BI.Model.superclass.has.apply(this, arguments); |
|
}, |
|
|
|
cat: function (attr) { |
|
if (_.has(this._tmp, attr)) { |
|
return this._tmp[attr]; |
|
} |
|
if (this._start === true && this._hass[attr]) { |
|
delete this._hass[attr]; |
|
switch (attr) { |
|
case "default": |
|
break; |
|
case "current": |
|
break; |
|
default : |
|
this._gets.push(attr); |
|
break; |
|
} |
|
} |
|
if (_.has(this.attributes, attr)) { |
|
return this.attributes[attr]; |
|
} |
|
var sta = _.result(this, "_static"); |
|
return BI.isFunction(sta[attr]) ? sta[attr].apply(this, BI.values(arguments).slice(1)) : sta[attr]; |
|
}, |
|
|
|
get: function () { |
|
return BI.deepClone(this.cat.apply(this, arguments)); |
|
}, |
|
|
|
set: function (key, val, options) { |
|
if (this._start === true || this._changing_ === true) { |
|
this._F.push({f: this.set, arg: arguments}); |
|
return this; |
|
} |
|
return BI.Model.superclass.set.apply(this, arguments); |
|
}, |
|
|
|
unset: function (attr, options) { |
|
var self = this; |
|
BI.each(this._childs, function (key, model) { |
|
key = key + ""; |
|
var keys = key.split('.'); |
|
if (_.isEqual(attr, keys[0])) { |
|
delete self._childs[attr]; |
|
if (!BI.isArray(model)) { |
|
model = [model]; |
|
} |
|
BI.each(model, function (i, m) { |
|
m.trigger("unset"); |
|
}); |
|
} |
|
}); |
|
return BI.Model.superclass.unset.apply(this, arguments); |
|
}, |
|
|
|
tmp: function (key, val, options) { |
|
if (this._start === true || this._changing_ === true) { |
|
this._F.push({f: this.tmp, arg: arguments}); |
|
return this; |
|
} |
|
var attr, attrs, unset, changes, silent, changing, changed, prev, current; |
|
if (key == null) return this; |
|
if (typeof key === 'object') { |
|
attrs = key; |
|
options = val; |
|
} else { |
|
(attrs = {})[key] = val; |
|
} |
|
options || (options = {}); |
|
|
|
unset = options.unset; |
|
silent = options.silent; |
|
changes = []; |
|
changing = this._changingTmp; |
|
this._changingTmp = true; |
|
|
|
if (!changing) { |
|
this._previousTmp = _.clone(this._tmp); |
|
this.changedTmp = {}; |
|
} |
|
if (!this._previousTmp) { |
|
this._previousTmp = _.clone(this._tmp); |
|
} |
|
current = this._tmp, prev = this._previousTmp; |
|
|
|
for (attr in attrs) { |
|
val = attrs[attr]; |
|
if (!_.isEqual(current[attr], val)) changes.push(attr); |
|
if (!_.isEqual(prev[attr], val)) { |
|
this.changedTmp[attr] = val; |
|
} else { |
|
delete this.changedTmp[attr]; |
|
} |
|
unset ? delete current[attr] : current[attr] = val; |
|
} |
|
|
|
if (!silent) { |
|
if (changes.length) this._pendingTmp = options; |
|
for (var i = 0, length = changes.length; i < length; i++) { |
|
this.trigger('change:' + changes[i], this, current[changes[i]], options); |
|
} |
|
} |
|
|
|
if (changing) return this; |
|
changed = BI.clone(this.changedTmp); |
|
if (!silent) { |
|
while (this._pendingTmp) { |
|
options = this._pendingTmp; |
|
this._pendingTmp = false; |
|
this.trigger('change', changed, prev, this, options); |
|
} |
|
} |
|
this._pendingTmp = false; |
|
this._changingTmp = false; |
|
if (!silent && changes.length) this.trigger("changed", changed, prev, this, options); |
|
return this; |
|
}, |
|
|
|
untmp: function (attr, options) { |
|
var self = this; |
|
BI.each(this._childs, function (key, model) { |
|
key = key + ""; |
|
var keys = key.split('.'); |
|
if (_.isEqual(attr, keys[0])) { |
|
delete self._childs[attr]; |
|
if (!BI.isArray(model)) { |
|
model = [model]; |
|
} |
|
BI.each(model, function (i, m) { |
|
m.trigger("unset"); |
|
}); |
|
} |
|
}); |
|
return this.tmp(attr, void 0, _.extend({}, options, {unset: true})); |
|
}, |
|
|
|
cancel: function (options) { |
|
var self = this; |
|
var tmp = BI.clone(this._tmp); |
|
this._tmp = {}; |
|
BI.each(tmp, function (k) { |
|
self.untmp(k, options); |
|
}); |
|
}, |
|
|
|
submit: function () { |
|
var tmp = BI.clone(this._tmp); |
|
this._tmp = {}; |
|
this.set(tmp); |
|
return this; |
|
}, |
|
|
|
urlRoot: function () { |
|
return BI.servletURL; |
|
}, |
|
|
|
parse: function (data) { |
|
return data; |
|
}, |
|
|
|
setEditing: function (edit) { |
|
this._editing = edit; |
|
}, |
|
|
|
getEditing: function () { |
|
if (this._start !== true) { |
|
throw new Error("getEditing函数只允许在local中调用"); |
|
} |
|
return this._editing; |
|
}, |
|
|
|
local: function () { |
|
|
|
}, |
|
|
|
load: function (data) { |
|
|
|
}, |
|
|
|
refresh: function () { |
|
|
|
}, |
|
|
|
/** |
|
* 更新整个model |
|
*/ |
|
updateURL: function () { |
|
|
|
}, |
|
/** |
|
* 添加一个元素或删除一个元素或修改一个元素 |
|
*/ |
|
patchURL: function () { |
|
|
|
}, |
|
/** |
|
* 删除整个model, destroy方法调用 |
|
*/ |
|
deleteURL: function () { |
|
|
|
}, |
|
/** |
|
* 读取model |
|
*/ |
|
readURL: function () { |
|
|
|
}, |
|
|
|
read: function (options) { |
|
if (this._start == true || this._changing_ === true) { |
|
this._F.push({f: this.read, arg: arguments}); |
|
return; |
|
} |
|
this._read(options); |
|
}, |
|
|
|
update: function (options) { |
|
if (this._start == true || this._changing_ === true) { |
|
this._F.push({f: this.update, arg: arguments}); |
|
return; |
|
} |
|
this._save(null, options); |
|
}, |
|
|
|
patch: function (options) { |
|
if (this._start == true || this._changing_ === true) { |
|
this._F.push({f: this.patch, arg: arguments}); |
|
return; |
|
} |
|
this._save(null, BI.extend({}, options, { |
|
patch: true |
|
})); |
|
} |
|
}); |