From 2c254d15e5245f6a9631df9e4eda2abdd9112601 Mon Sep 17 00:00:00 2001 From: Evan You Date: Tue, 12 Aug 2014 20:09:37 -0400 Subject: [PATCH] working on compile --- changes.md | 4 ++ src/config.js | 2 +- src/directive.js | 3 +- src/instance/compile.js | 121 +++++++++++++++++++++++++++++++++++++--- src/util/dom.js | 2 +- 5 files changed, 122 insertions(+), 10 deletions(-) diff --git a/changes.md b/changes.md index 651d9cf07..43c6ef760 100644 --- a/changes.md +++ b/changes.md @@ -120,6 +120,10 @@ Instead of the old `Vue.config()` with a heavily overloaded API, the config obje Vue.config.debug = true ``` +## Prefix + +Config prefix now should include the hyphen: so the default is now `v-` and if you want to change it make sure to include the hyphen as well. e.g. `Vue.config.prefix = "data-"`. + ## Interpolation Delimiters In the old version the interpolation delimiters are limited to the same base character (i.e. `['{','}']` translates into `{{}}` for text and `{{{}}}` for HTML). Now you can set them to whatever you like (*almost), and to indicate HTML interpolation, simply wrap the tag with one extra outer most character on each end. Example: diff --git a/src/config.js b/src/config.js index 1a18f18db..fef4a8ede 100644 --- a/src/config.js +++ b/src/config.js @@ -6,7 +6,7 @@ module.exports = { * @type {String} */ - prefix: 'v', + prefix: 'v-', /** * Whether to print debug messages. diff --git a/src/directive.js b/src/directive.js index 5465344b0..5e9da96a9 100644 --- a/src/directive.js +++ b/src/directive.js @@ -31,6 +31,7 @@ function Directive (name, el, vm, descriptor) { this._bound = false // init definition this._initDef() + this._bind() } var p = Directive.prototype @@ -71,7 +72,7 @@ p._bind = function () { ) var value = this._watcher.value if (this.bind) { - this.bind(value) + this.bind() } if (this.update) { this.update(value) diff --git a/src/instance/compile.js b/src/instance/compile.js index f8dc8331c..38829cd50 100644 --- a/src/instance/compile.js +++ b/src/instance/compile.js @@ -1,4 +1,7 @@ +var _ = require('../util') var config = require('../config') +var Direcitve = require('../directive') +var dirParser = require('../parse/directive') /** * The main entrance to the compilation process. @@ -41,9 +44,9 @@ exports._compileNode = function (node) { } /** - * Compile an HTMLElement + * Compile an Element * - * @param {HTMLElement} node + * @param {Element} node */ exports._compileElement = function (node) { @@ -54,15 +57,71 @@ exports._compileElement = function (node) { if (tag === 'TEXTAREA' && node.value) { node.value = this.$interpolate(node.value) } + var hasAttributes = node.hasAttributes() + // check priority directives + if (hasAttributes) { + if (this._checkPriorityDirectives(node)) { + return + } + } + // check tag components if ( - // skip non-component with no attributes - (!node.hasAttributes() && tag.indexOf('-') < 0) || - // skip v-pre - _.attr(node, 'pre') !== null + tag.indexOf('-') > 0 && + this.$options.components[tag] ) { + this._bindDirective('component', tag, node) return } - // TODO + // compile normal directives + if (hasAttributes) { + this._compileAttrs(node) + } + // recursively compile childNodes + if (node.hasChildNodes()) { + _.toArray(node.childNodes) + .forEach(this._compileNode, this) + } +} + +/** + * Compile attribtues on an Element + * + * @param {Element} node + */ + +exports._compileAttrs = function (node) { + var attrs = _.toArray(node.attributes) + var i = attrs.length + var registry = this.$options.directives + var dirs = [] + var attr, attrName, dir, dirName + while (i--) { + attr = attrs[i] + attrName = attr.name + if (attrName.indexOf(config.prefix) === 0) { + dirName = attrName.slice(config.prefix.length) + if (registry[dirName]) { + node.removeAttribute(attrName) + dirs.push({ + name: dirName, + value: attr.value + }) + } else { + _.warn('Unknown directive: ' + dirName) + } + } + } + // sort the directives by priority, low to high + dirs.sort(function (a, b) { + a = registry[a.name].priority || 0 + b = registry[b.name].priority || 0 + return a > b ? 1 : -1 + }) + i = dirs.length + while (i--) { + dir = dirs[i] + this._bindDirective(dir.name, dir.value, node) + } } /** @@ -83,4 +142,52 @@ exports._compileTextNode = function (node) { exports._compileComment = function (node) { +} + +/** + * Check for priority directives that would potentially + * skip other directives: + * + * - v-pre + * - v-repeat + * - v-if + * - v-component + * + * @param {Element} node + * @return {Boolean} + */ + +exports._checkPriorityDirectives = function (node) { + var value + /* jshint boss: true */ + if (_.attr(node, 'pre') !== null) { + return true + } else if (value = _.attr(node, 'repeat')) { + this._bindDirective('repeat', value) + return true + } else if (value = _.attr(node, 'if')) { + this._bindDirective('if', value) + return true + } else if (value = _.attr(node, 'component')) { + this._bindDirective('component', value) + return true + } +} + +/** + * Bind a directive. + * + * @param {String} name + * @param {String} value + * @param {Element} node + */ + +exports._bindDirective = function (name, value, node) { + var descriptors = dirParser.parse(value) + var dirs = this._directives + for (var i = 0, l = descriptors.length; i < l; i++) { + dirs.push( + new Direcitve(name, node, this, descriptors[i]) + ) + } } \ No newline at end of file diff --git a/src/util/dom.js b/src/util/dom.js index 1bd519a95..c4c4b2070 100644 --- a/src/util/dom.js +++ b/src/util/dom.js @@ -8,7 +8,7 @@ var config = require('../config') */ exports.attr = function (node, attr) { - attr = config.prefix + '-' + attr + attr = config.prefix + attr var val = node.getAttribute(attr) node.removeAttribute(attr) return val