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);

posted on 2014-06-26 09:43 koradji 阅读(140) 评论(0)  编辑  收藏


只有注册用户登录后才能发表评论。


网站导航:
 
<2025年1月>
2930311234
567891011
12131415161718
19202122232425
2627282930311
2345678

导航

统计

常用链接

留言簿(2)

随笔分类

随笔档案

文章分类

文章档案

收藏夹

db2

dos

Groovy

Hibernate

java

WAS

web application

搜索

最新评论

阅读排行榜

评论排行榜