mirror of https://github.com/vuejs/vue.git
				
				
				
			rename internal, optimize memory usage for GC
This commit is contained in:
		
							parent
							
								
									aff965f353
								
							
						
					
					
						commit
						d78df31017
					
				| 
						 | 
					@ -6,8 +6,8 @@
 | 
				
			||||||
        "src/main.js",
 | 
					        "src/main.js",
 | 
				
			||||||
        "src/config.js",
 | 
					        "src/config.js",
 | 
				
			||||||
        "src/utils.js",
 | 
					        "src/utils.js",
 | 
				
			||||||
        "src/seed.js",
 | 
					        "src/compiler.js",
 | 
				
			||||||
        "src/scope.js",
 | 
					        "src/viewmodel.js",
 | 
				
			||||||
        "src/binding.js",
 | 
					        "src/binding.js",
 | 
				
			||||||
        "src/directive-parser.js",
 | 
					        "src/directive-parser.js",
 | 
				
			||||||
        "src/text-parser.js",
 | 
					        "src/text-parser.js",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,7 @@ Seed.controller('todos', {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // initializer, reserved
 | 
					    // initializer, reserved
 | 
				
			||||||
    init: function () {
 | 
					    init: function () {
 | 
				
			||||||
 | 
					        window.app = this
 | 
				
			||||||
        // listen for hashtag change
 | 
					        // listen for hashtag change
 | 
				
			||||||
        this.updateFilter()
 | 
					        this.updateFilter()
 | 
				
			||||||
        this.$on('filterchange', this.updateFilter.bind(this))
 | 
					        this.$on('filterchange', this.updateFilter.bind(this))
 | 
				
			||||||
| 
						 | 
					@ -29,9 +30,9 @@ Seed.controller('todos', {
 | 
				
			||||||
        return this.total - this.remaining
 | 
					        return this.total - this.remaining
 | 
				
			||||||
    }},
 | 
					    }},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // dynamic context computed property using info from target scope
 | 
					    // dynamic context computed property using info from target viewmodel
 | 
				
			||||||
    todoFiltered: {get: function (ctx) {
 | 
					    todoFiltered: {get: function (ctx) {
 | 
				
			||||||
        return filters[this.filter](ctx.scope)
 | 
					        return filters[this.filter]({ completed: ctx.vm.completed })
 | 
				
			||||||
    }},
 | 
					    }},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // dynamic context computed property using info from target element
 | 
					    // dynamic context computed property using info from target element
 | 
				
			||||||
| 
						 | 
					@ -45,10 +46,11 @@ Seed.controller('todos', {
 | 
				
			||||||
            return this.remaining === 0
 | 
					            return this.remaining === 0
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        set: function (value) {
 | 
					        set: function (value) {
 | 
				
			||||||
            this.remaining = value ? 0 : this.total
 | 
					 | 
				
			||||||
            this.todos.forEach(function (todo) {
 | 
					            this.todos.forEach(function (todo) {
 | 
				
			||||||
                todo.completed = value
 | 
					                todo.completed = value
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
 | 
					            this.remaining = value ? 0 : this.total
 | 
				
			||||||
 | 
					            todoStorage.save(this.todos)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -64,32 +66,32 @@ Seed.controller('todos', {
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    removeTodo: function (e) {
 | 
					    removeTodo: function (e) {
 | 
				
			||||||
        this.todos.remove(e.scope)
 | 
					        this.todos.remove(e.vm)
 | 
				
			||||||
        this.remaining -= e.scope.completed ? 0 : 1
 | 
					        this.remaining -= e.vm.completed ? 0 : 1
 | 
				
			||||||
        todoStorage.save(this.todos)
 | 
					        todoStorage.save(this.todos)
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    toggleTodo: function (e) {
 | 
					    toggleTodo: function (e) {
 | 
				
			||||||
        this.remaining += e.scope.completed ? -1 : 1
 | 
					        this.remaining += e.vm.completed ? -1 : 1
 | 
				
			||||||
        todoStorage.save(this.todos)
 | 
					        todoStorage.save(this.todos)
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    editTodo: function (e) {
 | 
					    editTodo: function (e) {
 | 
				
			||||||
        this.beforeEditCache = e.scope.title
 | 
					        this.beforeEditCache = e.vm.title
 | 
				
			||||||
        e.scope.editing = true
 | 
					        e.vm.editing = true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    doneEdit: function (e) {
 | 
					    doneEdit: function (e) {
 | 
				
			||||||
        if (!e.scope.editing) return
 | 
					        if (!e.vm.editing) return
 | 
				
			||||||
        e.scope.editing = false
 | 
					        e.vm.editing = false
 | 
				
			||||||
        e.scope.title = e.scope.title.trim()
 | 
					        e.vm.title = e.vm.title.trim()
 | 
				
			||||||
        if (!e.scope.title) this.removeTodo(e)
 | 
					        if (!e.vm.title) this.removeTodo(e)
 | 
				
			||||||
        todoStorage.save(this.todos)
 | 
					        todoStorage.save(this.todos)
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cancelEdit: function (e) {
 | 
					    cancelEdit: function (e) {
 | 
				
			||||||
        e.scope.editing = false
 | 
					        e.vm.editing = false
 | 
				
			||||||
        e.scope.title = this.beforeEditCache
 | 
					        e.vm.title = this.beforeEditCache
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    removeCompleted: function () {
 | 
					    removeCompleted: function () {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										112
									
								
								src/binding.js
								
								
								
								
							
							
						
						
									
										112
									
								
								src/binding.js
								
								
								
								
							| 
						 | 
					@ -5,17 +5,17 @@ var utils    = require('./utils'),
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  Binding class.
 | 
					 *  Binding class.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *  each property on the scope has one corresponding Binding object
 | 
					 *  each property on the viewmodel has one corresponding Binding object
 | 
				
			||||||
 *  which has multiple directive instances on the DOM
 | 
					 *  which has multiple directive instances on the DOM
 | 
				
			||||||
 *  and multiple computed property dependents
 | 
					 *  and multiple computed property dependents
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function Binding (seed, key) {
 | 
					function Binding (compiler, key) {
 | 
				
			||||||
    this.seed = seed
 | 
					    this.compiler = compiler
 | 
				
			||||||
    this.scope = seed.scope
 | 
					    this.vm = compiler.vm
 | 
				
			||||||
    this.key = key
 | 
					    this.key = key
 | 
				
			||||||
    var path = key.split('.')
 | 
					    var path = key.split('.')
 | 
				
			||||||
    this.inspect(utils.getNestedValue(seed.scope, path))
 | 
					    this.inspect(utils.getNestedValue(compiler.vm, path))
 | 
				
			||||||
    this.def(seed.scope, path)
 | 
					    this.def(compiler.vm, path)
 | 
				
			||||||
    this.instances = []
 | 
					    this.instances = []
 | 
				
			||||||
    this.subs = []
 | 
					    this.subs = []
 | 
				
			||||||
    this.deps = []
 | 
					    this.deps = []
 | 
				
			||||||
| 
						 | 
					@ -27,85 +27,82 @@ var BindingProto = Binding.prototype
 | 
				
			||||||
 *  Pre-process a passed in value based on its type
 | 
					 *  Pre-process a passed in value based on its type
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
BindingProto.inspect = function (value) {
 | 
					BindingProto.inspect = function (value) {
 | 
				
			||||||
    var type = utils.typeOf(value),
 | 
					    var type = utils.typeOf(value)
 | 
				
			||||||
        self = this
 | 
					 | 
				
			||||||
    // preprocess the value depending on its type
 | 
					    // preprocess the value depending on its type
 | 
				
			||||||
    if (type === 'Object') {
 | 
					    if (type === 'Object') {
 | 
				
			||||||
        if (value.get) {
 | 
					        if (value.get) {
 | 
				
			||||||
            var l = Object.keys(value).length
 | 
					            var l = Object.keys(value).length
 | 
				
			||||||
            if (l === 1 || (l === 2 && value.set)) {
 | 
					            if (l === 1 || (l === 2 && value.set)) {
 | 
				
			||||||
                self.isComputed = true // computed property
 | 
					                this.isComputed = true // computed property
 | 
				
			||||||
                value.get = value.get.bind(self.scope)
 | 
					                this.rawGet = value.get
 | 
				
			||||||
                if (value.set) value.set = value.set.bind(self.scope)
 | 
					                value.get = value.get.bind(this.vm)
 | 
				
			||||||
 | 
					                if (value.set) value.set = value.set.bind(this.vm)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else if (type === 'Array') {
 | 
					    } else if (type === 'Array') {
 | 
				
			||||||
 | 
					        value = utils.dump(value)
 | 
				
			||||||
        utils.watchArray(value)
 | 
					        utils.watchArray(value)
 | 
				
			||||||
        value.on('mutate', function () {
 | 
					        value.on('mutate', this.pub.bind(this))
 | 
				
			||||||
            self.pub()
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    self.value = value
 | 
					    this.value = value
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  Define getter/setter for this binding on scope
 | 
					 *  Define getter/setter for this binding on viewmodel
 | 
				
			||||||
 *  recursive for nested objects
 | 
					 *  recursive for nested objects
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
BindingProto.def = function (scope, path) {
 | 
					BindingProto.def = function (viewmodel, path) {
 | 
				
			||||||
    var self = this,
 | 
					    var key = path[0]
 | 
				
			||||||
        seed = self.seed,
 | 
					 | 
				
			||||||
        key = path[0]
 | 
					 | 
				
			||||||
    if (path.length === 1) {
 | 
					    if (path.length === 1) {
 | 
				
			||||||
        // here we are! at the end of the path!
 | 
					        // here we are! at the end of the path!
 | 
				
			||||||
        // define the real value accessors.
 | 
					        // define the real value accessors.
 | 
				
			||||||
        def(scope, key, {
 | 
					        def(viewmodel, key, {
 | 
				
			||||||
            get: function () {
 | 
					            get: (function () {
 | 
				
			||||||
                if (observer.isObserving) {
 | 
					                if (observer.isObserving) {
 | 
				
			||||||
                    observer.emit('get', self)
 | 
					                    observer.emit('get', this)
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                return self.isComputed
 | 
					                return this.isComputed
 | 
				
			||||||
                    ? self.value.get({
 | 
					                    ? this.value.get({
 | 
				
			||||||
                        el: seed.el,
 | 
					                        el: this.compiler.el,
 | 
				
			||||||
                        scope: seed.scope
 | 
					                        vm: this.compiler.vm
 | 
				
			||||||
                    })
 | 
					                    })
 | 
				
			||||||
                    : self.value
 | 
					                    : this.value
 | 
				
			||||||
            },
 | 
					            }).bind(this),
 | 
				
			||||||
            set: function (value) {
 | 
					            set: (function (value) {
 | 
				
			||||||
                if (self.isComputed) {
 | 
					                if (this.isComputed) {
 | 
				
			||||||
                    // computed properties cannot be redefined
 | 
					                    // computed properties cannot be redefined
 | 
				
			||||||
                    // no need to call binding.update() here,
 | 
					                    // no need to call binding.update() here,
 | 
				
			||||||
                    // as dependency extraction has taken care of that
 | 
					                    // as dependency extraction has taken care of that
 | 
				
			||||||
                    if (self.value.set) {
 | 
					                    if (this.value.set) {
 | 
				
			||||||
                        self.value.set(value)
 | 
					                        this.value.set(value)
 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                } else if (value !== self.value) {
 | 
					 | 
				
			||||||
                    self.update(value)
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					                } else if (value !== this.value) {
 | 
				
			||||||
 | 
					                    this.update(value)
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					            }).bind(this)
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        // we are not there yet!!!
 | 
					        // we are not there yet!!!
 | 
				
			||||||
        // create an intermediate subscope
 | 
					        // create an intermediate object
 | 
				
			||||||
        // which also has its own getter/setters
 | 
					        // which also has its own getter/setters
 | 
				
			||||||
        var subScope = scope[key]
 | 
					        var nestedObject = viewmodel[key]
 | 
				
			||||||
        if (!subScope) {
 | 
					        if (!nestedObject) {
 | 
				
			||||||
            subScope = {}
 | 
					            nestedObject = {}
 | 
				
			||||||
            def(scope, key, {
 | 
					            def(viewmodel, key, {
 | 
				
			||||||
                get: function () {
 | 
					                get: (function () {
 | 
				
			||||||
                    return subScope
 | 
					                    return this
 | 
				
			||||||
                },
 | 
					                }).bind(nestedObject),
 | 
				
			||||||
                set: function (value) {
 | 
					                set: (function (value) {
 | 
				
			||||||
                    // when the subScope is given a new value,
 | 
					                    // when the nestedObject is given a new value,
 | 
				
			||||||
                    // copy everything over to trigger the setters
 | 
					                    // copy everything over to trigger the setters
 | 
				
			||||||
                    for (var prop in value) {
 | 
					                    for (var prop in value) {
 | 
				
			||||||
                        subScope[prop] = value[prop]
 | 
					                        this[prop] = value[prop]
 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					                }).bind(nestedObject)
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        // recurse
 | 
					        // recurse
 | 
				
			||||||
        this.def(subScope, path.slice(1))
 | 
					        this.def(nestedObject, path.slice(1))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -116,7 +113,7 @@ BindingProto.update = function (value) {
 | 
				
			||||||
    this.inspect(value)
 | 
					    this.inspect(value)
 | 
				
			||||||
    var i = this.instances.length
 | 
					    var i = this.instances.length
 | 
				
			||||||
    while (i--) {
 | 
					    while (i--) {
 | 
				
			||||||
        this.instances[i].update(value)
 | 
					        this.instances[i].update(this.value)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    this.pub()
 | 
					    this.pub()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -132,6 +129,21 @@ BindingProto.refresh = function () {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BindingProto.unbind = function () {
 | 
				
			||||||
 | 
					    var i = this.instances.length
 | 
				
			||||||
 | 
					    while (i--) {
 | 
				
			||||||
 | 
					        this.instances[i].unbind()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    i = this.deps.length
 | 
				
			||||||
 | 
					    var subs
 | 
				
			||||||
 | 
					    while (i--) {
 | 
				
			||||||
 | 
					        subs = this.deps[i].subs
 | 
				
			||||||
 | 
					        subs.splice(subs.indexOf(this), 1)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (Array.isArray(this.value)) this.value.off('mutate')
 | 
				
			||||||
 | 
					    this.vm = this.compiler = this.pubs = this.subs = this.instances = null
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  Notify computed properties that depend on this binding
 | 
					 *  Notify computed properties that depend on this binding
 | 
				
			||||||
 *  to update themselves
 | 
					 *  to update themselves
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
var config          = require('./config'),
 | 
					var config          = require('./config'),
 | 
				
			||||||
    Scope           = require('./scope'),
 | 
					    ViewModel       = require('./viewmodel'),
 | 
				
			||||||
    Binding         = require('./binding'),
 | 
					    Binding         = require('./binding'),
 | 
				
			||||||
    DirectiveParser = require('./directive-parser'),
 | 
					    DirectiveParser = require('./directive-parser'),
 | 
				
			||||||
    TextParser      = require('./text-parser'),
 | 
					    TextParser      = require('./text-parser'),
 | 
				
			||||||
| 
						 | 
					@ -11,26 +11,26 @@ var slice           = Array.prototype.slice,
 | 
				
			||||||
    eachAttr        = config.prefix + '-each'
 | 
					    eachAttr        = config.prefix + '-each'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  The main ViewModel class
 | 
					 *  The DOM compiler
 | 
				
			||||||
 *  scans a node and parse it to populate data bindings
 | 
					 *  scans a DOM node and compile bindings for a ViewModel
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function Seed (el, options) {
 | 
					function Compiler (el, options) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
    config.log('\ncreated new Seed instance.\n')
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    config.log('\ncreated new Compiler instance.\n')
 | 
				
			||||||
    if (typeof el === 'string') {
 | 
					    if (typeof el === 'string') {
 | 
				
			||||||
        el = document.querySelector(el)
 | 
					        el = document.querySelector(el)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.el              = el
 | 
					    this.el              = el
 | 
				
			||||||
    el.seed               = this
 | 
					    el.compiler          = this
 | 
				
			||||||
    this._bindings        = {}
 | 
					    this.bindings        = {}
 | 
				
			||||||
    this._watchers        = {}
 | 
					    this.directives      = []
 | 
				
			||||||
    this._listeners       = []
 | 
					    this.watchers        = {}
 | 
				
			||||||
 | 
					    this.listeners       = []
 | 
				
			||||||
    // list of computed properties that need to parse dependencies for
 | 
					    // list of computed properties that need to parse dependencies for
 | 
				
			||||||
    this._computed        = []
 | 
					    this.computed        = []
 | 
				
			||||||
    // list of bindings that has dynamic context dependencies
 | 
					    // list of bindings that has dynamic context dependencies
 | 
				
			||||||
    this._contextBindings = []
 | 
					    this.contextBindings = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // copy options
 | 
					    // copy options
 | 
				
			||||||
    options = options || {}
 | 
					    options = options || {}
 | 
				
			||||||
| 
						 | 
					@ -48,71 +48,71 @@ function Seed (el, options) {
 | 
				
			||||||
    data = data || {}
 | 
					    data = data || {}
 | 
				
			||||||
    el.removeAttribute(dataAttr)
 | 
					    el.removeAttribute(dataAttr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // if the passed in data is the scope of a Seed instance,
 | 
					    // if the passed in data is the viewmodel of a Compiler instance,
 | 
				
			||||||
    // make a copy from it
 | 
					    // make a copy from it
 | 
				
			||||||
    if (data.$seed instanceof Seed) {
 | 
					    if (data instanceof ViewModel) {
 | 
				
			||||||
        data = data.$dump()
 | 
					        data = data.$dump()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // check if there is a controller associated with this seed
 | 
					    // check if there is a controller associated with this compiler
 | 
				
			||||||
    var ctrlID = el.getAttribute(ctrlAttr), controller
 | 
					    var ctrlID = el.getAttribute(ctrlAttr), controller
 | 
				
			||||||
    if (ctrlID) {
 | 
					    if (ctrlID) {
 | 
				
			||||||
        el.removeAttribute(ctrlAttr)
 | 
					        el.removeAttribute(ctrlAttr)
 | 
				
			||||||
        controller = config.controllers[ctrlID]
 | 
					        controller = config.controllers[ctrlID]
 | 
				
			||||||
        if (controller) {
 | 
					        if (controller) {
 | 
				
			||||||
            this._controller = controller
 | 
					            this.controller = controller
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            config.warn('controller "' + ctrlID + '" is not defined.')
 | 
					            config.warn('controller "' + ctrlID + '" is not defined.')
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // create the scope object
 | 
					    // create the viewmodel object
 | 
				
			||||||
    // if the controller has an extended scope contructor, use it;
 | 
					    // if the controller has an extended viewmodel contructor, use it;
 | 
				
			||||||
    // otherwise, use the original scope constructor.
 | 
					    // otherwise, use the original viewmodel constructor.
 | 
				
			||||||
    var ScopeConstructor = (controller && controller.ExtendedScope) || Scope,
 | 
					    var VMCtor = (controller && controller.ExtendedVM) || ViewModel,
 | 
				
			||||||
        scope = this.scope = new ScopeConstructor(this, options)
 | 
					        viewmodel = this.vm = new VMCtor(this, options)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // copy data
 | 
					    // copy data
 | 
				
			||||||
    for (var key in data) {
 | 
					    for (var key in data) {
 | 
				
			||||||
        scope[key] = data[key]
 | 
					        viewmodel[key] = data[key]
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // apply controller initialize function
 | 
					    // apply controller initialize function
 | 
				
			||||||
    if (controller && controller.init) {
 | 
					    if (controller && controller.init) {
 | 
				
			||||||
        controller.init.call(scope)
 | 
					        controller.init.call(viewmodel)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // now parse the DOM
 | 
					    // now parse the DOM
 | 
				
			||||||
    this._compileNode(el, true)
 | 
					    this.compileNode(el, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // for anything in scope but not binded in DOM, create bindings for them
 | 
					    // for anything in viewmodel but not binded in DOM, create bindings for them
 | 
				
			||||||
    for (key in scope) {
 | 
					    for (key in viewmodel) {
 | 
				
			||||||
        if (key.charAt(0) !== '$' && !this._bindings[key]) {
 | 
					        if (key.charAt(0) !== '$' && !this.bindings[key]) {
 | 
				
			||||||
            this._createBinding(key)
 | 
					            this.createBinding(key)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // extract dependencies for computed properties
 | 
					    // extract dependencies for computed properties
 | 
				
			||||||
    if (this._computed.length) depsParser.parse(this._computed)
 | 
					    if (this.computed.length) depsParser.parse(this.computed)
 | 
				
			||||||
    delete this._computed
 | 
					    this.computed = null
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // extract dependencies for computed properties with dynamic context
 | 
					    // extract dependencies for computed properties with dynamic context
 | 
				
			||||||
    if (this._contextBindings.length) this._bindContexts(this._contextBindings)
 | 
					    if (this.contextBindings.length) this.bindContexts(this.contextBindings)
 | 
				
			||||||
    delete this._contextBindings
 | 
					    this.contextBindings = null
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// for better compression
 | 
					// for better compression
 | 
				
			||||||
var SeedProto = Seed.prototype
 | 
					var CompilerProto = Compiler.prototype
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  Compile a DOM node (recursive)
 | 
					 *  Compile a DOM node (recursive)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
SeedProto._compileNode = function (node, root) {
 | 
					CompilerProto.compileNode = function (node, root) {
 | 
				
			||||||
    var seed = this
 | 
					    var compiler = this
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (node.nodeType === 3) { // text node
 | 
					    if (node.nodeType === 3) { // text node
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        seed._compileTextNode(node)
 | 
					        compiler.compileTextNode(node)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    } else if (node.nodeType === 1) {
 | 
					    } else if (node.nodeType === 1) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -125,14 +125,14 @@ SeedProto._compileNode = function (node, root) {
 | 
				
			||||||
            directive = DirectiveParser.parse(eachAttr, eachExp)
 | 
					            directive = DirectiveParser.parse(eachAttr, eachExp)
 | 
				
			||||||
            if (directive) {
 | 
					            if (directive) {
 | 
				
			||||||
                directive.el = node
 | 
					                directive.el = node
 | 
				
			||||||
                seed._bind(directive)
 | 
					                compiler.bindDirective(directive)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        } else if (ctrlExp && !root) { // nested controllers
 | 
					        } else if (ctrlExp && !root) { // nested controllers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            new Seed(node, {
 | 
					            new Compiler(node, {
 | 
				
			||||||
                child: true,
 | 
					                child: true,
 | 
				
			||||||
                parentSeed: seed
 | 
					                parentCompiler: compiler
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        } else { // normal node
 | 
					        } else { // normal node
 | 
				
			||||||
| 
						 | 
					@ -153,7 +153,7 @@ SeedProto._compileNode = function (node, root) {
 | 
				
			||||||
                        if (directive) {
 | 
					                        if (directive) {
 | 
				
			||||||
                            valid = true
 | 
					                            valid = true
 | 
				
			||||||
                            directive.el = node
 | 
					                            directive.el = node
 | 
				
			||||||
                            seed._bind(directive)
 | 
					                            compiler.bindDirective(directive)
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    if (valid) node.removeAttribute(attr.name)
 | 
					                    if (valid) node.removeAttribute(attr.name)
 | 
				
			||||||
| 
						 | 
					@ -162,7 +162,7 @@ SeedProto._compileNode = function (node, root) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // recursively compile childNodes
 | 
					            // recursively compile childNodes
 | 
				
			||||||
            if (node.childNodes.length) {
 | 
					            if (node.childNodes.length) {
 | 
				
			||||||
                slice.call(node.childNodes).forEach(seed._compileNode, seed)
 | 
					                slice.call(node.childNodes).forEach(compiler.compileNode, compiler)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -171,10 +171,10 @@ SeedProto._compileNode = function (node, root) {
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  Compile a text node
 | 
					 *  Compile a text node
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
SeedProto._compileTextNode = function (node) {
 | 
					CompilerProto.compileTextNode = function (node) {
 | 
				
			||||||
    var tokens = TextParser.parse(node)
 | 
					    var tokens = TextParser.parse(node)
 | 
				
			||||||
    if (!tokens) return
 | 
					    if (!tokens) return
 | 
				
			||||||
    var seed = this,
 | 
					    var compiler = this,
 | 
				
			||||||
        dirname = config.prefix + '-text',
 | 
					        dirname = config.prefix + '-text',
 | 
				
			||||||
        el, token, directive
 | 
					        el, token, directive
 | 
				
			||||||
    for (var i = 0, l = tokens.length; i < l; i++) {
 | 
					    for (var i = 0, l = tokens.length; i < l; i++) {
 | 
				
			||||||
| 
						 | 
					@ -184,7 +184,7 @@ SeedProto._compileTextNode = function (node) {
 | 
				
			||||||
            directive = DirectiveParser.parse(dirname, token.key)
 | 
					            directive = DirectiveParser.parse(dirname, token.key)
 | 
				
			||||||
            if (directive) {
 | 
					            if (directive) {
 | 
				
			||||||
                directive.el = el
 | 
					                directive.el = el
 | 
				
			||||||
                seed._bind(directive)
 | 
					                compiler.bindDirective(directive)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            el.nodeValue = token
 | 
					            el.nodeValue = token
 | 
				
			||||||
| 
						 | 
					@ -195,29 +195,56 @@ SeedProto._compileTextNode = function (node) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  Add a directive instance to the correct binding & scope
 | 
					 *  Create binding and attach getter/setter for a key to the viewmodel object
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
SeedProto._bind = function (directive) {
 | 
					CompilerProto.createBinding = function (key) {
 | 
				
			||||||
 | 
					    config.log('  created binding: ' + key)
 | 
				
			||||||
 | 
					    var binding = new Binding(this, key)
 | 
				
			||||||
 | 
					    this.bindings[key] = binding
 | 
				
			||||||
 | 
					    if (binding.isComputed) this.computed.push(binding)
 | 
				
			||||||
 | 
					    return binding
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  Add a directive instance to the correct binding & viewmodel
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CompilerProto.bindDirective = function (directive) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.directives.push(directive)
 | 
				
			||||||
 | 
					    directive.compiler = this
 | 
				
			||||||
 | 
					    directive.vm       = this.vm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var key = directive.key,
 | 
					    var key = directive.key,
 | 
				
			||||||
        seed = directive.seed = this
 | 
					        compiler = this
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // deal with each block
 | 
					    // deal with each block
 | 
				
			||||||
    if (this.each) {
 | 
					    if (this.each) {
 | 
				
			||||||
        if (key.indexOf(this.eachPrefix) === 0) {
 | 
					        if (key.indexOf(this.eachPrefix) === 0) {
 | 
				
			||||||
            key = directive.key = key.replace(this.eachPrefix, '')
 | 
					            key = directive.key = key.replace(this.eachPrefix, '')
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            seed = this.parentSeed
 | 
					            compiler = this.parentCompiler
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // deal with nesting
 | 
					    // deal with nesting
 | 
				
			||||||
    seed = traceOwnerSeed(directive, seed)
 | 
					    compiler = traceOwnerCompiler(directive, compiler)
 | 
				
			||||||
    var binding = seed._bindings[key] || seed._createBinding(key)
 | 
					    var binding = compiler.bindings[key] || compiler.createBinding(key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    binding.instances.push(directive)
 | 
					    binding.instances.push(directive)
 | 
				
			||||||
    directive.binding = binding
 | 
					    directive.binding = binding
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // for newly inserted sub-VMs (each items), need to bind deps
 | 
				
			||||||
 | 
					    // because they didn't get processed when the parent compiler
 | 
				
			||||||
 | 
					    // was binding dependencies.
 | 
				
			||||||
 | 
					    var i, dep
 | 
				
			||||||
 | 
					    if (binding.contextDeps) {
 | 
				
			||||||
 | 
					        i = binding.contextDeps.length
 | 
				
			||||||
 | 
					        while (i--) {
 | 
				
			||||||
 | 
					            dep = this.bindings[binding.contextDeps[i]]
 | 
				
			||||||
 | 
					            dep.subs.push(directive)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // invoke bind hook if exists
 | 
					    // invoke bind hook if exists
 | 
				
			||||||
    if (directive.bind) {
 | 
					    if (directive.bind) {
 | 
				
			||||||
        directive.bind(binding.value)
 | 
					        directive.bind(binding.value)
 | 
				
			||||||
| 
						 | 
					@ -230,81 +257,74 @@ SeedProto._bind = function (directive) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 *  Create binding and attach getter/setter for a key to the scope object
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
SeedProto._createBinding = function (key) {
 | 
					 | 
				
			||||||
    config.log('  created binding: ' + key)
 | 
					 | 
				
			||||||
    var binding = new Binding(this, key)
 | 
					 | 
				
			||||||
    this._bindings[key] = binding
 | 
					 | 
				
			||||||
    if (binding.isComputed) this._computed.push(binding)
 | 
					 | 
				
			||||||
    return binding
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  Process subscriptions for computed properties that has
 | 
					 *  Process subscriptions for computed properties that has
 | 
				
			||||||
 *  dynamic context dependencies
 | 
					 *  dynamic context dependencies
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
SeedProto._bindContexts = function (bindings) {
 | 
					CompilerProto.bindContexts = function (bindings) {
 | 
				
			||||||
    var i = bindings.length, j, binding, depKey, dep
 | 
					    var i = bindings.length, j, k, binding, depKey, dep, ins
 | 
				
			||||||
    while (i--) {
 | 
					    while (i--) {
 | 
				
			||||||
        binding = bindings[i]
 | 
					        binding = bindings[i]
 | 
				
			||||||
        j = binding.contextDeps.length
 | 
					        j = binding.contextDeps.length
 | 
				
			||||||
        while (j--) {
 | 
					        while (j--) {
 | 
				
			||||||
            depKey = binding.contextDeps[j]
 | 
					            depKey = binding.contextDeps[j]
 | 
				
			||||||
            dep = this._bindings[depKey]
 | 
					            k = binding.instances.length
 | 
				
			||||||
            dep.subs.push(binding)
 | 
					            while (k--) {
 | 
				
			||||||
 | 
					                ins = binding.instances[k]
 | 
				
			||||||
 | 
					                dep = ins.compiler.bindings[depKey]
 | 
				
			||||||
 | 
					                dep.subs.push(ins)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 *  Call unbind() of all directive instances
 | 
					 | 
				
			||||||
 *  to remove event listeners, destroy child seeds, etc.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
SeedProto._unbind = function () {
 | 
					 | 
				
			||||||
    var i, ins, key, listener
 | 
					 | 
				
			||||||
    // unbind all bindings
 | 
					 | 
				
			||||||
    for (key in this._bindings) {
 | 
					 | 
				
			||||||
        ins = this._bindings[key].instances
 | 
					 | 
				
			||||||
        i = ins.length
 | 
					 | 
				
			||||||
        while (i--) {
 | 
					 | 
				
			||||||
            if (ins[i].unbind) ins[i].unbind()
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    // remove all listeners on eventbus
 | 
					 | 
				
			||||||
    i = this._listeners.length
 | 
					 | 
				
			||||||
    while (i--) {
 | 
					 | 
				
			||||||
        listener = this._listeners[i]
 | 
					 | 
				
			||||||
        eventbus.off(listener.event, listener.handler)
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  Unbind and remove element
 | 
					 *  Unbind and remove element
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
SeedProto._destroy = function () {
 | 
					CompilerProto.destroy = function () {
 | 
				
			||||||
    this._unbind()
 | 
					    var i, key, dir, listener, inss
 | 
				
			||||||
 | 
					    // remove all directives that are instances of external bindings
 | 
				
			||||||
 | 
					    i = this.directives.length
 | 
				
			||||||
 | 
					    while (i--) {
 | 
				
			||||||
 | 
					        dir = this.directives[i]
 | 
				
			||||||
 | 
					        if (dir.binding.compiler !== this) {
 | 
				
			||||||
 | 
					            inss = dir.binding.instances
 | 
				
			||||||
 | 
					            inss.splice(inss.indexOf(dir), 1)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        dir.unbind()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // remove all listeners on eventbus
 | 
				
			||||||
 | 
					    i = this.listeners.length
 | 
				
			||||||
 | 
					    while (i--) {
 | 
				
			||||||
 | 
					        listener = this.listeners[i]
 | 
				
			||||||
 | 
					        eventbus.off(listener.event, listener.handler)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // unbind all bindings
 | 
				
			||||||
 | 
					    for (key in this.bindings) {
 | 
				
			||||||
 | 
					        this.bindings[key].unbind()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // remove el
 | 
				
			||||||
 | 
					    this.el.compiler = null
 | 
				
			||||||
    this.el.parentNode.removeChild(this.el)
 | 
					    this.el.parentNode.removeChild(this.el)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Helpers --------------------------------------------------------------------
 | 
					// Helpers --------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  determine which scope a key belongs to based on nesting symbols
 | 
					 *  determine which viewmodel a key belongs to based on nesting symbols
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function traceOwnerSeed (key, seed) {
 | 
					function traceOwnerCompiler (key, compiler) {
 | 
				
			||||||
    if (key.nesting) {
 | 
					    if (key.nesting) {
 | 
				
			||||||
        var levels = key.nesting
 | 
					        var levels = key.nesting
 | 
				
			||||||
        while (seed.parentSeed && levels--) {
 | 
					        while (compiler.parentCompiler && levels--) {
 | 
				
			||||||
            seed = seed.parentSeed
 | 
					            compiler = compiler.parentCompiler
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else if (key.root) {
 | 
					    } else if (key.root) {
 | 
				
			||||||
        while (seed.parentSeed) {
 | 
					        while (compiler.parentCompiler) {
 | 
				
			||||||
            seed = seed.parentSeed
 | 
					            compiler = compiler.parentCompiler
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return seed
 | 
					    return compiler
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = Seed
 | 
					module.exports = Compiler
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,7 @@ var Emitter  = require('emitter'),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var dummyEl = document.createElement('div'),
 | 
					var dummyEl = document.createElement('div'),
 | 
				
			||||||
    ARGS_RE = /^function\s*?\((.+?)\)/,
 | 
					    ARGS_RE = /^function\s*?\((.+?)\)/,
 | 
				
			||||||
    SCOPE_RE_STR = '\\.scope\\.[\\.A-Za-z0-9_][\\.A-Za-z0-9_$]*',
 | 
					    SCOPE_RE_STR = '\\.vm\\.[\\.A-Za-z0-9_][\\.A-Za-z0-9_$]*',
 | 
				
			||||||
    noop = function () {}
 | 
					    noop = function () {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -21,7 +21,7 @@ function catchDeps (binding) {
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    parseContextDependency(binding)
 | 
					    parseContextDependency(binding)
 | 
				
			||||||
    binding.value.get({
 | 
					    binding.value.get({
 | 
				
			||||||
        scope: createDummyScope(binding),
 | 
					        vm: createDummyVM(binding),
 | 
				
			||||||
        el: dummyEl
 | 
					        el: dummyEl
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    observer.off('get')
 | 
					    observer.off('get')
 | 
				
			||||||
| 
						 | 
					@ -37,31 +37,37 @@ function filterDeps (binding) {
 | 
				
			||||||
    while (i--) {
 | 
					    while (i--) {
 | 
				
			||||||
        dep = binding.deps[i]
 | 
					        dep = binding.deps[i]
 | 
				
			||||||
        if (!dep.deps.length) {
 | 
					        if (!dep.deps.length) {
 | 
				
			||||||
            config.log('  └─' + dep.key)
 | 
					            config.log('  └─ ' + dep.key)
 | 
				
			||||||
            dep.subs.push(binding)
 | 
					            dep.subs.push(binding)
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            binding.deps.splice(i, 1)
 | 
					            binding.deps.splice(i, 1)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    var ctdeps = binding.contextDeps
 | 
				
			||||||
 | 
					    if (!ctdeps || !config.debug) return
 | 
				
			||||||
 | 
					    i = ctdeps.length
 | 
				
			||||||
 | 
					    while (i--) {
 | 
				
			||||||
 | 
					        config.log('  └─ ctx:' + ctdeps[i])
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  We need to invoke each binding's getter for dependency parsing,
 | 
					 *  We need to invoke each binding's getter for dependency parsing,
 | 
				
			||||||
 *  but we don't know what sub-scope properties the user might try
 | 
					 *  but we don't know what sub-viewmodel properties the user might try
 | 
				
			||||||
 *  to access in that getter. To avoid thowing an error or forcing
 | 
					 *  to access in that getter. To avoid thowing an error or forcing
 | 
				
			||||||
 *  the user to guard against an undefined argument, we staticly
 | 
					 *  the user to guard against an undefined argument, we staticly
 | 
				
			||||||
 *  analyze the function to extract any possible nested properties
 | 
					 *  analyze the function to extract any possible nested properties
 | 
				
			||||||
 *  the user expects the target scope to possess. They are all assigned
 | 
					 *  the user expects the target viewmodel to possess. They are all assigned
 | 
				
			||||||
 *  a noop function so they can be invoked with no real harm.
 | 
					 *  a noop function so they can be invoked with no real harm.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function createDummyScope (binding) {
 | 
					function createDummyVM (binding) {
 | 
				
			||||||
    var scope = {},
 | 
					    var viewmodel = {},
 | 
				
			||||||
        deps = binding.contextDeps
 | 
					        deps = binding.contextDeps
 | 
				
			||||||
    if (!deps) return scope
 | 
					    if (!deps) return viewmodel
 | 
				
			||||||
    var i = binding.contextDeps.length,
 | 
					    var i = binding.contextDeps.length,
 | 
				
			||||||
        j, level, key, path
 | 
					        j, level, key, path
 | 
				
			||||||
    while (i--) {
 | 
					    while (i--) {
 | 
				
			||||||
        level = scope
 | 
					        level = viewmodel
 | 
				
			||||||
        path = deps[i].split('.')
 | 
					        path = deps[i].split('.')
 | 
				
			||||||
        j = 0
 | 
					        j = 0
 | 
				
			||||||
        while (j < path.length) {
 | 
					        while (j < path.length) {
 | 
				
			||||||
| 
						 | 
					@ -71,20 +77,20 @@ function createDummyScope (binding) {
 | 
				
			||||||
            j++
 | 
					            j++
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return scope
 | 
					    return viewmodel
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  Extract context dependency paths
 | 
					 *  Extract context dependency paths
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function parseContextDependency (binding) {
 | 
					function parseContextDependency (binding) {
 | 
				
			||||||
    var fn   = binding.value.get,
 | 
					    var fn   = binding.rawGet,
 | 
				
			||||||
        str  = fn.toString(),
 | 
					        str  = fn.toString(),
 | 
				
			||||||
        args = str.match(ARGS_RE)
 | 
					        args = str.match(ARGS_RE)
 | 
				
			||||||
    if (!args) return null
 | 
					    if (!args) return null
 | 
				
			||||||
    var argRE = new RegExp(args[1] + SCOPE_RE_STR, 'g'),
 | 
					    var depsRE = new RegExp(args[1] + SCOPE_RE_STR, 'g'),
 | 
				
			||||||
        matches = str.match(argRE),
 | 
					        matches = str.match(depsRE),
 | 
				
			||||||
        base = args[1].length + 7
 | 
					        base = args[1].length + 4
 | 
				
			||||||
    if (!matches) return null
 | 
					    if (!matches) return null
 | 
				
			||||||
    var i = matches.length,
 | 
					    var i = matches.length,
 | 
				
			||||||
        deps = [], dep
 | 
					        deps = [], dep
 | 
				
			||||||
| 
						 | 
					@ -95,7 +101,7 @@ function parseContextDependency (binding) {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    binding.contextDeps = deps
 | 
					    binding.contextDeps = deps
 | 
				
			||||||
    binding.seed._contextBindings.push(binding)
 | 
					    binding.compiler.contextBindings.push(binding)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = {
 | 
					module.exports = {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,10 +26,14 @@ function Directive (directiveName, expression, oneway) {
 | 
				
			||||||
        this._update = definition.update
 | 
					        this._update = definition.update
 | 
				
			||||||
        for (prop in definition) {
 | 
					        for (prop in definition) {
 | 
				
			||||||
            if (prop !== 'update') {
 | 
					            if (prop !== 'update') {
 | 
				
			||||||
 | 
					                if (prop === 'unbind') {
 | 
				
			||||||
 | 
					                    this._unbind = definition[prop]
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
                    this[prop] = definition[prop]
 | 
					                    this[prop] = definition[prop]
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.oneway        = !!oneway
 | 
					    this.oneway        = !!oneway
 | 
				
			||||||
    this.directiveName = directiveName
 | 
					    this.directiveName = directiveName
 | 
				
			||||||
| 
						 | 
					@ -62,11 +66,11 @@ DirProto.update = function (value) {
 | 
				
			||||||
 *  called when a dependency has changed
 | 
					 *  called when a dependency has changed
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
DirProto.refresh = function () {
 | 
					DirProto.refresh = function () {
 | 
				
			||||||
    // pass element and scope info to the getter
 | 
					    // pass element and viewmodel info to the getter
 | 
				
			||||||
    // enables powerful context-aware bindings
 | 
					    // enables powerful context-aware bindings
 | 
				
			||||||
    var value = this.value.get({
 | 
					    var value = this.value.get({
 | 
				
			||||||
        el: this.el,
 | 
					        el: this.el,
 | 
				
			||||||
        scope: this.seed.scope
 | 
					        vm: this.vm
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    if (value === this.computedValue) return
 | 
					    if (value === this.computedValue) return
 | 
				
			||||||
    this.computedValue = value
 | 
					    this.computedValue = value
 | 
				
			||||||
| 
						 | 
					@ -135,6 +139,15 @@ DirProto.parseKey = function (rawKey) {
 | 
				
			||||||
    this.key = key
 | 
					    this.key = key
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  unbind noop, to be overwritten by definitions
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					DirProto.unbind = function (update) {
 | 
				
			||||||
 | 
					    if (!this.el) return
 | 
				
			||||||
 | 
					    if (this._unbind) this._unbind(update)
 | 
				
			||||||
 | 
					    if (!update) this.vm = this.el = this.compiler = this.binding =  null
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  parse a filter expression
 | 
					 *  parse a filter expression
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
var config = require('../config')
 | 
					var config = require('../config'),
 | 
				
			||||||
 | 
					    utils  = require('../utils')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  Mathods that perform precise DOM manipulation
 | 
					 *  Mathods that perform precise DOM manipulation
 | 
				
			||||||
| 
						 | 
					@ -59,16 +60,16 @@ var mutationHandlers = {
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sort: function () {
 | 
					    sort: function () {
 | 
				
			||||||
        var i, l = this.collection.length, scope
 | 
					        var i, l = this.collection.length, viewmodel
 | 
				
			||||||
        for (i = 0; i < l; i++) {
 | 
					        for (i = 0; i < l; i++) {
 | 
				
			||||||
            scope = this.collection[i]
 | 
					            viewmodel = this.collection[i]
 | 
				
			||||||
            scope.$index = i
 | 
					            viewmodel.$index = i
 | 
				
			||||||
            this.container.insertBefore(scope.$el, this.ref)
 | 
					            this.container.insertBefore(viewmodel.$el, this.ref)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mutationHandlers.reverse = mutationHandlers.sort
 | 
					//mutationHandlers.reverse = mutationHandlers.sort
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = {
 | 
					module.exports = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -84,7 +85,6 @@ module.exports = {
 | 
				
			||||||
    update: function (collection) {
 | 
					    update: function (collection) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.unbind(true)
 | 
					        this.unbind(true)
 | 
				
			||||||
        if (!Array.isArray(collection)) return
 | 
					 | 
				
			||||||
        this.collection = collection
 | 
					        this.collection = collection
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // attach an object to container to hold handlers
 | 
					        // attach an object to container to hold handlers
 | 
				
			||||||
| 
						 | 
					@ -92,10 +92,9 @@ module.exports = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // listen for collection mutation events
 | 
					        // listen for collection mutation events
 | 
				
			||||||
        // the collection has been augmented during Binding.set()
 | 
					        // the collection has been augmented during Binding.set()
 | 
				
			||||||
        var self = this
 | 
					        collection.on('mutate', (function (mutation) {
 | 
				
			||||||
        collection.on('mutate', function (mutation) {
 | 
					            mutationHandlers[mutation.method].call(this, mutation)
 | 
				
			||||||
            mutationHandlers[mutation.method].call(self, mutation)
 | 
					        }).bind(this))
 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // create child-seeds and append to DOM
 | 
					        // create child-seeds and append to DOM
 | 
				
			||||||
        for (var i = 0, l = collection.length; i < l; i++) {
 | 
					        for (var i = 0, l = collection.length; i < l; i++) {
 | 
				
			||||||
| 
						 | 
					@ -106,16 +105,16 @@ module.exports = {
 | 
				
			||||||
    buildItem: function (ref, data, index) {
 | 
					    buildItem: function (ref, data, index) {
 | 
				
			||||||
        var node = this.el.cloneNode(true)
 | 
					        var node = this.el.cloneNode(true)
 | 
				
			||||||
        this.container.insertBefore(node, ref)
 | 
					        this.container.insertBefore(node, ref)
 | 
				
			||||||
        var Seed = require('../seed'),
 | 
					        var Compiler = require('../compiler'),
 | 
				
			||||||
            spore = new Seed(node, {
 | 
					            spore = new Compiler(node, {
 | 
				
			||||||
                each: true,
 | 
					                each: true,
 | 
				
			||||||
                eachPrefix: this.arg + '.',
 | 
					                eachPrefix: this.arg + '.',
 | 
				
			||||||
                parentSeed: this.seed,
 | 
					                parentCompiler: this.compiler,
 | 
				
			||||||
                index: index,
 | 
					                index: index,
 | 
				
			||||||
                data: data,
 | 
					                data: data,
 | 
				
			||||||
                delegator: this.container
 | 
					                delegator: this.container
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
        this.collection[index] = spore.scope
 | 
					        this.collection[index] = spore.vm
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    updateIndexes: function () {
 | 
					    updateIndexes: function () {
 | 
				
			||||||
| 
						 | 
					@ -125,20 +124,19 @@ module.exports = {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    unbind: function (reset) {
 | 
					    unbind: function () {
 | 
				
			||||||
        if (this.collection && this.collection.length) {
 | 
					        if (this.collection) {
 | 
				
			||||||
            var i = this.collection.length,
 | 
					            this.collection.off('mutate')
 | 
				
			||||||
                fn = reset ? '_destroy' : '_unbind'
 | 
					            var i = this.collection.length
 | 
				
			||||||
            while (i--) {
 | 
					            while (i--) {
 | 
				
			||||||
                this.collection[i].$seed[fn]()
 | 
					                this.collection[i].$destroy()
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            this.collection = null
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        var ctn = this.container,
 | 
					        var ctn = this.container,
 | 
				
			||||||
            handlers = ctn.sd_dHandlers
 | 
					            handlers = ctn.sd_dHandlers
 | 
				
			||||||
        for (var key in handlers) {
 | 
					        for (var key in handlers) {
 | 
				
			||||||
            ctn.removeEventListener(handlers[key].event, handlers[key])
 | 
					            ctn.removeEventListener(handlers[key].event, handlers[key])
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        delete ctn.sd_dHandlers
 | 
					        ctn.sd_dHandlers = null
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -51,7 +51,7 @@ module.exports = {
 | 
				
			||||||
            if (this.oneway) return
 | 
					            if (this.oneway) return
 | 
				
			||||||
            var el = this.el, self = this
 | 
					            var el = this.el, self = this
 | 
				
			||||||
            this.change = function () {
 | 
					            this.change = function () {
 | 
				
			||||||
                self.seed.scope[self.key] = el.value
 | 
					                self.compiler.vm[self.key] = el.value
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            el.addEventListener('keyup', this.change)
 | 
					            el.addEventListener('keyup', this.change)
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
| 
						 | 
					@ -69,7 +69,7 @@ module.exports = {
 | 
				
			||||||
            if (this.oneway) return
 | 
					            if (this.oneway) return
 | 
				
			||||||
            var el = this.el, self = this
 | 
					            var el = this.el, self = this
 | 
				
			||||||
            this.change = function () {
 | 
					            this.change = function () {
 | 
				
			||||||
                self.seed.scope[self.key] = el.checked
 | 
					                self.compiler.vm[self.key] = el.checked
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            el.addEventListener('change', this.change)
 | 
					            el.addEventListener('change', this.change)
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,29 +13,29 @@ module.exports = {
 | 
				
			||||||
    expectFunction : true,
 | 
					    expectFunction : true,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bind: function () {
 | 
					    bind: function () {
 | 
				
			||||||
        if (this.seed.each) {
 | 
					        if (this.compiler.each) {
 | 
				
			||||||
            // attach an identifier to the el
 | 
					            // attach an identifier to the el
 | 
				
			||||||
            // so it can be matched during event delegation
 | 
					            // so it can be matched during event delegation
 | 
				
			||||||
            this.el[this.expression] = true
 | 
					            this.el[this.expression] = true
 | 
				
			||||||
            // attach the owner scope of this directive
 | 
					            // attach the owner viewmodel of this directive
 | 
				
			||||||
            this.el.sd_scope = this.seed.scope
 | 
					            this.el.sd_viewmodel = this.vm
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    update: function (handler) {
 | 
					    update: function (handler) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.unbind()
 | 
					        this.unbind(true)
 | 
				
			||||||
        if (!handler) return
 | 
					        if (!handler) return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        var seed  = this.seed,
 | 
					        var compiler = this.compiler,
 | 
				
			||||||
            event    = this.arg,
 | 
					            event    = this.arg,
 | 
				
			||||||
            ownerScope = this.binding.seed.scope
 | 
					            ownerVM  = this.binding.vm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (seed.each && event !== 'blur' && event !== 'blur') {
 | 
					        if (compiler.each && event !== 'blur' && event !== 'blur') {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // for each blocks, delegate for better performance
 | 
					            // for each blocks, delegate for better performance
 | 
				
			||||||
            // focus and blur events dont bubble so exclude them
 | 
					            // focus and blur events dont bubble so exclude them
 | 
				
			||||||
            var delegator  = seed.delegator,
 | 
					            var delegator  = compiler.delegator,
 | 
				
			||||||
                identifier = this.expression,
 | 
					                identifier = this.expression,
 | 
				
			||||||
                dHandler   = delegator.sd_dHandlers[identifier]
 | 
					                dHandler   = delegator.sd_dHandlers[identifier]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,8 +46,8 @@ module.exports = {
 | 
				
			||||||
                var target = delegateCheck(e.target, delegator, identifier)
 | 
					                var target = delegateCheck(e.target, delegator, identifier)
 | 
				
			||||||
                if (target) {
 | 
					                if (target) {
 | 
				
			||||||
                    e.el = target
 | 
					                    e.el = target
 | 
				
			||||||
                    e.scope = target.sd_scope
 | 
					                    e.vm = target.sd_viewmodel
 | 
				
			||||||
                    handler.call(ownerScope, e)
 | 
					                    handler.call(ownerVM, e)
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            dHandler.event = event
 | 
					            dHandler.event = event
 | 
				
			||||||
| 
						 | 
					@ -58,15 +58,17 @@ module.exports = {
 | 
				
			||||||
            // a normal, single element handler
 | 
					            // a normal, single element handler
 | 
				
			||||||
            this.handler = function (e) {
 | 
					            this.handler = function (e) {
 | 
				
			||||||
                e.el = e.currentTarget
 | 
					                e.el = e.currentTarget
 | 
				
			||||||
                e.scope = seed.scope
 | 
					                e.vm = compiler.vm
 | 
				
			||||||
                handler.call(seed.scope, e)
 | 
					                handler.call(compiler.vm, e)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            this.el.addEventListener(event, this.handler)
 | 
					            this.el.addEventListener(event, this.handler)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    unbind: function () {
 | 
					    unbind: function (update) {
 | 
				
			||||||
        this.el.removeEventListener(this.arg, this.handler)
 | 
					        this.el.removeEventListener(this.arg, this.handler)
 | 
				
			||||||
 | 
					        this.handler = null
 | 
				
			||||||
 | 
					        if (!update) this.el.sd_viewmodel = null
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										22
									
								
								src/main.js
								
								
								
								
							
							
						
						
									
										22
									
								
								src/main.js
								
								
								
								
							| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
var config      = require('./config'),
 | 
					var config      = require('./config'),
 | 
				
			||||||
    Seed        = require('./seed'),
 | 
					    Compiler    = require('./compiler'),
 | 
				
			||||||
    Scope       = require('./scope'),
 | 
					    ViewModel   = require('./viewmodel'),
 | 
				
			||||||
    directives  = require('./directives'),
 | 
					    directives  = require('./directives'),
 | 
				
			||||||
    filters     = require('./filters'),
 | 
					    filters     = require('./filters'),
 | 
				
			||||||
    textParser  = require('./text-parser'),
 | 
					    textParser  = require('./text-parser'),
 | 
				
			||||||
| 
						 | 
					@ -40,12 +40,12 @@ api.data = function (id, data) {
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
api.controller = function (id, properties) {
 | 
					api.controller = function (id, properties) {
 | 
				
			||||||
    if (!properties) return controllers[id]
 | 
					    if (!properties) return controllers[id]
 | 
				
			||||||
    // create a subclass of Scope that has the extension methods mixed-in
 | 
					    // create a subclass of ViewModel that has the extension methods mixed-in
 | 
				
			||||||
    var ExtendedScope = function () {
 | 
					    var ExtendedVM = function () {
 | 
				
			||||||
        Scope.apply(this, arguments)
 | 
					        ViewModel.apply(this, arguments)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    var p = ExtendedScope.prototype = Object.create(Scope.prototype)
 | 
					    var p = ExtendedVM.prototype = Object.create(ViewModel.prototype)
 | 
				
			||||||
    p.constructor = ExtendedScope
 | 
					    p.constructor = ExtendedVM
 | 
				
			||||||
    for (var prop in properties) {
 | 
					    for (var prop in properties) {
 | 
				
			||||||
        if (prop !== 'init') {
 | 
					        if (prop !== 'init') {
 | 
				
			||||||
            p[prop] = properties[prop]
 | 
					            p[prop] = properties[prop]
 | 
				
			||||||
| 
						 | 
					@ -53,7 +53,7 @@ api.controller = function (id, properties) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    controllers[id] = {
 | 
					    controllers[id] = {
 | 
				
			||||||
        init: properties.init,
 | 
					        init: properties.init,
 | 
				
			||||||
        ExtendedScope: ExtendedScope
 | 
					        ExtendedVM: ExtendedVM
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -91,12 +91,12 @@ api.config = function (opts) {
 | 
				
			||||||
 *  Compile a single element
 | 
					 *  Compile a single element
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
api.compile = function (el) {
 | 
					api.compile = function (el) {
 | 
				
			||||||
    return new Seed(el).scope
 | 
					    return new Compiler(el).vm
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  Bootstrap the whole thing
 | 
					 *  Bootstrap the whole thing
 | 
				
			||||||
 *  by creating a Seed instance for top level nodes
 | 
					 *  by creating a Compiler instance for top level nodes
 | 
				
			||||||
 *  that has either sd-controller or sd-data
 | 
					 *  that has either sd-controller or sd-data
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
api.bootstrap = function (opts) {
 | 
					api.bootstrap = function (opts) {
 | 
				
			||||||
| 
						 | 
					@ -107,7 +107,7 @@ api.bootstrap = function (opts) {
 | 
				
			||||||
        dataSlt = '[' + config.prefix + '-data]'
 | 
					        dataSlt = '[' + config.prefix + '-data]'
 | 
				
			||||||
    /* jshint boss: true */
 | 
					    /* jshint boss: true */
 | 
				
			||||||
    while (el = document.querySelector(ctrlSlt) || document.querySelector(dataSlt)) {
 | 
					    while (el = document.querySelector(ctrlSlt) || document.querySelector(dataSlt)) {
 | 
				
			||||||
        new Seed(el)
 | 
					        new Compiler(el)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    booted = true
 | 
					    booted = true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,7 +31,7 @@ function dump (val) {
 | 
				
			||||||
    } else if (type === 'Object') {
 | 
					    } else if (type === 'Object') {
 | 
				
			||||||
        if (val.get) { // computed property
 | 
					        if (val.get) { // computed property
 | 
				
			||||||
            return val.get()
 | 
					            return val.get()
 | 
				
			||||||
        } else { // object / child scope
 | 
					        } else { // object / child viewmodel
 | 
				
			||||||
            var ret = {}, prop
 | 
					            var ret = {}, prop
 | 
				
			||||||
            for (var key in val) {
 | 
					            for (var key in val) {
 | 
				
			||||||
                prop = val[key]
 | 
					                prop = val[key]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,26 +1,25 @@
 | 
				
			||||||
var utils   = require('./utils')
 | 
					var utils   = require('./utils')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  Scope is the ViewModel/whatever exposed to the user
 | 
					 *  ViewModel exposed to the user that holds data,
 | 
				
			||||||
 *  that holds data, computed properties, event handlers
 | 
					 *  computed properties, event handlers
 | 
				
			||||||
 *  and a few reserved methods
 | 
					 *  and a few reserved methods
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function Scope (seed, options) {
 | 
					function ViewModel (compiler, options) {
 | 
				
			||||||
    this.$seed     = seed
 | 
					    this.$compiler = compiler
 | 
				
			||||||
    this.$el       = seed.el
 | 
					    this.$el       = compiler.el
 | 
				
			||||||
    this.$index    = options.index
 | 
					    this.$index    = options.index
 | 
				
			||||||
    this.$parent   = options.parentSeed && options.parentSeed.scope
 | 
					    this.$parent   = options.parentCompiler && options.parentCompiler.vm
 | 
				
			||||||
    this.$seed._watchers = {}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var ScopeProto = Scope.prototype
 | 
					var VMProto = ViewModel.prototype
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  register a listener that will be broadcasted from the global event bus
 | 
					 *  register a listener that will be broadcasted from the global event bus
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
ScopeProto.$on = function (event, handler) {
 | 
					VMProto.$on = function (event, handler) {
 | 
				
			||||||
    utils.eventbus.on(event, handler)
 | 
					    utils.eventbus.on(event, handler)
 | 
				
			||||||
    this.$seed._listeners.push({
 | 
					    this.$compiler.listeners.push({
 | 
				
			||||||
        event: event,
 | 
					        event: event,
 | 
				
			||||||
        handler: handler
 | 
					        handler: handler
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
| 
						 | 
					@ -29,9 +28,9 @@ ScopeProto.$on = function (event, handler) {
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  remove the registered listener
 | 
					 *  remove the registered listener
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
ScopeProto.$off = function (event, handler) {
 | 
					VMProto.$off = function (event, handler) {
 | 
				
			||||||
    utils.eventbus.off(event, handler)
 | 
					    utils.eventbus.off(event, handler)
 | 
				
			||||||
    var listeners = this.$seed._listeners,
 | 
					    var listeners = this.$compiler.listeners,
 | 
				
			||||||
        i = listeners.length, listener
 | 
					        i = listeners.length, listener
 | 
				
			||||||
    while (i--) {
 | 
					    while (i--) {
 | 
				
			||||||
        listener = listeners[i]
 | 
					        listener = listeners[i]
 | 
				
			||||||
| 
						 | 
					@ -43,19 +42,19 @@ ScopeProto.$off = function (event, handler) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  watch a key on the scope for changes
 | 
					 *  watch a key on the viewmodel for changes
 | 
				
			||||||
 *  fire callback with new value
 | 
					 *  fire callback with new value
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
ScopeProto.$watch = function (key, callback) {
 | 
					VMProto.$watch = function (key, callback) {
 | 
				
			||||||
    var self = this
 | 
					    var self = this
 | 
				
			||||||
    // yield and wait for seed to finish compiling
 | 
					    // yield and wait for compiler to finish compiling
 | 
				
			||||||
    setTimeout(function () {
 | 
					    setTimeout(function () {
 | 
				
			||||||
        var scope   = self.$seed.scope,
 | 
					        var viewmodel   = self.$compiler.vm,
 | 
				
			||||||
            binding = self.$seed._bindings[key],
 | 
					            binding = self.$compiler.bindings[key],
 | 
				
			||||||
            i       = binding.deps.length,
 | 
					            i       = binding.deps.length,
 | 
				
			||||||
            watcher = self.$seed._watchers[key] = {
 | 
					            watcher = self.$compiler.watchers[key] = {
 | 
				
			||||||
                refresh: function () {
 | 
					                refresh: function () {
 | 
				
			||||||
                    callback(scope[key])
 | 
					                    callback(viewmodel[key])
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                deps: binding.deps
 | 
					                deps: binding.deps
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -68,50 +67,51 @@ ScopeProto.$watch = function (key, callback) {
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  remove watcher
 | 
					 *  remove watcher
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
ScopeProto.$unwatch = function (key) {
 | 
					VMProto.$unwatch = function (key) {
 | 
				
			||||||
    var self = this
 | 
					    var self = this
 | 
				
			||||||
    setTimeout(function () {
 | 
					    setTimeout(function () {
 | 
				
			||||||
        var watcher = self.$seed._watchers[key]
 | 
					        var watcher = self.$compiler.watchers[key]
 | 
				
			||||||
        if (!watcher) return
 | 
					        if (!watcher) return
 | 
				
			||||||
        var i = watcher.deps.length, subs
 | 
					        var i = watcher.deps.length, subs
 | 
				
			||||||
        while (i--) {
 | 
					        while (i--) {
 | 
				
			||||||
            subs = watcher.deps[i].subs
 | 
					            subs = watcher.deps[i].subs
 | 
				
			||||||
            subs.splice(subs.indexOf(watcher))
 | 
					            subs.splice(subs.indexOf(watcher))
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        delete self.$seed._watchers[key]
 | 
					        self.$compiler.watchers[key] = null
 | 
				
			||||||
    }, 0)
 | 
					    }, 0)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  load data into scope
 | 
					 *  load data into viewmodel
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
ScopeProto.$load = function (data) {
 | 
					VMProto.$load = function (data) {
 | 
				
			||||||
    for (var key in data) {
 | 
					    for (var key in data) {
 | 
				
			||||||
        this[key] = data[key]
 | 
					        this[key] = data[key]
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  Dump a copy of current scope data, excluding seed-exposed properties.
 | 
					 *  Dump a copy of current viewmodel data, excluding compiler-exposed properties.
 | 
				
			||||||
 *  @param key (optional): key for the value to dump
 | 
					 *  @param key (optional): key for the value to dump
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
ScopeProto.$dump = function (key) {
 | 
					VMProto.$dump = function (key) {
 | 
				
			||||||
    var bindings = this.$seed._bindings
 | 
					    var bindings = this.$compiler.bindings
 | 
				
			||||||
    return utils.dump(key ? bindings[key].value : this)
 | 
					    return utils.dump(key ? bindings[key].value : this)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  stringify the result from $dump
 | 
					 *  stringify the result from $dump
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
ScopeProto.$serialize = function (key) {
 | 
					VMProto.$serialize = function (key) {
 | 
				
			||||||
    return JSON.stringify(this.$dump(key))
 | 
					    return JSON.stringify(this.$dump(key))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *  unbind everything, remove everything
 | 
					 *  unbind everything, remove everything
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
ScopeProto.$destroy = function () {
 | 
					VMProto.$destroy = function () {
 | 
				
			||||||
    this.$seed._destroy()
 | 
					    this.$compiler.destroy()
 | 
				
			||||||
 | 
					    this.$compiler = null
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = Scope
 | 
					module.exports = ViewModel
 | 
				
			||||||
		Loading…
	
		Reference in New Issue