forked from fanruan/fineui
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.
518 lines
17 KiB
518 lines
17 KiB
/** |
|
* @class BI.View |
|
* @extends BI.V |
|
* @type {*|void|Object} |
|
*/ |
|
BI.View = BI.inherit(BI.V, { |
|
|
|
_init: function () { |
|
BI.View.superclass._init.apply(this, arguments); |
|
var self = this; |
|
this.listenTo(this.model, "change:current", function (obj, val) { |
|
if (BI.isNotNull(val) && val.length > 0) { |
|
this.refresh(val); |
|
} |
|
}).listenTo(this.model, "change", function (changed) { |
|
this.delegateEvents(); |
|
}).listenTo(this.model, "changed", function (changed, prev, context, options) { |
|
if (BI.has(changed, "current") && BI.size(changed) > 1) { |
|
throw new Error("refresh操作不能调用set操作"); |
|
} |
|
var notLocal = !BI.has(changed, "current") && !this.local() && this.notifyParent().notify(); |
|
this.model.actionEnd() && this.actionEnd(); |
|
this.model._changing_ = true; |
|
notLocal && !BI.isEmpty(changed) && this.change(changed, prev, context, options); |
|
this.model._changing_ = false; |
|
this.model.actionEnd() && this.actionEnd(); |
|
}).listenTo(this.model, "destroy", function () { |
|
this.destroy(); |
|
}).listenTo(this.model, "unset", function () { |
|
this.destroy(); |
|
}).listenTo(this.model, "splice", function (arg) { |
|
this.splice.apply(this, arg); |
|
}).listenTo(this.model, "duplicate", function (arg) { |
|
this.duplicate.apply(this, arg); |
|
}); |
|
this._F = []; |
|
var flatten = ["_init", "_defaultConfig", "_vessel", "_render", "getName", "listenEnd", "local", "refresh", "load", "change"]; |
|
flatten = BI.makeObject(flatten, true); |
|
BI.each(this.constructor.caller.caller.prototype, function (key) { |
|
if (flatten[key]) { |
|
return; |
|
} |
|
var f = self[key]; |
|
if (BI.isFunction(f)) { |
|
self[key] = BI.bind(function () { |
|
if (this.model._start === true) { |
|
this._F.push({f: f, arg: arguments}); |
|
return; |
|
} |
|
return f.apply(this, arguments); |
|
}, self); |
|
} |
|
}) |
|
}, |
|
|
|
change: function (changed, prev) { |
|
|
|
}, |
|
|
|
actionEnd: function () { |
|
var self = this; |
|
var _F = this._F.slice(0); |
|
this._F = []; |
|
BI.each(_F, function (i, f) { |
|
f.f.apply(self, f.arg); |
|
}); |
|
return this; |
|
}, |
|
|
|
delegateEvents: function (events) { |
|
if (!(events || (events = BI.deepClone(_.result(this, 'events'))))) return this; |
|
var delegateEventSplitter = /^(\S+)\s*(.*)$/; |
|
for (var key in events) { |
|
var method = events[key]; |
|
if (!_.isFunction(method)) method = this[events[key]]; |
|
if (!method) continue; |
|
var match = key.match(delegateEventSplitter); |
|
var ev = true; |
|
switch (match[1]) { |
|
case "draggable": |
|
break; |
|
case "droppable": |
|
break; |
|
case "sortable": |
|
break; |
|
case "resizable": |
|
break; |
|
case "hover": |
|
break; |
|
default : |
|
ev = false; |
|
break; |
|
} |
|
|
|
var off = new BI.OffList({ |
|
event: match[1] + '.delegateEvents' + this.cid |
|
}); |
|
|
|
var keys = match[2].split('.'); |
|
var handle = keys[1]; |
|
var bind = ev ? new BI.EventList({ |
|
event: match[1], |
|
handle: handle, |
|
callback: BI.bind(method, this) |
|
}) : new BI.ListenerList({ |
|
event: match[1] + '.delegateEvents' + this.cid, |
|
handle: handle, |
|
callback: BI.bind(method, this), |
|
context: this |
|
}); |
|
|
|
var list = []; |
|
if (this[keys[0]] && (this[keys[0]] instanceof $ || this[keys[0]].element instanceof $)) { |
|
list = [this[keys[0]]] |
|
delete events[key]; |
|
} else if (BI.isArray(this[keys[0]]) || BI.isPlainObject(this[keys[0]])) { |
|
list = this[keys[0]] |
|
delete events[key]; |
|
} |
|
off.populate(list); |
|
bind.populate(list); |
|
} |
|
return BI.View.superclass.delegateEvents.apply(this, [events]); |
|
}, |
|
|
|
_vessel: function () { |
|
this._cardLayouts = {}; |
|
this._cardLayouts[this.getName()] = new BI.CardLayout({ |
|
element: this |
|
}); |
|
var vessel = BI.createWidget(); |
|
this._cardLayouts[this.getName()].addCardByName(this.getName(), vessel); |
|
return vessel.element; |
|
}, |
|
|
|
_render: function (vessel) { |
|
return this; |
|
}, |
|
|
|
/** |
|
* 创建儿子所在容器 |
|
* @param key |
|
* @param vessel |
|
* @param options isLayer:是否是弹出层, defaultShowName:默认显示项 |
|
* @returns {BI.View} |
|
*/ |
|
addSubVessel: function (key, vessel, options) { |
|
options || (options = {}); |
|
this._cardLayouts || (this._cardLayouts = {}); |
|
var id = key + this.cid; |
|
options.isLayer && (vessel = BI.Layers.has(id) ? BI.Layers.get(id) : BI.Layers.create(id, vessel)); |
|
if (this._cardLayouts[key]) { |
|
options.defaultShowName && this._cardLayouts[key].setDefaultShowName(options.defaultShowName); |
|
this._cardLayouts[key].setElement(vessel) && this._cardLayouts[key].resize(); |
|
return this; |
|
} |
|
this._cardLayouts[key] = BI.createWidget({ |
|
type: "bi.card", |
|
element: vessel, |
|
defaultShowName: options.defaultShowName |
|
}); |
|
return this; |
|
}, |
|
|
|
removeSubVessel: function (key) { |
|
var self = this, id = key + this.cid; |
|
BI.Layers.remove(id); |
|
var cardNames = this._cardLayouts[key] && this._cardLayouts[key].getAllCardNames(); |
|
BI.each(cardNames, function (i, name) { |
|
delete self._cards[name]; |
|
}); |
|
this._cardLayouts[key] && this._cardLayouts[key].destroy(); |
|
return this; |
|
}, |
|
|
|
createView: function (url, modelData, viewData) { |
|
return BI.Factory.createView(url, this.get(url), modelData, viewData); |
|
}, |
|
|
|
/** |
|
* 跳转到指定的card |
|
* @param cardName |
|
*/ |
|
skipTo: function (cardName, layout, modelData, viewData, options) { |
|
if (this.model._start === true || this._changing_ === true) { |
|
this._F.push({f: this.skipTo, arg: arguments}); |
|
return this; |
|
} |
|
var self = this, isValid = BI.isKey(modelData), data = void 0; |
|
BI.isKey(layout) && (layout = layout + ""); |
|
layout = layout || this.getName(); |
|
options || (options = {}); |
|
if (isValid) { |
|
modelData = modelData + "";//避免modelData是数字 |
|
var keys = modelData.split('.'); |
|
BI.each(keys, function (i, k) { |
|
if (i === 0) { |
|
data = self.model.get(k) || {}; |
|
} else { |
|
data = data[k] || {}; |
|
} |
|
}); |
|
data.id = options.id || keys[keys.length - 1]; |
|
} else { |
|
data = modelData; |
|
} |
|
BI.extend(data, options.data); |
|
var action = options.action || new BI.ShowAction(); |
|
var cardLayout = this._cardLayouts[layout]; |
|
if (!cardLayout) { |
|
return this; |
|
} |
|
cardLayout.setVisible(true); |
|
if (BI.isKey(cardName) && !cardLayout.isCardExisted(cardName)) { |
|
var view = this.createView(this.rootURL + "/" + cardName, data, viewData); |
|
isValid && this.model.addChild(modelData, view.model); |
|
view.listenTo(view.model, "destroy", function () { |
|
delete self._cards[cardName]; |
|
cardLayout.deleteCardByName(cardName); |
|
if (cardLayout.isAllCardHide()) { |
|
cardLayout.setVisible(false); |
|
BI.Layers.hide(layout + self.cid); |
|
} |
|
}).listenTo(view.model, "unset", function () { |
|
delete self._cards[cardName]; |
|
cardLayout.deleteCardByName(cardName); |
|
}); |
|
cardLayout.addCardByName(cardName, view); |
|
this._cards || (this._cards = {}); |
|
this._cards[cardName] = view; |
|
data = {}; |
|
this.on("end:" + view.cid, function () { |
|
var isNew = false, t, keys; |
|
if (isValid) { |
|
keys = modelData.split('.'); |
|
BI.each(keys, function (i, k) { |
|
if (i === 0) { |
|
t = self.model.get(k) || (isNew = true); |
|
} else { |
|
t = t[k] || (isNew = true); |
|
} |
|
}); |
|
} |
|
if (isNew) { |
|
delete self._cards[cardName]; |
|
self.model.removeChild(modelData, view.model); |
|
cardLayout.deleteCardByName(cardName); |
|
view.destroy(); |
|
cardLayout.setVisible(false); |
|
} |
|
action.actionBack(view, null, function () { |
|
if (cardLayout.isAllCardHide()) { |
|
cardLayout.setVisible(false); |
|
BI.Layers.hide(layout + self.cid); |
|
} |
|
!isNew && (self.listenEnd.apply(self, isValid ? keys : [modelData]) !== false) && self.populate(); |
|
}) |
|
}).on("change:" + view.cid, _.bind(this.notifyParent, this)); |
|
} |
|
BI.isKey(cardName) && BI.Layers.show(layout + this.cid); |
|
cardLayout.showCardByName(cardName, action, function () { |
|
BI.isKey(cardName) && self._cards[cardName].populate(data, options); |
|
}); |
|
!BI.isKey(cardName) && BI.Layers.hide(layout + this.cid); |
|
return this._cards[cardName]; |
|
}, |
|
|
|
listenEnd: function (key1, key2, key3) { |
|
return this; |
|
}, |
|
|
|
/** |
|
* 告诉父亲我的操作结束了,后面的事情任由父亲处置 |
|
* @param force 强制下次再次进入该节点时不进行刷新操作, 默认执行刷新 |
|
* @returns {BI.View} |
|
*/ |
|
notifyParentEnd: function (force) { |
|
this.parent && this.parent.trigger("end:" + this.cid); |
|
this.trigger("end"); |
|
!force && this.notify(); |
|
return this; |
|
}, |
|
|
|
/** |
|
* 通知父亲我的数据发生了变化 |
|
*/ |
|
notifyParent: function () { |
|
this.parent && this.parent.notify().trigger("change:" + this.cid); |
|
return this; |
|
}, |
|
|
|
/** |
|
* 告诉Model数据改变了 |
|
*/ |
|
notify: function () { |
|
this.model.unset("current", {silent: true}); |
|
return this; |
|
}, |
|
|
|
getName: function () { |
|
return "VIEW" |
|
}, |
|
|
|
/** |
|
* 全局刷新 |
|
* @param current |
|
*/ |
|
refresh: function (current) { |
|
}, |
|
/** |
|
* 局部刷新 |
|
*/ |
|
local: function () { |
|
return false; |
|
}, |
|
|
|
load: function (data) { |
|
|
|
}, |
|
|
|
readData: function (force, options) { |
|
options || (options = {}); |
|
var self = this; |
|
var args = [].slice.call(arguments, 2); |
|
if (!force && this._readed === true) {//只从后台获取一次数据 |
|
callback(this.model.toJSON()); |
|
return; |
|
} |
|
//采用静默方式读数据,该数据变化不引起data的change事件触发 |
|
var success = options.success; |
|
this.read(BI.extend({ |
|
silent: true |
|
}, options, { |
|
success: function (data, model) { |
|
callback(data); |
|
!force && (self._readed = true); |
|
self.delegateEvents(); |
|
success && success(data, model); |
|
} |
|
})); |
|
function callback(data) { |
|
self.model.load(data); |
|
self.load(data); |
|
BI.each(args, function (i, arg) { |
|
if (BI.isFunction(arg)) { |
|
arg.apply(self, [data]); |
|
} |
|
}) |
|
} |
|
}, |
|
|
|
//处理model的通用方法 |
|
cat: function () { |
|
return this.model.cat.apply(this.model, arguments); |
|
}, |
|
|
|
get: function () { |
|
return this.model.get.apply(this.model, arguments); |
|
}, |
|
|
|
set: function () { |
|
return this.model.set.apply(this.model, arguments); |
|
}, |
|
|
|
has: function () { |
|
return this.model.has.apply(this.model, arguments); |
|
}, |
|
|
|
getEditing: function () { |
|
return this.model.getEditing(); |
|
}, |
|
|
|
read: function (options) { |
|
this.model.read(options) |
|
}, |
|
|
|
update: function (options) { |
|
this.model.update(options); |
|
}, |
|
|
|
patch: function (options) { |
|
this.model.patch(options); |
|
}, |
|
|
|
reading: function (options) { |
|
var self = this; |
|
var name = BI.UUID(); |
|
this.read(BI.extend({}, options, { |
|
beforeSend: function () { |
|
var loading = BI.createWidget({ |
|
type: 'bi.vertical', |
|
items: [{ |
|
type: "bi.layout", |
|
height: 30, |
|
cls: "loading-background" |
|
}], |
|
element: BI.Maskers.make(name, self) |
|
}); |
|
loading.setVisible(true); |
|
}, |
|
complete: function (data) { |
|
options.complete && options.complete(data); |
|
BI.Maskers.remove(name); |
|
} |
|
})); |
|
}, |
|
|
|
updating: function (options) { |
|
var self = this; |
|
var name = BI.UUID(); |
|
this.update(BI.extend({}, options, { |
|
noset: true, |
|
beforeSend: function () { |
|
var loading = BI.createWidget({ |
|
type: 'bi.vertical', |
|
items: [{ |
|
type: "bi.layout", |
|
height: 30, |
|
cls: "loading-background" |
|
}], |
|
element: BI.Maskers.make(name, self) |
|
}); |
|
loading.setVisible(true); |
|
}, |
|
complete: function (data) { |
|
options.complete && options.complete(data); |
|
BI.Maskers.remove(name); |
|
} |
|
})); |
|
}, |
|
|
|
patching: function (options) { |
|
var self = this; |
|
var name = BI.UUID(); |
|
this.patch(BI.extend({}, options, { |
|
noset: true, |
|
beforeSend: function () { |
|
var loading = BI.createWidget({ |
|
type: 'bi.vertical', |
|
items: [{ |
|
type: "bi.layout", |
|
height: 30, |
|
cls: "loading-background" |
|
}], |
|
element: BI.Maskers.make(name, self) |
|
}); |
|
loading.setVisible(true); |
|
}, |
|
complete: function (data) { |
|
options.complete && options.complete(data); |
|
BI.Maskers.remove(name); |
|
} |
|
})); |
|
}, |
|
|
|
populate: function (modelData, options) { |
|
var self = this; |
|
options || (options = {}); |
|
if (options.force === true) { |
|
this.notify(); |
|
} |
|
if (this._cardLayouts && this._cardLayouts[this.getName()]) { |
|
this._cardLayouts[this.getName()].showCardByName(this.getName()); |
|
} |
|
//BI.each(this._cardLayouts, function (key, layout) { |
|
// layout.showCardByName(layout.getDefaultShowName() || self.getName()); |
|
//}); |
|
//BI.each(this._cards, function (i, card) { |
|
// card.notify && card.notify(); |
|
//}); |
|
if (this._F.length > 0) { |
|
throw new Error("流程错误"); |
|
} |
|
if (options.force === true) { |
|
this.model.set(modelData, options).set({current: this.model.get("default")}); |
|
return; |
|
} |
|
if (options.force === false) { |
|
this.model.set(modelData); |
|
return; |
|
} |
|
var filter = BI.clone(modelData || {}); |
|
delete filter.id; |
|
var contains = BI.has(this.model.toJSON(), _.keys(filter)); |
|
var match = BI.isEmpty(filter) || (contains && this.model.matches(modelData)); |
|
if (match === true) { |
|
this.model.set({current: this.model.get("default")}); |
|
} else if (contains === false) { |
|
this.model.set(modelData); |
|
} else { |
|
this.model.set(modelData, options).set({current: this.model.get("default")}); |
|
} |
|
}, |
|
|
|
//删除子节点触发 |
|
splice: function (old, key1, key2, key3) { |
|
|
|
}, |
|
|
|
//复制子节点触发 |
|
duplicate: function (copy, key1, key2, key3) { |
|
|
|
}, |
|
|
|
destroy: function () { |
|
BI.each(this._cardLayouts, function (name, card) { |
|
card && card.destroy(); |
|
}); |
|
delete this._cardLayouts; |
|
delete this._cards; |
|
this.remove(); |
|
this.destroyed(); |
|
}, |
|
|
|
destroyed: function () { |
|
|
|
} |
|
}); |