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);
// 遍歷并執行"all"事件中的回調函數列表
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); //調子類方法
}
_.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變量用于存儲模型的默認數據
var defaults;
// 如果沒有指定attributes參數, 則設置attributes為空對象
attributes || ( attributes = {});
if(options && options.parse)
attributes = this.parse(attributes);
if( defaults = getValue(this, 'defaults')) {
// 如果Model在定義時設置了defaults默認數據, 則初始化數據使用defaults與attributes參數合并后的數據(attributes中的數據會覆蓋defaults中的同名數據)
attributes = _.extend({}, defaults, attributes);
}
// attributes屬性存儲了當前模型的JSON對象化數據, 創建模型時默認為空
this.attributes = {};
// 定義_escapedAttributes緩存對象, 它將緩存通過escape方法處理過的數據
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() {
},
// 根據attr屬性名, 獲取模型中的數據值
get : function(attr) {
return this.attributes[attr];
},
// 設置模型中的數據, 如果key值不存在, 則作為新的屬性添加到模型, 如果key值已經存在, 則修改為新的值
set : function(key, value, options) {
// attrs變量中記錄需要設置的數據對象
var attrs, attr, val;
// 參數形式允許key-value對象形式, 或通過key, value兩個參數進行單獨設置
// 如果key是一個對象, 則認定為使用對象形式設置, 第二個參數將被視為options參數
if(_.isObject(key) || key == null) {
attrs = key;
options = value;
} else {
// 通過key, value兩個參數單獨設置, 將數據放到attrs對象中方便統一處理
attrs = {};
attrs[key] = value;
}
// options配置項必須是一個對象, 如果沒有設置options則默認值為一個空對象
options || ( options = {});
// 沒有設置參數時不執行任何動作
if(!attrs)
return this;
// Check for changes of `id`.
if(this.idAttribute in attrs)
this.id = attrs[this.idAttribute];
var changes = options.changes = {};
// now記錄當前模型中的數據對象
var now = this.attributes;
// escaped記錄當前模型中通過escape緩存過的數據
var escaped = this._escapedAttributes;
var prev = this._previousAttributes || {};
// For each `set` attribute...
// 遍歷需要設置的數據對象
for(attr in attrs) {
// attr存儲當前屬性名稱, val存儲當前屬性的值
val = attrs[attr];
// 如果當前數據在模型中不存在, 或已經發生變化, 或在options中指定了unset屬性刪除, 則刪除該數據被換存在_escapedAttributes中的數據
// 以下代碼僅刪除通過escape緩存過的數據, 這是為了保證緩存中的數據與模型中的真實數據保持同步
if(!_.isEqual(now[attr], val) || (options.unset && _.has(now, attr))) {
delete escaped[attr];
(options.silent ? this._silent : changes)[attr] = true;
}
// 如果在options中設置了unset, 則從模型中刪除該數據(包括key)
// 如果沒有指定unset屬性, 則認為將新增或修改數據, 向模型的數據對象中加入新的數據
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是一個共享的空函數, 用于在調用inherits方法實現繼承時, 承載父類的原型鏈以便設置到子類原型中
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.
// 實現對象繼承的函數, 該函數內部使用inherits實現繼承, 請參考inherits函數
var extend = function(protoProps, classProps) {
var child = inherits(this, protoProps, classProps);
child.extend = this.extend;
return child;
};
// 獲取對象prop屬性的值, 如果prop屬性是一個函數, 則執行并返回該函數的返回值
var getValue = function(object, prop) {
// 如果object為空或object不存在prop屬性, 則返回null
if(!(object && object[prop]))
return null;
// 返回prop屬性值, 如果prop是一個函數, 則執行并返回該函數的返回值
return _.isFunction(object[prop]) ? object[prop]() : object[prop];
};
// Set up inheritance for the model, collection, and view.
// 為Model, Collection, Router和View類實現繼承機制
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);
// 遍歷并執行"all"事件中的回調函數列表
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); //調子類方法
}
_.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變量用于存儲模型的默認數據
var defaults;
// 如果沒有指定attributes參數, 則設置attributes為空對象
attributes || ( attributes = {});
if(options && options.parse)
attributes = this.parse(attributes);
if( defaults = getValue(this, 'defaults')) {
// 如果Model在定義時設置了defaults默認數據, 則初始化數據使用defaults與attributes參數合并后的數據(attributes中的數據會覆蓋defaults中的同名數據)
attributes = _.extend({}, defaults, attributes);
}
// attributes屬性存儲了當前模型的JSON對象化數據, 創建模型時默認為空
this.attributes = {};
// 定義_escapedAttributes緩存對象, 它將緩存通過escape方法處理過的數據
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() {
},
// 根據attr屬性名, 獲取模型中的數據值
get : function(attr) {
return this.attributes[attr];
},
// 設置模型中的數據, 如果key值不存在, 則作為新的屬性添加到模型, 如果key值已經存在, 則修改為新的值
set : function(key, value, options) {
// attrs變量中記錄需要設置的數據對象
var attrs, attr, val;
// 參數形式允許key-value對象形式, 或通過key, value兩個參數進行單獨設置
// 如果key是一個對象, 則認定為使用對象形式設置, 第二個參數將被視為options參數
if(_.isObject(key) || key == null) {
attrs = key;
options = value;
} else {
// 通過key, value兩個參數單獨設置, 將數據放到attrs對象中方便統一處理
attrs = {};
attrs[key] = value;
}
// options配置項必須是一個對象, 如果沒有設置options則默認值為一個空對象
options || ( options = {});
// 沒有設置參數時不執行任何動作
if(!attrs)
return this;
// Check for changes of `id`.
if(this.idAttribute in attrs)
this.id = attrs[this.idAttribute];
var changes = options.changes = {};
// now記錄當前模型中的數據對象
var now = this.attributes;
// escaped記錄當前模型中通過escape緩存過的數據
var escaped = this._escapedAttributes;
var prev = this._previousAttributes || {};
// For each `set` attribute...
// 遍歷需要設置的數據對象
for(attr in attrs) {
// attr存儲當前屬性名稱, val存儲當前屬性的值
val = attrs[attr];
// 如果當前數據在模型中不存在, 或已經發生變化, 或在options中指定了unset屬性刪除, 則刪除該數據被換存在_escapedAttributes中的數據
// 以下代碼僅刪除通過escape緩存過的數據, 這是為了保證緩存中的數據與模型中的真實數據保持同步
if(!_.isEqual(now[attr], val) || (options.unset && _.has(now, attr))) {
delete escaped[attr];
(options.silent ? this._silent : changes)[attr] = true;
}
// 如果在options中設置了unset, 則從模型中刪除該數據(包括key)
// 如果沒有指定unset屬性, 則認為將新增或修改數據, 向模型的數據對象中加入新的數據
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是一個共享的空函數, 用于在調用inherits方法實現繼承時, 承載父類的原型鏈以便設置到子類原型中
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.
// 實現對象繼承的函數, 該函數內部使用inherits實現繼承, 請參考inherits函數
var extend = function(protoProps, classProps) {
var child = inherits(this, protoProps, classProps);
child.extend = this.extend;
return child;
};
// 獲取對象prop屬性的值, 如果prop屬性是一個函數, 則執行并返回該函數的返回值
var getValue = function(object, prop) {
// 如果object為空或object不存在prop屬性, 則返回null
if(!(object && object[prop]))
return null;
// 返回prop屬性值, 如果prop是一個函數, 則執行并返回該函數的返回值
return _.isFunction(object[prop]) ? object[prop]() : object[prop];
};
// Set up inheritance for the model, collection, and view.
// 為Model, Collection, Router和View類實現繼承機制
Model.extend = View.extend = extend;
exports.View = View;
exports.Model = Model;
})(PackTools);