diff --git a/component.json b/component.json index 5a1bab014..486da9f2e 100644 --- a/component.json +++ b/component.json @@ -24,7 +24,8 @@ "src/directives/if.js", "src/directives/repeat.js", "src/directives/on.js", - "src/directives/model.js" + "src/directives/model.js", + "src/directives/component.js" ], "dependencies": { "component/emitter": "*" diff --git a/src/compiler.js b/src/compiler.js index d799084bd..129ab811a 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -71,8 +71,9 @@ function Compiler (vm, options) { // set parent VM // and register child id on parent - var childId = utils.attr(el, 'id') + var childId = utils.attr(el, 'component-id') if (parent) { + parent.childCompilers.push(compiler) def(vm, '$parent', parent.vm) if (childId) { compiler.childId = childId @@ -217,18 +218,20 @@ CompilerProto.setupObserver = function () { */ CompilerProto.compile = function (node, root) { - var compiler = this + var compiler = this, + nodeType = node.nodeType, + tagName = node.tagName - if (node.nodeType === 1) { // a normal node + if (nodeType === 1 && tagName !== 'SCRIPT') { // a normal node // skip anything with v-pre if (utils.attr(node, 'pre') !== null) return // special attributes to check var repeatExp, - componentId, + componentExp, partialId, - customElementFn = compiler.getOption('elements', node.tagName.toLowerCase()) + directive // It is important that we access these attributes // procedurally because the order matters. @@ -242,21 +245,25 @@ CompilerProto.compile = function (node, root) { if (repeatExp = utils.attr(node, 'repeat')) { // repeat block cannot have v-id at the same time. - var directive = Directive.parse(config.attrs.repeat, repeatExp, compiler, node) + directive = Directive.parse(config.attrs.repeat, repeatExp, compiler, node) if (directive) { compiler.bindDirective(directive) } - // custom elements has 2nd highest priority - } else if (!root && customElementFn) { + // v-component has 2nd highest priority + } else if (!root && (componentExp = utils.attr(node, 'component'))) { - addChild(customElementFn) - - // v-component has 3rd highest priority - } else if (!root && (componentId = utils.attr(node, 'component'))) { - - var ChildVM = compiler.getOption('components', componentId) - if (ChildVM) addChild(ChildVM) + directive = Directive.parse(config.attrs.component, componentExp, compiler, node) + if (directive) { + // component directive is a bit different from the others. + // when it has no argument, it should be treated as a + // simple directive with its key as the argument. + if (componentExp.indexOf(':') === -1) { + directive.isSimple = true + directive.arg = directive.key + } + compiler.bindDirective(directive) + } } else { @@ -277,27 +284,12 @@ CompilerProto.compile = function (node, root) { compiler.compileNode(node) } - } else if (node.nodeType === 3) { // text node + } else if (nodeType === 3) { // text node compiler.compileTextNode(node) } - function addChild (Ctor) { - if (utils.isConstructor(Ctor)) { - var child = new Ctor({ - el: node, - child: true, - compilerOptions: { - parentCompiler: compiler - } - }) - compiler.childCompilers.push(child.$compiler) - } else { - // simply call the function - Ctor(node) - } - } } /** @@ -412,13 +404,13 @@ CompilerProto.bindDirective = function (directive) { binding.instances.push(directive) directive.binding = binding - var value = binding.value // invoke bind hook if exists if (directive.bind) { - directive.bind(value) + directive.bind() } // set initial value + var value = binding.value if (value !== undefined) { if (binding.isComputed) { directive.refresh(value) @@ -454,11 +446,11 @@ CompilerProto.createBinding = function (key, isExp, isFn) { bindings[key] = binding // make sure the key exists in the object so it can be observed // by the Observer! - Observer.ensurePath(compiler.vm, key) if (binding.root) { // this is a root level binding. we need to define getter/setters for it. compiler.define(key, binding) } else { + Observer.ensurePath(compiler.vm, key) var parentKey = key.slice(0, key.lastIndexOf('.')) if (!hasOwn.call(bindings, parentKey)) { // this is a nested value binding, but the binding for its parent @@ -488,9 +480,10 @@ CompilerProto.define = function (key, binding) { // computed property compiler.markComputed(binding) } else if (type === 'Object' || type === 'Array') { - // observe objects later, becase there might be more keys - // to be added to it. we also want to emit all the set events - // after all values are available. + // observe objects later, because there might be more keys + // to be added to it during Observer.ensurePath(). + // we also want to emit all the set events after all values + // are available. compiler.observables.push(binding) } diff --git a/src/deps-parser.js b/src/deps-parser.js index 36a93112b..8b495ba4c 100644 --- a/src/deps-parser.js +++ b/src/deps-parser.js @@ -9,10 +9,10 @@ var Emitter = require('./emitter'), function catchDeps (binding) { if (binding.isFn) return utils.log('\n─ ' + binding.key) - var depsHash = utils.hash() + var has = [] observer.on('get', function (dep) { - if (depsHash[dep.key]) return - depsHash[dep.key] = 1 + if (has.indexOf(dep) > -1) return + has.push(dep) utils.log(' └─ ' + dep.key) binding.deps.push(dep) dep.subs.push(binding) diff --git a/src/directives/component.js b/src/directives/component.js new file mode 100644 index 000000000..1a3888e94 --- /dev/null +++ b/src/directives/component.js @@ -0,0 +1,40 @@ +var utils = require('../utils') + +module.exports = { + + bind: function () { + if (this.isSimple) { + this.build() + } + }, + + update: function (value) { + if (!this.component) { + this.build(value) + } else { + this.component.model = value + } + }, + + build: function (value) { + var Ctor = this.compiler.getOption('components', this.arg) + if (!Ctor) utils.warn('unknown component: ' + this.arg) + var options = { + el: this.el, + compilerOptions: { + parentCompiler: this.compiler + } + } + if (value) { + options.scope = { + model: value + } + } + this.component = new Ctor(options) + }, + + unbind: function () { + this.component.$destroy() + } + +} \ No newline at end of file diff --git a/src/directives/index.js b/src/directives/index.js index b55f0439f..b73a9e1a7 100644 --- a/src/directives/index.js +++ b/src/directives/index.js @@ -3,10 +3,11 @@ var utils = require('../utils'), module.exports = { - on : require('./on'), - repeat : require('./repeat'), - model : require('./model'), - 'if' : require('./if'), + on : require('./on'), + repeat : require('./repeat'), + model : require('./model'), + 'if' : require('./if'), + component : require('./component'), attr: function (value) { this.el.setAttribute(this.arg, value) diff --git a/src/main.js b/src/main.js index 9403c1881..bd6e7bafd 100644 --- a/src/main.js +++ b/src/main.js @@ -42,15 +42,6 @@ ViewModel.component = function (id, Ctor) { return this } -/** - * Allows user to register/retrieve a Custom element constructor - */ -ViewModel.element = function (id, Ctor) { - if (!Ctor) return utils.elements[id] - utils.elements[id] = utils.toConstructor(Ctor) - return this -} - /** * Allows user to register/retrieve a template partial */ @@ -141,12 +132,12 @@ function inheritOptions (child, parent, topLevel) { * that are used in compilation. */ var specialAttributes = [ - 'id', 'pre', 'text', 'repeat', 'partial', 'component', + 'component-id', 'transition' ] diff --git a/src/observer.js b/src/observer.js index 13a39d09c..fb10de603 100644 --- a/src/observer.js +++ b/src/observer.js @@ -214,10 +214,12 @@ function ensurePath (obj, key) { if (!obj[sec]) obj[sec] = {} obj = obj[sec] } - if (typeOf(obj) === 'Object') { + var type = typeOf(obj) + if (type === 'Object' || type === 'Array') { sec = path[i] if (!(sec in obj)) obj[sec] = undefined } + return obj[sec] } module.exports = { diff --git a/src/utils.js b/src/utils.js index 37dec8041..a1cb7dd97 100644 --- a/src/utils.js +++ b/src/utils.js @@ -22,7 +22,6 @@ var utils = module.exports = { components : makeHash(), partials : makeHash(), transitions : makeHash(), - elements : makeHash(), /** * get an attribute and remove it. @@ -141,11 +140,6 @@ var utils = module.exports = { : null }, - isConstructor: function (obj) { - ViewModel = ViewModel || require('./viewmodel') - return obj.prototype instanceof ViewModel || obj === ViewModel - }, - /** * convert certain option values to the desired format. */ @@ -153,18 +147,12 @@ var utils = module.exports = { var components = options.components, partials = options.partials, template = options.template, - elements = options.elements, key if (components) { for (key in components) { components[key] = utils.toConstructor(components[key]) } } - if (elements) { - for (key in elements) { - elements[key] = utils.toConstructor(elements[key]) - } - } if (partials) { for (key in partials) { partials[key] = utils.toFragment(partials[key]) @@ -185,11 +173,11 @@ var utils = module.exports = { }, /** - * warnings, thrown in all cases + * warnings, traces by default + * can be suppressed by `silent` option. */ warn: function() { if (!config.silent && console) { - console.trace() console.warn(join.call(arguments, ' ')) } } diff --git a/test/functional/fixtures/custom-element.html b/test/functional/fixtures/custom-element.html deleted file mode 100644 index 1d8aee510..000000000 --- a/test/functional/fixtures/custom-element.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - Custom Elements - - - - - afsefsefse - hmm - - - - \ No newline at end of file diff --git a/test/functional/fixtures/encapsulation.html b/test/functional/fixtures/encapsulation.html index b3d10fde7..d84a28d22 100644 --- a/test/functional/fixtures/encapsulation.html +++ b/test/functional/fixtures/encapsulation.html @@ -11,15 +11,21 @@
{{filterMsg | nodigits}}
{{vmMsg}}
+
{{msg + model.msg}}
diff --git a/test/functional/fixtures/nested-props.html b/test/functional/fixtures/nested-props.html index 3396458bf..53ec2475e 100644 --- a/test/functional/fixtures/nested-props.html +++ b/test/functional/fixtures/nested-props.html @@ -24,7 +24,7 @@ var data = { c: 555 } var Demo = Vue.extend({ lazy: true, - ready: function () { + created: function () { this.msg = 'Yoyoyo' this.a = data }, diff --git a/test/functional/fixtures/nested-repeat.html b/test/functional/fixtures/nested-repeat.html index 234504388..ac7be0d5d 100644 --- a/test/functional/fixtures/nested-repeat.html +++ b/test/functional/fixtures/nested-repeat.html @@ -11,7 +11,7 @@
  • @@ -24,6 +24,7 @@