Skip to content

Commit

Permalink
clean up get binding owner compiler logic
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Jan 22, 2014
1 parent 1fb885b commit 9a45f63
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 80 deletions.
52 changes: 23 additions & 29 deletions src/compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,30 +44,23 @@ function Compiler (vm, options) {

// set compiler properties
compiler.vm = vm
compiler.bindings = makeHash()
compiler.dirs = []
compiler.exps = []
compiler.computed = []
compiler.childCompilers = []
compiler.emitter = new Emitter()

// inherit parent bindings
var parent = compiler.parentCompiler
compiler.bindings = parent
? Object.create(parent.bindings)
: makeHash()
compiler.rootCompiler = parent
? getRoot(parent)
: compiler

// set inenumerable VM properties
def(vm, '$', makeHash())
def(vm, '$el', el)
def(vm, '$compiler', compiler)
def(vm, '$root', compiler.rootCompiler.vm)
def(vm, '$root', getRoot(compiler).vm)

// set parent VM
// and register child id on parent
var childId = utils.attr(el, 'component-id')
var parent = compiler.parentCompiler,
childId = utils.attr(el, 'component-id')
if (parent) {
parent.childCompilers.push(compiler)
def(vm, '$parent', parent.vm)
Expand Down Expand Up @@ -204,7 +197,7 @@ CompilerProto.setupObserver = function () {
})

function check (key) {
if (!hasOwn.call(bindings, key)) {
if (!bindings[key]) {
compiler.createBinding(key)
}
}
Expand Down Expand Up @@ -405,31 +398,23 @@ CompilerProto.bindDirective = function (directive) {

// otherwise, we got more work to do...
var binding,
compiler = this,
key = directive.key,
baseKey = key.split('.')[0]
compiler = this,
key = directive.key

if (directive.isExp) {
// expression bindings are always created on current compiler
binding = compiler.createBinding(key, true, directive.isFn)
} else {
// recursively locate where to place the binding
// recursively locate which compiler owns the binding
while (compiler) {
if (
hasOwn.call(compiler.data, baseKey) ||
hasOwn.call(compiler.vm, baseKey)
) {
// If a compiler has the base key, the directive should
// belong to it. Create the binding if it's not created already.
binding = hasOwn.call(compiler.bindings, key)
? compiler.bindings[key]
: compiler.createBinding(key)
if (compiler.hasKey(key)) {
break
} else {
compiler = compiler.parentCompiler
}
}
if (!binding) binding = this.createBinding(key)
compiler = compiler || this
binding = compiler.bindings[key] || compiler.createBinding(key)
}

binding.instances.push(directive)
Expand Down Expand Up @@ -484,7 +469,7 @@ CompilerProto.createBinding = function (key, isExp, isFn) {
// ensure path in data so it can be observed
Observer.ensurePath(compiler.data, key)
var parentKey = key.slice(0, key.lastIndexOf('.'))
if (!hasOwn.call(bindings, parentKey)) {
if (!bindings[parentKey]) {
// this is a nested value binding, but the binding for its parent
// has not been created yet. We better create that one too.
compiler.createBinding(parentKey)
Expand Down Expand Up @@ -585,6 +570,15 @@ CompilerProto.execHook = function (id, alt) {
}
}

/**
* Check if a compiler's data contains a keypath
*/
CompilerProto.hasKey = function (key) {
var baseKey = key.split('.')[0]
return hasOwn.call(this.data, baseKey) ||
hasOwn.call(this.vm, baseKey)
}

/**
* Unbind and remove element
*/
Expand Down Expand Up @@ -626,8 +620,8 @@ CompilerProto.destroy = function () {

// unbind/unobserve all own bindings
for (key in bindings) {
if (hasOwn.call(bindings, key)) {
binding = bindings[key]
binding = bindings[key]
if (binding) {
if (binding.root) {
Observer.unobserve(binding.value, binding.key, compiler.observer)
}
Expand Down
36 changes: 11 additions & 25 deletions src/exp-parser.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
var utils = require('./utils'),
hasOwn = Object.prototype.hasOwnProperty,
stringSaveRE = /"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'/g,
stringRestoreRE = /"(\d+)"/g

Expand Down Expand Up @@ -54,38 +53,25 @@ function getVariables (code) {
*/
function getRel (path, compiler) {
var rel = '',
has = false,
nest = 0,
vm = compiler.vm,
dot = path.indexOf('.'),
key = dot > -1
? path.slice(0, dot)
: path
while (true) {
if (
hasOwn.call(vm.$data, key) ||
hasOwn.call(vm, key)
) {
has = true
dist = 0,
self = compiler
while (compiler) {
if (compiler.hasKey(path)) {
break
} else {
if (vm.$parent) {
vm = vm.$parent
nest++
} else {
break
}
compiler = compiler.parentCompiler
dist++
}
}
if (has) {
while (nest--) {
if (compiler) {
while (dist--) {
rel += '$parent.'
}
if (!hasOwn.call(vm.$compiler.bindings, path) && path.charAt(0) !== '$') {
vm.$compiler.createBinding(path)
if (!compiler.bindings[path] && path.charAt(0) !== '$') {
compiler.createBinding(path)
}
} else {
compiler.createBinding(path)
self.createBinding(path)
}
return rel
}
Expand Down
7 changes: 5 additions & 2 deletions test/unit/specs/exp-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ describe('UNIT: Expression Parser', function () {
var caughtMissingPaths = [],
compilerMock = {
createBinding: createBinding,
hasKey: function () {},
vm:{
$data: {},
$compiler:{
Expand Down Expand Up @@ -120,12 +121,14 @@ describe('UNIT: Expression Parser', function () {
utils.warn = function () {
warned = true
}
function noop () {}
ExpParser.parse('a + "fsef', {
createBinding: function () {},
createBinding: noop,
hasKey: noop,
vm: {
$compiler: {
bindings: {},
createBinding: function () {}
createBinding: noop
},
$data: {}
}
Expand Down
38 changes: 14 additions & 24 deletions test/unit/specs/viewmodel.js
Original file line number Diff line number Diff line change
Expand Up @@ -371,8 +371,7 @@ describe('UNIT: ViewModel', function () {
expUnbindCalled = false,
bindingUnbindCalled = false,
unobserveCalled = 0,
elRemoved = false,
externalBindingUnbindCalled = false
elRemoved = false

var dirMock = {
binding: {
Expand All @@ -385,26 +384,21 @@ describe('UNIT: ViewModel', function () {
}
dirMock.binding.instances.push(dirMock)

var bindingsMock = Object.create({
'test2': {
unbind: function () {
externalBindingUnbindCalled = true
}
}
})
bindingsMock.test = {
root: true,
key: 'test',
value: {
__observer__: {
off: function () {
unobserveCalled++
return this
var bindingsMock = {
test: {
root: true,
key: 'test',
value: {
__observer__: {
off: function () {
unobserveCalled++
return this
}
}
},
unbind: function () {
bindingUnbindCalled = true
}
},
unbind: function () {
bindingUnbindCalled = true
}
}

Expand Down Expand Up @@ -487,10 +481,6 @@ describe('UNIT: ViewModel', function () {
assert.strictEqual(unobserveCalled, 3)
})

it('should not unbind external bindings', function () {
assert.notOk(externalBindingUnbindCalled)
})

it('should remove self from parentCompiler', function () {
var parent = compilerMock.parentCompiler
assert.ok(parent.childCompilers.indexOf(compilerMock), -1)
Expand Down

0 comments on commit 9a45f63

Please sign in to comment.