cvm
;(function(exports) {
var slice = Array.prototype.slice;
var splice = Array.prototype.splice;
var eventSplitter = /\s+/;
var Events = {
on : function(events, callback, context) {
var calls, event, node, tail, list;
if(!callback)
return this;
events = events.split(eventSplitter);
calls = this._callbacks || (this._callbacks = {});
while( event = events.shift()) {
list = calls[event];
node = list ? list.tail : {};
node.next = tail = {};
node.context = context;
node.callback = callback;
calls[event] = {
tail : tail,
next : list ? list.next : node
};
}
return this;
},
off : function(events, callback, context) {
var event, calls, node, tail, cb, ctx;
if(!( calls = this._callbacks))
return;
if(!(events || callback || context)) {
delete this._callbacks;
return this;
}
events = events ? events.split(eventSplitter) : _.keys(calls);
while( event = events.shift()) {
node = calls[event];
delete calls[event];
if(!node || !(callback || context))
continue;
tail = node.tail;
while(( node = node.next) !== tail) {
cb = node.callback;
ctx = node.context;
if((callback && cb !== callback) || (context && ctx !== context)) {
this.on(event, cb, ctx);
}
}
}
return this;
},
trigger : function(events) {
var event, node, calls, tail, args, all, rest;
if(!( calls = this._callbacks))
return this;
all = calls.all;
events = events.split(eventSplitter);
rest = slice.call(arguments, 1);
while( event = events.shift()) {
if( node = calls[event]) {
tail = node.tail;
while(( node = node.next) !== tail) {
node.callback.apply(node.context || this, rest);
}
}
if( node = all) {
tail = node.tail;
args = [event].concat(rest);
// 遍歷并執(zhí)行"all"事件中的回調(diào)函數(shù)列表
while(( node = node.next) !== tail) {
node.callback.apply(node.context || this, args);
}
}
}
return this;
}
};
Events.bind = Events.on;
Events.unbind = Events.off;
var viewOptions = ['model','el', 'id', 'attributes', 'name']; //揀選錄入this的屬性
var View = function(options){
this.cid = _.uniqueId('view');
this._configure(options || {});
this.initialize.apply(this, arguments); //調(diào)子類方法
}
_.extend(View.prototype, Events, {
_configure : function(options) {
if(this.options)
options = _.extend({}, this.options, options);
for(var i = 0, l = viewOptions.length; i < l; i++) {
var attr = viewOptions[i];
if(options[attr])
this[attr] = options[attr];
}
this.options = options;
},
// initialization logic.
initialize : function() {
},
render : function() {
return this;
},
remove : function() {
this.el.remove();
return this;
},
getElement : function(privateElKey) {
if(!privateElKey){
return this.el;
}
return this[privateElKey];
},
hideBar : function(elementsKey, show) {
var i=0, len=elementsKey.length;
if(show){
for(i=0; i<len; i++){
this[elementsKey[i]].show();
}
}else{
for(i=0; i<len; i++){
this[elementsKey[i]].hide();
}
}
}
});
var Model = function(attributes, options){
// defaults變量用于存儲模型的默認數(shù)據(jù)
var defaults;
// 如果沒有指定attributes參數(shù), 則設置attributes為空對象
attributes || ( attributes = {});
if(options && options.parse)
attributes = this.parse(attributes);
if( defaults = getValue(this, 'defaults')) {
// 如果Model在定義時設置了defaults默認數(shù)據(jù), 則初始化數(shù)據(jù)使用defaults與attributes參數(shù)合并后的數(shù)據(jù)(attributes中的數(shù)據(jù)會覆蓋defaults中的同名數(shù)據(jù))
attributes = _.extend({}, defaults, attributes);
}
// attributes屬性存儲了當前模型的JSON對象化數(shù)據(jù), 創(chuàng)建模型時默認為空
this.attributes = {};
// 定義_escapedAttributes緩存對象, 它將緩存通過escape方法處理過的數(shù)據(jù)
this._escapedAttributes = {};
// 為每一個模型配置一個唯一標識
this.cid = _.uniqueId('c');
this.changed = {};
this._silent = {};
this._pending = {};
//
this.set(attributes, {
silent : true
});
// Reset change tracking.
this.changed = {};
this._silent = {};
this._pending = {};
this._previousAttributes = _.clone(this.attributes);
this.initialize.apply(this, arguments);
}
_.extend(Model.prototype, Events, {
idAttribute : 'id',
initialize : function() {
},
// 根據(jù)attr屬性名, 獲取模型中的數(shù)據(jù)值
get : function(attr) {
return this.attributes[attr];
},
// 設置模型中的數(shù)據(jù), 如果key值不存在, 則作為新的屬性添加到模型, 如果key值已經(jīng)存在, 則修改為新的值
set : function(key, value, options) {
// attrs變量中記錄需要設置的數(shù)據(jù)對象
var attrs, attr, val;
// 參數(shù)形式允許key-value對象形式, 或通過key, value兩個參數(shù)進行單獨設置
// 如果key是一個對象, 則認定為使用對象形式設置, 第二個參數(shù)將被視為options參數(shù)
if(_.isObject(key) || key == null) {
attrs = key;
options = value;
} else {
// 通過key, value兩個參數(shù)單獨設置, 將數(shù)據(jù)放到attrs對象中方便統(tǒng)一處理
attrs = {};
attrs[key] = value;
}
// options配置項必須是一個對象, 如果沒有設置options則默認值為一個空對象
options || ( options = {});
// 沒有設置參數(shù)時不執(zhí)行任何動作
if(!attrs)
return this;
// Check for changes of `id`.
if(this.idAttribute in attrs)
this.id = attrs[this.idAttribute];
var changes = options.changes = {};
// now記錄當前模型中的數(shù)據(jù)對象
var now = this.attributes;
// escaped記錄當前模型中通過escape緩存過的數(shù)據(jù)
var escaped = this._escapedAttributes;
var prev = this._previousAttributes || {};
// For each `set` attribute...
// 遍歷需要設置的數(shù)據(jù)對象
for(attr in attrs) {
// attr存儲當前屬性名稱, val存儲當前屬性的值
val = attrs[attr];
// 如果當前數(shù)據(jù)在模型中不存在, 或已經(jīng)發(fā)生變化, 或在options中指定了unset屬性刪除, 則刪除該數(shù)據(jù)被換存在_escapedAttributes中的數(shù)據(jù)
// 以下代碼僅刪除通過escape緩存過的數(shù)據(jù), 這是為了保證緩存中的數(shù)據(jù)與模型中的真實數(shù)據(jù)保持同步
if(!_.isEqual(now[attr], val) || (options.unset && _.has(now, attr))) {
delete escaped[attr];
(options.silent ? this._silent : changes)[attr] = true;
}
// 如果在options中設置了unset, 則從模型中刪除該數(shù)據(jù)(包括key)
// 如果沒有指定unset屬性, 則認為將新增或修改數(shù)據(jù), 向模型的數(shù)據(jù)對象中加入新的數(shù)據(jù)
options.unset ?
delete now[attr] : now[attr] = val;
if(!_.isEqual(prev[attr], val) || (_.has(now, attr) != _.has(prev, attr))) {
this.changed[attr] = val;
if(!options.silent)
this._pending[attr] = true;
} else {
delete this.changed[attr];
delete this._pending[attr];
}
}
if(!options.silent)
this.change(options);
return this;
},
unset : function(attr, options) {
(options || ( options = {})).unset = true;
return this.set(attr, null, options);
},
change : function(options) {
options || ( options = {});
var changing = this._changing;
this._changing = true;
// Silent changes become pending changes.
for(var attr in this._silent)
this._pending[attr] = true;
// Silent changes are triggered.
var changes = _.extend({}, options.changes, this._silent);
this._silent = {};
for(var attr in changes) {
this.trigger('change:' + attr, this, this.get(attr), options);
}
if(changing)
return this;
// Continue firing `"change"` events while there are pending changes.
while(!_.isEmpty(this._pending)) {
this._pending = {};
this.trigger('change', this, options);
// Pending and silent changes still remain.
for(var attr in this.changed) {
if(this._pending[attr] || this._silent[attr])
continue;
delete this.changed[attr];
}
this._previousAttributes = _.clone(this.attributes);
}
this._changing = false;
return this;
}
});
// ctor是一個共享的空函數(shù), 用于在調(diào)用inherits方法實現(xiàn)繼承時, 承載父類的原型鏈以便設置到子類原型中
var ctor = function() {
};
var inherits = function(parent, protoProps, staticProps) {
var child;
if(protoProps && protoProps.hasOwnProperty('constructor')) {
child = protoProps.constructor;
} else {
child = function() {
parent.apply(this, arguments);
};
}
_.extend(child, parent);
ctor.prototype = parent.prototype;
child.prototype = new ctor();
if(protoProps)
_.extend(child.prototype, protoProps);
if(staticProps)
_.extend(child, staticProps);
child.prototype.constructor = child;
child.__super__ = parent.prototype;
return child;
};
// The self-propagating extend function that Backbone classes use.
// 實現(xiàn)對象繼承的函數(shù), 該函數(shù)內(nèi)部使用inherits實現(xiàn)繼承, 請參考inherits函數(shù)
var extend = function(protoProps, classProps) {
var child = inherits(this, protoProps, classProps);
child.extend = this.extend;
return child;
};
// 獲取對象prop屬性的值, 如果prop屬性是一個函數(shù), 則執(zhí)行并返回該函數(shù)的返回值
var getValue = function(object, prop) {
// 如果object為空或object不存在prop屬性, 則返回null
if(!(object && object[prop]))
return null;
// 返回prop屬性值, 如果prop是一個函數(shù), 則執(zhí)行并返回該函數(shù)的返回值
return _.isFunction(object[prop]) ? object[prop]() : object[prop];
};
// Set up inheritance for the model, collection, and view.
// 為Model, Collection, Router和View類實現(xiàn)繼承機制
Model.extend = View.extend = extend;
exports.View = View;
exports.Model = Model;
})(PackTools);
var slice = Array.prototype.slice;
var splice = Array.prototype.splice;
var eventSplitter = /\s+/;
var Events = {
on : function(events, callback, context) {
var calls, event, node, tail, list;
if(!callback)
return this;
events = events.split(eventSplitter);
calls = this._callbacks || (this._callbacks = {});
while( event = events.shift()) {
list = calls[event];
node = list ? list.tail : {};
node.next = tail = {};
node.context = context;
node.callback = callback;
calls[event] = {
tail : tail,
next : list ? list.next : node
};
}
return this;
},
off : function(events, callback, context) {
var event, calls, node, tail, cb, ctx;
if(!( calls = this._callbacks))
return;
if(!(events || callback || context)) {
delete this._callbacks;
return this;
}
events = events ? events.split(eventSplitter) : _.keys(calls);
while( event = events.shift()) {
node = calls[event];
delete calls[event];
if(!node || !(callback || context))
continue;
tail = node.tail;
while(( node = node.next) !== tail) {
cb = node.callback;
ctx = node.context;
if((callback && cb !== callback) || (context && ctx !== context)) {
this.on(event, cb, ctx);
}
}
}
return this;
},
trigger : function(events) {
var event, node, calls, tail, args, all, rest;
if(!( calls = this._callbacks))
return this;
all = calls.all;
events = events.split(eventSplitter);
rest = slice.call(arguments, 1);
while( event = events.shift()) {
if( node = calls[event]) {
tail = node.tail;
while(( node = node.next) !== tail) {
node.callback.apply(node.context || this, rest);
}
}
if( node = all) {
tail = node.tail;
args = [event].concat(rest);
// 遍歷并執(zhí)行"all"事件中的回調(diào)函數(shù)列表
while(( node = node.next) !== tail) {
node.callback.apply(node.context || this, args);
}
}
}
return this;
}
};
Events.bind = Events.on;
Events.unbind = Events.off;
var viewOptions = ['model','el', 'id', 'attributes', 'name']; //揀選錄入this的屬性
var View = function(options){
this.cid = _.uniqueId('view');
this._configure(options || {});
this.initialize.apply(this, arguments); //調(diào)子類方法
}
_.extend(View.prototype, Events, {
_configure : function(options) {
if(this.options)
options = _.extend({}, this.options, options);
for(var i = 0, l = viewOptions.length; i < l; i++) {
var attr = viewOptions[i];
if(options[attr])
this[attr] = options[attr];
}
this.options = options;
},
// initialization logic.
initialize : function() {
},
render : function() {
return this;
},
remove : function() {
this.el.remove();
return this;
},
getElement : function(privateElKey) {
if(!privateElKey){
return this.el;
}
return this[privateElKey];
},
hideBar : function(elementsKey, show) {
var i=0, len=elementsKey.length;
if(show){
for(i=0; i<len; i++){
this[elementsKey[i]].show();
}
}else{
for(i=0; i<len; i++){
this[elementsKey[i]].hide();
}
}
}
});
var Model = function(attributes, options){
// defaults變量用于存儲模型的默認數(shù)據(jù)
var defaults;
// 如果沒有指定attributes參數(shù), 則設置attributes為空對象
attributes || ( attributes = {});
if(options && options.parse)
attributes = this.parse(attributes);
if( defaults = getValue(this, 'defaults')) {
// 如果Model在定義時設置了defaults默認數(shù)據(jù), 則初始化數(shù)據(jù)使用defaults與attributes參數(shù)合并后的數(shù)據(jù)(attributes中的數(shù)據(jù)會覆蓋defaults中的同名數(shù)據(jù))
attributes = _.extend({}, defaults, attributes);
}
// attributes屬性存儲了當前模型的JSON對象化數(shù)據(jù), 創(chuàng)建模型時默認為空
this.attributes = {};
// 定義_escapedAttributes緩存對象, 它將緩存通過escape方法處理過的數(shù)據(jù)
this._escapedAttributes = {};
// 為每一個模型配置一個唯一標識
this.cid = _.uniqueId('c');
this.changed = {};
this._silent = {};
this._pending = {};
//
this.set(attributes, {
silent : true
});
// Reset change tracking.
this.changed = {};
this._silent = {};
this._pending = {};
this._previousAttributes = _.clone(this.attributes);
this.initialize.apply(this, arguments);
}
_.extend(Model.prototype, Events, {
idAttribute : 'id',
initialize : function() {
},
// 根據(jù)attr屬性名, 獲取模型中的數(shù)據(jù)值
get : function(attr) {
return this.attributes[attr];
},
// 設置模型中的數(shù)據(jù), 如果key值不存在, 則作為新的屬性添加到模型, 如果key值已經(jīng)存在, 則修改為新的值
set : function(key, value, options) {
// attrs變量中記錄需要設置的數(shù)據(jù)對象
var attrs, attr, val;
// 參數(shù)形式允許key-value對象形式, 或通過key, value兩個參數(shù)進行單獨設置
// 如果key是一個對象, 則認定為使用對象形式設置, 第二個參數(shù)將被視為options參數(shù)
if(_.isObject(key) || key == null) {
attrs = key;
options = value;
} else {
// 通過key, value兩個參數(shù)單獨設置, 將數(shù)據(jù)放到attrs對象中方便統(tǒng)一處理
attrs = {};
attrs[key] = value;
}
// options配置項必須是一個對象, 如果沒有設置options則默認值為一個空對象
options || ( options = {});
// 沒有設置參數(shù)時不執(zhí)行任何動作
if(!attrs)
return this;
// Check for changes of `id`.
if(this.idAttribute in attrs)
this.id = attrs[this.idAttribute];
var changes = options.changes = {};
// now記錄當前模型中的數(shù)據(jù)對象
var now = this.attributes;
// escaped記錄當前模型中通過escape緩存過的數(shù)據(jù)
var escaped = this._escapedAttributes;
var prev = this._previousAttributes || {};
// For each `set` attribute...
// 遍歷需要設置的數(shù)據(jù)對象
for(attr in attrs) {
// attr存儲當前屬性名稱, val存儲當前屬性的值
val = attrs[attr];
// 如果當前數(shù)據(jù)在模型中不存在, 或已經(jīng)發(fā)生變化, 或在options中指定了unset屬性刪除, 則刪除該數(shù)據(jù)被換存在_escapedAttributes中的數(shù)據(jù)
// 以下代碼僅刪除通過escape緩存過的數(shù)據(jù), 這是為了保證緩存中的數(shù)據(jù)與模型中的真實數(shù)據(jù)保持同步
if(!_.isEqual(now[attr], val) || (options.unset && _.has(now, attr))) {
delete escaped[attr];
(options.silent ? this._silent : changes)[attr] = true;
}
// 如果在options中設置了unset, 則從模型中刪除該數(shù)據(jù)(包括key)
// 如果沒有指定unset屬性, 則認為將新增或修改數(shù)據(jù), 向模型的數(shù)據(jù)對象中加入新的數(shù)據(jù)
options.unset ?
delete now[attr] : now[attr] = val;
if(!_.isEqual(prev[attr], val) || (_.has(now, attr) != _.has(prev, attr))) {
this.changed[attr] = val;
if(!options.silent)
this._pending[attr] = true;
} else {
delete this.changed[attr];
delete this._pending[attr];
}
}
if(!options.silent)
this.change(options);
return this;
},
unset : function(attr, options) {
(options || ( options = {})).unset = true;
return this.set(attr, null, options);
},
change : function(options) {
options || ( options = {});
var changing = this._changing;
this._changing = true;
// Silent changes become pending changes.
for(var attr in this._silent)
this._pending[attr] = true;
// Silent changes are triggered.
var changes = _.extend({}, options.changes, this._silent);
this._silent = {};
for(var attr in changes) {
this.trigger('change:' + attr, this, this.get(attr), options);
}
if(changing)
return this;
// Continue firing `"change"` events while there are pending changes.
while(!_.isEmpty(this._pending)) {
this._pending = {};
this.trigger('change', this, options);
// Pending and silent changes still remain.
for(var attr in this.changed) {
if(this._pending[attr] || this._silent[attr])
continue;
delete this.changed[attr];
}
this._previousAttributes = _.clone(this.attributes);
}
this._changing = false;
return this;
}
});
// ctor是一個共享的空函數(shù), 用于在調(diào)用inherits方法實現(xiàn)繼承時, 承載父類的原型鏈以便設置到子類原型中
var ctor = function() {
};
var inherits = function(parent, protoProps, staticProps) {
var child;
if(protoProps && protoProps.hasOwnProperty('constructor')) {
child = protoProps.constructor;
} else {
child = function() {
parent.apply(this, arguments);
};
}
_.extend(child, parent);
ctor.prototype = parent.prototype;
child.prototype = new ctor();
if(protoProps)
_.extend(child.prototype, protoProps);
if(staticProps)
_.extend(child, staticProps);
child.prototype.constructor = child;
child.__super__ = parent.prototype;
return child;
};
// The self-propagating extend function that Backbone classes use.
// 實現(xiàn)對象繼承的函數(shù), 該函數(shù)內(nèi)部使用inherits實現(xiàn)繼承, 請參考inherits函數(shù)
var extend = function(protoProps, classProps) {
var child = inherits(this, protoProps, classProps);
child.extend = this.extend;
return child;
};
// 獲取對象prop屬性的值, 如果prop屬性是一個函數(shù), 則執(zhí)行并返回該函數(shù)的返回值
var getValue = function(object, prop) {
// 如果object為空或object不存在prop屬性, 則返回null
if(!(object && object[prop]))
return null;
// 返回prop屬性值, 如果prop是一個函數(shù), 則執(zhí)行并返回該函數(shù)的返回值
return _.isFunction(object[prop]) ? object[prop]() : object[prop];
};
// Set up inheritance for the model, collection, and view.
// 為Model, Collection, Router和View類實現(xiàn)繼承機制
Model.extend = View.extend = extend;
exports.View = View;
exports.Model = Model;
})(PackTools);