Comparing version 0.12.0 to 0.12.1
{ | ||
"name": "vue", | ||
"version": "0.12.0", | ||
"version": "0.12.1", | ||
"author": "Evan You <yyx990803@gmail.com>", | ||
@@ -42,4 +42,4 @@ "license": "MIT", | ||
"uglify-js": "^2.4.20", | ||
"webpack": "^1.8.4" | ||
"webpack": "^1.9.10" | ||
} | ||
} |
@@ -7,2 +7,3 @@ var _ = require('../util') | ||
var resolveAsset = _.resolveAsset | ||
var propBindingModes = config._propBindingModes | ||
@@ -145,4 +146,4 @@ // internal directives | ||
// 1. props | ||
propsLinkFn = props && containerAttrs | ||
? compileProps(el, containerAttrs, props) | ||
propsLinkFn = props | ||
? compileProps(el, containerAttrs || {}, props) | ||
: null | ||
@@ -400,3 +401,3 @@ | ||
* @param {Object} attrs | ||
* @param {Array} propNames | ||
* @param {Array} propDescriptors | ||
* @return {Function} propsLinkFn | ||
@@ -407,11 +408,19 @@ */ | ||
var settablePathRE = /^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*|\[[^\[\]]+\])*$/ | ||
var literalValueRE = /^(true|false|\d+)$/ | ||
var literalValueRE = /^(true|false)$|\d.*/ | ||
var identRE = require('../parsers/path').identRE | ||
function compileProps (el, attrs, propNames) { | ||
function compileProps (el, attrs, propDescriptors) { | ||
var props = [] | ||
var i = propNames.length | ||
var name, value, path, prop, settable, literal, single | ||
var i = propDescriptors.length | ||
var descriptor, name, assertions, value, path, prop, literal, single | ||
while (i--) { | ||
name = propNames[i] | ||
descriptor = propDescriptors[i] | ||
// normalize prop string/descriptor | ||
if (typeof descriptor === 'object') { | ||
name = descriptor.name | ||
assertions = descriptor | ||
} else { | ||
name = descriptor | ||
assertions = null | ||
} | ||
// props could contain dashes, which will be | ||
@@ -442,3 +451,5 @@ // interpreted as minus calculations by the parser | ||
raw: value, | ||
path: path | ||
path: path, | ||
assertions: assertions, | ||
mode: propBindingModes.ONE_WAY | ||
} | ||
@@ -459,20 +470,23 @@ var tokens = textParser.parse(value) | ||
// one time: {{* prop}} | ||
prop.oneTime = | ||
literal || | ||
(single && tokens[0].oneTime) | ||
// check one-way bindings | ||
if (!prop.oneTime) { | ||
settable = !literal && settablePathRE.test(prop.parentPath) | ||
// one way down: {{> prop}} | ||
prop.oneWayDown = | ||
!settable || | ||
(single && tokens[0].oneWay === 60) // < | ||
// one way up: {{< prop}} | ||
prop.oneWayUp = | ||
single && | ||
settable && | ||
tokens[0].oneWay === 62 // > | ||
if (literal || (single && tokens[0].oneTime)) { | ||
prop.mode = propBindingModes.ONE_TIME | ||
} else if ( | ||
!literal && | ||
(single && tokens[0].twoWay) | ||
) { | ||
if (settablePathRE.test(prop.parentPath)) { | ||
prop.mode = propBindingModes.TWO_WAY | ||
} else { | ||
_.warn( | ||
'Cannot bind two-way prop with non-settable ' + | ||
'parent path: ' + prop.parentPath | ||
) | ||
} | ||
} | ||
} | ||
props.push(prop) | ||
} else if (assertions && assertions.required) { | ||
_.warn( | ||
'Missing required prop: ' + name | ||
) | ||
} | ||
@@ -493,3 +507,3 @@ } | ||
var i = props.length | ||
var prop, path | ||
var prop, path, value | ||
while (i--) { | ||
@@ -500,5 +514,8 @@ prop = props[i] | ||
if (vm.$parent) { | ||
if (prop.oneTime) { | ||
if (prop.mode === propBindingModes.ONE_TIME) { | ||
// one time binding | ||
vm.$set(path, vm.$parent.$get(prop.parentPath)) | ||
value = vm.$parent.$get(prop.parentPath) | ||
if (_.assertProp(prop, value)) { | ||
vm.$set(path, value) | ||
} | ||
} else { | ||
@@ -516,4 +533,7 @@ // dynamic binding | ||
} else { | ||
// literal, just set once | ||
vm.$set(path, _.toNumber(prop.raw)) | ||
// literal, cast it and just set once | ||
value = _.toBoolean(_.toNumber(prop.raw)) | ||
if (_.assertProp(prop, value)) { | ||
vm.$set(path, value) | ||
} | ||
} | ||
@@ -520,0 +540,0 @@ } |
@@ -21,6 +21,3 @@ var _ = require('../util') | ||
if (!raw) { | ||
// fallback content | ||
// extract as a fragment | ||
content = _.extractContent(this.el, true) | ||
this.compile(content, vm) | ||
this.fallback() | ||
return | ||
@@ -31,17 +28,33 @@ } | ||
if (!selector) { | ||
// default content | ||
// Importent: clone the rawContent before extracting | ||
// content because the <content> may be inside a v-if | ||
// and need to be compiled more than once. | ||
content = _.extractContent(raw.cloneNode(true), true) | ||
this.compile(content, parent, vm) | ||
// Default content | ||
var self = this | ||
var compileDefaultContent = function () { | ||
self.compile( | ||
extractFragment(raw.childNodes, raw, true), | ||
contentOwner.$parent, | ||
vm | ||
) | ||
} | ||
if (!contentOwner._isCompiled) { | ||
// defer until the end of instance compilation, | ||
// because the default outlet must wait until all | ||
// other possible outlets with selectors have picked | ||
// out their contents. | ||
contentOwner.$once('hook:compiled', compileDefaultContent) | ||
} else { | ||
compileDefaultContent() | ||
} | ||
} else { | ||
// select content | ||
selector = vm.$interpolate(selector) | ||
content = raw.querySelector(selector) | ||
// only allow top-level select | ||
if (content && content.parentNode === raw) { | ||
// same deal, clone the node for v-if | ||
content = content.cloneNode(true) | ||
this.compile(content, parent, vm) | ||
var nodes = raw.querySelectorAll(selector) | ||
if (nodes.length) { | ||
content = extractFragment(nodes, raw) | ||
if (content.hasChildNodes()) { | ||
this.compile(content, parent, vm) | ||
} else { | ||
this.fallback() | ||
} | ||
} else { | ||
this.fallback() | ||
} | ||
@@ -51,2 +64,6 @@ } | ||
fallback: function () { | ||
this.compile(_.extractContent(this.el, true), this.vm) | ||
}, | ||
compile: function (content, owner, host) { | ||
@@ -68,3 +85,31 @@ if (content && owner) { | ||
} | ||
} | ||
/** | ||
* Extract qualified content nodes from a node list. | ||
* | ||
* @param {NodeList} nodes | ||
* @param {Element} parent | ||
* @param {Boolean} main | ||
* @return {DocumentFragment} | ||
*/ | ||
function extractFragment (nodes, parent, main) { | ||
var frag = document.createDocumentFragment() | ||
for (var i = 0, l = nodes.length; i < l; i++) { | ||
var node = nodes[i] | ||
// if this is the main outlet, we want to skip all | ||
// previously selected nodes; | ||
// otherwise, we want to mark the node as selected. | ||
// clone the node so the original raw content remains | ||
// intact. this ensures proper re-compilation in cases | ||
// where the outlet is inside a conditional block | ||
if (main && !node.selected) { | ||
frag.appendChild(node.cloneNode(true)) | ||
} else if (!main && node.parentNode === parent) { | ||
node.selected = true | ||
frag.appendChild(node.cloneNode(true)) | ||
} | ||
} | ||
return frag | ||
} |
@@ -31,4 +31,10 @@ var _ = require('../util') | ||
} | ||
if (options && options.template) { | ||
el = transcludeTemplate(el, options) | ||
if (options) { | ||
if (options._asComponent && !options.template) { | ||
options.template = '<content></content>' | ||
} | ||
if (options.template) { | ||
options._content = _.extractContent(el) | ||
el = transcludeTemplate(el, options) | ||
} | ||
} | ||
@@ -60,3 +66,2 @@ if (el instanceof DocumentFragment) { | ||
} else { | ||
options._content = _.extractContent(el) | ||
var replacer = frag.firstChild | ||
@@ -126,2 +131,2 @@ if (options.replace) { | ||
} | ||
} | ||
} |
@@ -78,4 +78,14 @@ module.exports = { | ||
'transition' | ||
] | ||
], | ||
/** | ||
* prop binding modes | ||
*/ | ||
_propBindingModes: { | ||
ONE_WAY: 0, | ||
TWO_WAY: 1, | ||
ONE_TIME: 2 | ||
} | ||
} | ||
@@ -100,2 +110,2 @@ | ||
} | ||
}) | ||
}) |
@@ -0,2 +1,4 @@ | ||
var _ = require('../util') | ||
var Watcher = require('../watcher') | ||
var bindingModes = require('../config')._propBindingModes | ||
@@ -19,21 +21,24 @@ module.exports = { | ||
if (!prop.oneWayUp) { | ||
this.parentWatcher = new Watcher( | ||
parent, | ||
parentKey, | ||
function (val) { | ||
if (!locked) { | ||
locked = true | ||
// all props have been initialized already | ||
this.parentWatcher = new Watcher( | ||
parent, | ||
parentKey, | ||
function (val) { | ||
if (!locked) { | ||
locked = true | ||
// all props have been initialized already | ||
if (_.assertProp(prop, val)) { | ||
child[childKey] = val | ||
locked = false | ||
} | ||
}, | ||
{ sync: true } | ||
) | ||
// set the child initial value first, before setting | ||
// up the child watcher to avoid triggering it | ||
// immediately. | ||
child.$set(childKey, this.parentWatcher.value) | ||
locked = false | ||
} | ||
}, | ||
{ sync: true } | ||
) | ||
// set the child initial value first, before setting | ||
// up the child watcher to avoid triggering it | ||
// immediately. | ||
var value = this.parentWatcher.value | ||
if (_.assertProp(prop, value)) { | ||
child.$set(childKey, value) | ||
} | ||
@@ -43,3 +48,3 @@ | ||
// binding. | ||
if (!prop.oneWayDown) { | ||
if (prop.mode === bindingModes.TWO_WAY) { | ||
this.childWatcher = new Watcher( | ||
@@ -57,7 +62,2 @@ child, | ||
) | ||
// set initial value for one-way up binding | ||
if (prop.oneWayUp) { | ||
parent.$set(parentKey, this.childWatcher.value) | ||
} | ||
} | ||
@@ -64,0 +64,0 @@ }, |
@@ -105,3 +105,3 @@ var _ = require('../util') | ||
// extract inline template as a DocumentFragment | ||
this.inlineTempalte = _.extractContent(this.el, true) | ||
this.inlineTemplate = _.extractContent(this.el, true) | ||
} | ||
@@ -354,3 +354,3 @@ var tokens = textParser.parse(id) | ||
inherit: this.inherit, | ||
template: this.inlineTempalte, | ||
template: this.inlineTemplate, | ||
// repeater meta, e.g. $index, $key | ||
@@ -363,3 +363,3 @@ _meta: meta, | ||
// linker cachable if no inline-template | ||
_linkerCachable: !this.inlineTempalte, | ||
_linkerCachable: !this.inlineTemplate, | ||
// transclusion host | ||
@@ -366,0 +366,0 @@ _host: this._host, |
@@ -92,2 +92,2 @@ var mergeOptions = require('../util').mergeOptions | ||
} | ||
} | ||
} |
@@ -14,2 +14,3 @@ var _ = require('../util') | ||
exports._initScope = function () { | ||
this._initProps() | ||
this._initData() | ||
@@ -22,15 +23,20 @@ this._initComputed() | ||
/** | ||
* Initialize the data. | ||
* Initialize props. | ||
*/ | ||
exports._initData = function () { | ||
// proxy data on instance | ||
exports._initProps = function () { | ||
// make sure all props properties are observed | ||
var data = this._data | ||
var i, key | ||
// make sure all props properties are observed | ||
var props = this.$options.props | ||
var prop, key, i | ||
if (props) { | ||
i = props.length | ||
while (i--) { | ||
key = _.camelize(props[i]) | ||
prop = props[i] | ||
// props can be strings or object descriptors | ||
key = _.camelize( | ||
typeof prop === 'string' | ||
? prop | ||
: prop.name | ||
) | ||
if (!(key in data) && key !== '$data') { | ||
@@ -41,3 +47,13 @@ data[key] = undefined | ||
} | ||
} | ||
/** | ||
* Initialize the data. | ||
*/ | ||
exports._initData = function () { | ||
// proxy data on instance | ||
var data = this._data | ||
var keys = Object.keys(data) | ||
var i, key | ||
i = keys.length | ||
@@ -44,0 +60,0 @@ while (i--) { |
@@ -68,2 +68,3 @@ var Cache = require('../cache') | ||
} | ||
text = text.replace(/\n/g, '') | ||
if (!tagRE.test(text)) { | ||
@@ -74,3 +75,3 @@ return null | ||
var lastIndex = tagRE.lastIndex = 0 | ||
var match, index, value, first, oneTime, oneWay | ||
var match, index, value, first, oneTime, twoWay | ||
/* jshint boss:true */ | ||
@@ -87,5 +88,5 @@ while (match = tagRE.exec(text)) { | ||
first = match[1].charCodeAt(0) | ||
oneTime = first === 42 // * | ||
oneWay = first === 62 || first === 60 // > or < | ||
value = oneTime || oneWay | ||
oneTime = first === 42 // * | ||
twoWay = first === 64 // @ | ||
value = oneTime || twoWay | ||
? match[1].slice(1) | ||
@@ -98,3 +99,3 @@ : match[1] | ||
oneTime: oneTime, | ||
oneWay: oneWay ? first : 0 | ||
twoWay: twoWay | ||
}) | ||
@@ -101,0 +102,0 @@ lastIndex = index + match[0].length |
@@ -45,2 +45,17 @@ /** | ||
/** | ||
* Convert string boolean literals into real booleans. | ||
* | ||
* @param {*} value | ||
* @return {*|Boolean} | ||
*/ | ||
exports.toBoolean = function (value) { | ||
return value === 'true' | ||
? true | ||
: value === 'false' | ||
? false | ||
: value | ||
} | ||
/** | ||
* Strip quotes from a string | ||
@@ -270,2 +285,2 @@ * | ||
return cb | ||
} | ||
} |
var _ = require('./index') | ||
var config = require('../config') | ||
var commonTagRE = /^(div|p|span|img|a|br|ul|ol|li|h1|h2|h3|h4|h5|code|pre)$/ | ||
var tableElementsRE = /^caption|colgroup|thead|tfoot|tbody|tr|td|th$/ | ||
/** | ||
* Assert whether a prop is valid. | ||
* | ||
* @param {Object} prop | ||
* @param {*} value | ||
*/ | ||
exports.assertProp = function (prop, value) { | ||
var assertions = prop.assertions | ||
if (!assertions) { | ||
return true | ||
} | ||
var type = assertions.type | ||
var valid = true | ||
var expectedType | ||
if (type) { | ||
if (type === String) { | ||
expectedType = 'string' | ||
valid = typeof value === expectedType | ||
} else if (type === Number) { | ||
expectedType = 'number' | ||
valid = typeof value === 'number' | ||
} else if (type === Boolean) { | ||
expectedType = 'boolean' | ||
valid = typeof value === 'boolean' | ||
} else if (type === Function) { | ||
expectedType = 'function' | ||
valid = typeof value === 'function' | ||
} else if (type === Object) { | ||
expectedType = 'object' | ||
valid = _.isPlainObject(value) | ||
} else if (type === Array) { | ||
expectedType = 'array' | ||
valid = _.isArray(value) | ||
} else { | ||
valid = value instanceof type | ||
} | ||
} | ||
if (!valid) { | ||
_.warn( | ||
'Invalid prop: type check failed for ' + | ||
prop.path + '="' + prop.raw + '".' + | ||
' Expected ' + formatType(expectedType) + | ||
', got ' + formatValue(value) + '.' | ||
) | ||
return false | ||
} | ||
var validator = assertions.validator | ||
if (validator) { | ||
if (!validator.call(null, value)) { | ||
_.warn( | ||
'Invalid prop: custom validator check failed for ' + | ||
prop.path + '="' + prop.raw + '"' | ||
) | ||
return false | ||
} | ||
} | ||
return true | ||
} | ||
function formatType (val) { | ||
return val | ||
? val.charAt(0).toUpperCase() + val.slice(1) | ||
: 'custom type' | ||
} | ||
function formatValue (val) { | ||
return Object.prototype.toString.call(val).slice(8, -1) | ||
} | ||
/** | ||
* Check if an element is a component, if yes return its | ||
@@ -15,2 +83,5 @@ * component id. | ||
var commonTagRE = /^(div|p|span|img|a|br|ul|ol|li|h1|h2|h3|h4|h5|code|pre)$/ | ||
var tableElementsRE = /^caption|colgroup|thead|tfoot|tbody|tr|td|th$/ | ||
exports.checkComponent = function (el, options) { | ||
@@ -17,0 +88,0 @@ var tag = el.tagName.toLowerCase() |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
780216
16996
8