Comparing version 0.12.0-beta5 to 0.12.0-csp
@@ -6,4 +6,18 @@ /** | ||
module.exports = function (grunt) { | ||
grunt.registerTask('build', function () { | ||
grunt.registerTask('build-vendor', function () { | ||
var webpack = require('webpack') | ||
webpack({ | ||
entry: './node_modules/notevil/index.js', | ||
output: { | ||
path: './vendor', | ||
filename: 'notevil.js', | ||
library: 'notevil', | ||
libraryTarget: 'commonjs2' | ||
} | ||
}, this.async()) | ||
}) | ||
grunt.registerTask('build-self', function () { | ||
var done = this.async() | ||
@@ -21,13 +35,2 @@ var fs = require('fs') | ||
' */\n' | ||
// update component.json first | ||
var jsRE = /\.js$/ | ||
var component = grunt.file.readJSON('component.json') | ||
component.scripts = [] | ||
grunt.file.recurse('src', function (file) { | ||
if (jsRE.test(file)) { | ||
component.scripts.push(file) | ||
} | ||
}) | ||
grunt.file.write('component.json', JSON.stringify(component, null, 2)) | ||
@@ -95,2 +98,4 @@ // build | ||
}) | ||
} | ||
grunt.registerTask('build', ['build-vendor', 'build-self']) | ||
} |
{ | ||
"name": "vue", | ||
"version": "0.12.0-beta5", | ||
"version": "0.12.0-csp", | ||
"author": "Evan You <yyx990803@gmail.com>", | ||
@@ -43,3 +43,6 @@ "license": "MIT", | ||
"webpack": "^1.8.4" | ||
}, | ||
"dependencies": { | ||
"notevil": "^1.0.0" | ||
} | ||
} |
@@ -0,1 +1,7 @@ | ||
# CSP compliant build | ||
This is the CSP-compliant build of Vue.js that does not use `new Function()` for expression evaluation. Note there's an additional limitation compared to the normal build: you cannot use any globals in expressions (e.g. `Date`, `parseInt` etc.). | ||
--- | ||
<p align="center"><a href="http://vuejs.org" target="_blank"><img width="100"src="http://vuejs.org/images/logo.png"></a></p> | ||
@@ -5,54 +11,32 @@ | ||
> MVVM made simple. | ||
## Intro | ||
## Introduction | ||
Vue.js is a library for building interactive web interfaces. It provides data-reactive components with a simple and flexible API. Core features include: | ||
Vue.js is a library for building interactive web interfaces. It provides the benefits of MVVM data binding and a composable component system with a simple and flexible API. You should try it out if you like: | ||
- Two-way data binding | ||
- Plain JavaScript objects as reactive models | ||
- Component-oriented development style | ||
- Intuitive API that simply makes sense | ||
- Extendable Data bindings | ||
- Plain JavaScript objects as models | ||
- Building interface by composing reusable components | ||
- Flexibility to mix & match the view layer with other libraries | ||
Note that Vue.js only supports [ES5-compliant browsers](http://kangax.github.io/compat-table/es5/) (IE8 and below are not supported). To check out live examples and docs, visit [vuejs.org](http://vuejs.org). You can also start with this excellent screencast series on [Laracasts](https://laracasts.com/series/learning-vuejs). | ||
It's really really easy to get started. Seriously, it's so easy: | ||
## Questions | ||
``` html | ||
<div id="demo"> | ||
{{message}} | ||
<input v-model="message"> | ||
</div> | ||
``` | ||
For questions and support please use the Gitter room: [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/yyx990803/vue) or submit issues at [vuejs/Discussion](https://github.com/vuejs/Discussion/issues). The issue list of this repo is **exclusively** for bug reports and feature requests. | ||
``` js | ||
var demo = new Vue({ | ||
el: '#demo', | ||
data: { | ||
message: 'Hello Vue.js!' | ||
} | ||
}) | ||
``` | ||
## Issues | ||
To check out the live demo, guides and API reference, visit [vuejs.org](http://vuejs.org). | ||
Please make sure to read the [Issue Reporting Checklist](https://github.com/yyx990803/vue/blob/dev/CONTRIBUTING.md#issue-reporting-guidelines) before opening an issue. Issues not conforming to the guidelines may be closed immediately. | ||
## Browser Support | ||
## Contribution | ||
Vue.js supports [most ECMAScript 5 compliant browsers](https://saucelabs.com/u/vuejs), essentially IE9+. IE8 and below are not supported. | ||
Please make sure to read the [Contributing Guide](https://github.com/yyx990803/vue/blob/dev/CONTRIBUTING.md) before making a pull request. If you have a Vue-related project/component/tool, add it to [this list](https://github.com/yyx990803/vue/wiki/User-Contributed-Components-&-Tools)! | ||
## Contribution | ||
## Changelog | ||
Read the [contributing guide](https://github.com/yyx990803/vue/blob/master/CONTRIBUTING.md). | ||
Details changes for each release are documented in the [release notes](https://github.com/yyx990803/vue/releases). | ||
## Get in Touch | ||
## Stay In Touch | ||
- For latest releases and announcements, follow on Twitter: [@vuejs](https://twitter.com/vuejs) | ||
- Live discussion: [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/yyx990803/vue) | ||
- Bugs reports: first read the [issue checklist](https://github.com/yyx990803/vue/blob/master/CONTRIBUTING.md#issue-reporting-checklist), then [open an issue](https://github.com/yyx990803/vue/issues). | ||
- Questions, suggestions, feature requests: open an issue at [vuejs/Discussion](https://github.com/vuejs/Discussion/issues). | ||
- If you have a Vue-related project/component/tool, add it to [this list](https://github.com/yyx990803/vue/wiki/User-Contributed-Components-&-Tools)! | ||
## Changelog | ||
Details changes for each release are documented in the [release notes](https://github.com/yyx990803/vue/releases). | ||
## License | ||
@@ -62,2 +46,2 @@ | ||
Copyright (c) 2014 Evan You | ||
Copyright (c) 2014 Evan You |
@@ -26,12 +26,8 @@ var _ = require('../util') | ||
if (!ChildVue) { | ||
var optionName = BaseCtor.options.name | ||
var className = optionName | ||
? _.classify(optionName) | ||
: 'VueComponent' | ||
ChildVue = new Function( | ||
'return function ' + className + ' (options) {' + | ||
'this.constructor = ' + className + ';' + | ||
'this._init(options) }' | ||
)() | ||
ChildVue = function VueComponent (options) { | ||
this.constructor = ChildVue | ||
this._init(options) | ||
} | ||
ChildVue.options = BaseCtor.options | ||
ChildVue.linker = BaseCtor.linker | ||
ChildVue.prototype = this | ||
@@ -38,0 +34,0 @@ ctors[BaseCtor.cid] = ChildVue |
@@ -18,3 +18,5 @@ var Watcher = require('../watcher') | ||
if (res) { | ||
return res.get.call(this, this) | ||
try { | ||
return res.get.call(this, this) | ||
} catch (e) {} | ||
} | ||
@@ -66,8 +68,10 @@ } | ||
* @param {Function} cb | ||
* @param {Boolean} [deep] | ||
* @param {Boolean} [immediate] | ||
* @param {Object} [options] | ||
* - {Boolean} deep | ||
* - {Boolean} immediate | ||
* - {Boolean} user | ||
* @return {Function} - unwatchFn | ||
*/ | ||
exports.$watch = function (exp, cb, deep, immediate) { | ||
exports.$watch = function (exp, cb, options) { | ||
var vm = this | ||
@@ -78,6 +82,6 @@ var wrappedCb = function (val, oldVal) { | ||
var watcher = new Watcher(vm, exp, wrappedCb, { | ||
deep: deep, | ||
user: true | ||
deep: options && options.deep, | ||
user: !options || options.user !== false | ||
}) | ||
if (immediate) { | ||
if (options && options.immediate) { | ||
wrappedCb(watcher.value) | ||
@@ -153,2 +157,2 @@ } | ||
console.log(data) | ||
} | ||
} |
@@ -90,2 +90,5 @@ var _ = require('../util') | ||
exports.$remove = function (cb, withTransition) { | ||
if (!this.$el.parentNode) { | ||
return cb && cb() | ||
} | ||
var inDoc = this._isAttached && _.inDoc(this.$el) | ||
@@ -224,2 +227,2 @@ // if we are not in document, no need to check | ||
if (cb) cb() | ||
} | ||
} |
@@ -11,8 +11,4 @@ var _ = require('../util') | ||
exports.config = require('../config') | ||
exports.compiler = require('../compiler') | ||
exports.compiler = { | ||
compile: require('../compiler/compile'), | ||
transclude: require('../compiler/transclude') | ||
} | ||
exports.parsers = { | ||
@@ -44,7 +40,5 @@ path: require('../parsers/path'), | ||
var Super = this | ||
var Sub = createClass( | ||
extendOptions.name || | ||
Super.options.name || | ||
'VueComponent' | ||
) | ||
var Sub = function VueComponent (options) { | ||
_.Vue.call(this, options) | ||
} | ||
Sub.prototype = Object.create(Super.prototype) | ||
@@ -67,18 +61,2 @@ Sub.prototype.constructor = Sub | ||
/** | ||
* A function that returns a sub-class constructor with the | ||
* given name. This gives us much nicer output when | ||
* logging instances in the console. | ||
* | ||
* @param {String} name | ||
* @return {Function} | ||
*/ | ||
function createClass (name) { | ||
return new Function( | ||
'return function ' + _.classify(name) + | ||
' (options) { this._init(options) }' | ||
)() | ||
} | ||
/** | ||
* Plugin system | ||
@@ -146,2 +124,2 @@ * | ||
createAssetRegisters(exports) | ||
createAssetRegisters(exports) |
var _ = require('../util') | ||
var compile = require('../compiler/compile') | ||
var compiler = require('../compiler') | ||
@@ -67,7 +67,8 @@ /** | ||
* @param {Element|DocumentFragment} el | ||
* @param {Vue} [host] | ||
* @return {Function} | ||
*/ | ||
exports.$compile = function (el) { | ||
return compile(el, this.$options, true)(this, el) | ||
exports.$compile = function (el, host) { | ||
return compiler.compile(el, this.$options, true, host)(this, el) | ||
} |
@@ -15,2 +15,3 @@ var _ = require('./util') | ||
var flushing = false | ||
var internalQueueDepleted = false | ||
@@ -25,4 +26,3 @@ /** | ||
has = {} | ||
waiting = false | ||
flushing = false | ||
waiting = flushing = internalQueueDepleted = false | ||
} | ||
@@ -37,2 +37,3 @@ | ||
run(queue) | ||
internalQueueDepleted = true | ||
run(userQueue) | ||
@@ -87,3 +88,3 @@ reset() | ||
// we call that update immediately as it is pushed. | ||
if (flushing && !job.user) { | ||
if (flushing && !job.user && internalQueueDepleted) { | ||
job.run() | ||
@@ -90,0 +91,0 @@ return |
@@ -18,22 +18,25 @@ var _ = require('../util') | ||
module.exports = compile | ||
/** | ||
* Compile a template and return a reusable composite link | ||
* function, which recursively contains more link functions | ||
* inside. This top level compile function should only be | ||
* called on instance root nodes. | ||
* inside. This top level compile function would normally | ||
* be called on instance root nodes, but can also be used | ||
* for partial compilation if the partial argument is true. | ||
* | ||
* The returned composite link function, when called, will | ||
* return an unlink function that tearsdown all directives | ||
* created during the linking phase. | ||
* | ||
* @param {Element|DocumentFragment} el | ||
* @param {Object} options | ||
* @param {Boolean} partial | ||
* @param {Boolean} transcluded | ||
* @param {Vue} [host] - host vm of transcluded content | ||
* @return {Function} | ||
*/ | ||
function compile (el, options, partial, transcluded) { | ||
exports.compile = function (el, options, partial, host) { | ||
// link function for the node itself. | ||
var nodeLinkFn = options._asComponent && !partial | ||
? compileRoot(el, options) | ||
: compileNode(el, options) | ||
var nodeLinkFn = partial || !options._asComponent | ||
? compileNode(el, options) | ||
: null | ||
// link function for the childNodes | ||
@@ -57,24 +60,11 @@ var childLinkFn = | ||
function compositeLinkFn (vm, el) { | ||
// save original directive count before linking | ||
// so we can capture the directives created during a | ||
// partial compilation. | ||
var originalDirCount = vm._directives.length | ||
var parentOriginalDirCount = | ||
vm.$parent && vm.$parent._directives.length | ||
return function compositeLinkFn (vm, el) { | ||
// cache childNodes before linking parent, fix #657 | ||
var childNodes = _.toArray(el.childNodes) | ||
// if this is a transcluded compile, linkers need to be | ||
// called in source scope, and the host needs to be | ||
// passed down. | ||
var source = transcluded ? vm.$parent : vm | ||
var host = transcluded ? vm : undefined | ||
// link | ||
if (nodeLinkFn) nodeLinkFn(source, el, host) | ||
if (childLinkFn) childLinkFn(source, childNodes, host) | ||
var dirs = linkAndCapture(function () { | ||
if (nodeLinkFn) nodeLinkFn(vm, el, host) | ||
if (childLinkFn) childLinkFn(vm, childNodes, host) | ||
}, vm) | ||
var selfDirs = vm._directives.slice(originalDirCount) | ||
var parentDirs = vm.$parent && | ||
vm.$parent._directives.slice(parentOriginalDirCount) | ||
/** | ||
@@ -88,20 +78,23 @@ * The linker function returns an unlink function that | ||
return function unlink (destroying) { | ||
teardownDirs(vm, selfDirs, destroying) | ||
if (parentDirs) { | ||
teardownDirs(vm.$parent, parentDirs) | ||
} | ||
teardownDirs(vm, dirs, destroying) | ||
} | ||
} | ||
} | ||
// transcluded linkFns are terminal, because it takes | ||
// over the entire sub-tree. | ||
if (transcluded) { | ||
compositeLinkFn.terminal = true | ||
} | ||
/** | ||
* Apply a linker to a vm/element pair and capture the | ||
* directives created during the process. | ||
* | ||
* @param {Function} linker | ||
* @param {Vue} vm | ||
*/ | ||
return compositeLinkFn | ||
function linkAndCapture (linker, vm) { | ||
var originalDirCount = vm._directives.length | ||
linker() | ||
return vm._directives.slice(originalDirCount) | ||
} | ||
/** | ||
* Teardown a subset of directives on a vm. | ||
* Teardown partial linked directives. | ||
* | ||
@@ -114,2 +107,3 @@ * @param {Vue} vm | ||
function teardownDirs (vm, dirs, destroying) { | ||
if (!dirs) return | ||
var i = dirs.length | ||
@@ -125,5 +119,5 @@ while (i--) { | ||
/** | ||
* Compile the root element of a component. There are | ||
* Compile the root element of an instance. There are | ||
* 3 types of things to process here: | ||
* | ||
* | ||
* 1. props on parent container (child scope) | ||
@@ -137,2 +131,8 @@ * 2. other attrs on parent container (parent scope) | ||
* | ||
* This function does compile and link at the same time, | ||
* since root linkers can not be reused. It returns the | ||
* unlink function for potential parent directives on the | ||
* container. | ||
* | ||
* @param {Vue} vm | ||
* @param {Element} el | ||
@@ -143,4 +143,3 @@ * @param {Object} options | ||
function compileRoot (el, options) { | ||
var isBlock = el.nodeType === 11 // DocumentFragment | ||
exports.compileAndLinkRoot = function (vm, el, options) { | ||
var containerAttrs = options._containerAttrs | ||
@@ -150,22 +149,48 @@ var replacerAttrs = options._replacerAttrs | ||
var propsLinkFn, parentLinkFn, replacerLinkFn | ||
// 1. props | ||
propsLinkFn = props | ||
propsLinkFn = props && containerAttrs | ||
? compileProps(el, containerAttrs, props) | ||
: null | ||
if (!isBlock) { | ||
// 2. container attributes | ||
if (containerAttrs) { | ||
parentLinkFn = compileDirectives(containerAttrs, options) | ||
// only need to compile other attributes for | ||
// non-block instances | ||
if (el.nodeType !== 11) { | ||
// for components, container and replacer need to be | ||
// compiled separately and linked in different scopes. | ||
if (options._asComponent) { | ||
// 2. container attributes | ||
if (containerAttrs) { | ||
parentLinkFn = compileDirectives(containerAttrs, options) | ||
} | ||
if (replacerAttrs) { | ||
// 3. replacer attributes | ||
replacerLinkFn = compileDirectives(replacerAttrs, options) | ||
} | ||
} else { | ||
// non-component, just compile as a normal element. | ||
replacerLinkFn = compileDirectives(el, options) | ||
} | ||
if (replacerAttrs) { | ||
// 3. replacer attributes | ||
replacerLinkFn = compileDirectives(replacerAttrs, options) | ||
} | ||
} | ||
return function rootLinkFn (vm, el, host) { | ||
// explicitly passing null to props | ||
// linkers because they don't need a real element | ||
// link parent dirs | ||
var parent = vm.$parent | ||
var parentDirs | ||
if (parent && parentLinkFn) { | ||
parentDirs = linkAndCapture(function () { | ||
parentLinkFn(parent, el) | ||
}, parent) | ||
} | ||
// link self | ||
var selfDirs = linkAndCapture(function () { | ||
if (propsLinkFn) propsLinkFn(vm, null) | ||
if (parentLinkFn) parentLinkFn(vm.$parent, el, host) | ||
if (replacerLinkFn) replacerLinkFn(vm, el, host) | ||
if (replacerLinkFn) replacerLinkFn(vm, el) | ||
}, vm) | ||
// return the unlink function that tearsdown parent | ||
// container directives. | ||
return function rootUnlinkFn () { | ||
teardownDirs(parent, parentDirs) | ||
teardownDirs(vm, selfDirs) | ||
} | ||
@@ -203,14 +228,6 @@ } | ||
function compileElement (el, options) { | ||
if (checkTransclusion(el)) { | ||
// unwrap textNode | ||
if (el.hasAttribute('__vue__wrap')) { | ||
el = el.firstChild | ||
} | ||
return compile(el, options._parent.$options, true, true) | ||
} | ||
var linkFn | ||
var hasAttrs = el.hasAttributes() | ||
// check element directives | ||
linkFn = checkElementDirectives(el, options) | ||
// check terminal direcitves (repeat & if) | ||
var linkFn = checkElementDirectives(el, options) | ||
// check terminal directives (repeat & if) | ||
if (!linkFn && hasAttrs) { | ||
@@ -394,5 +411,6 @@ linkFn = checkTerminalDirectives(el, options) | ||
// regex to test if a path is "settable" | ||
// if not the prop binding is automatically one-way. | ||
var settablePathRE = /^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*|\[[^\[\]]\])*$/ | ||
var dataAttrRE = /^data-/ | ||
var settablePathRE = /^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*|\[[^\[\]]+\])*$/ | ||
var literalValueRE = /^(true|false|\d+)$/ | ||
var identRE = require('../parsers/path').identRE | ||
@@ -402,5 +420,9 @@ function compileProps (el, attrs, propNames) { | ||
var i = propNames.length | ||
var name, value, prop | ||
var name, value, path, prop, settable, literal, single | ||
while (i--) { | ||
name = propNames[i] | ||
// props could contain dashes, which will be | ||
// interpreted as minus calculations by the parser | ||
// so we need to camelize the path here | ||
path = _.camelize(name.replace(dataAttrRE, '')) | ||
if (/[A-Z]/.test(name)) { | ||
@@ -415,2 +437,8 @@ _.warn( | ||
} | ||
if (!identRE.test(path)) { | ||
_.warn( | ||
'Invalid prop key: "' + name + '". Prop keys ' + | ||
'must be valid identifiers.' | ||
) | ||
} | ||
value = attrs[name] | ||
@@ -421,3 +449,4 @@ /* jshint eqeqeq:false */ | ||
name: name, | ||
value: value | ||
raw: value, | ||
path: path | ||
} | ||
@@ -429,9 +458,27 @@ var tokens = textParser.parse(value) | ||
} | ||
// important so that this doesn't get compiled | ||
// again as a normal attribute binding | ||
attrs[name] = null | ||
prop.dynamic = true | ||
prop.value = textParser.tokensToExp(tokens) | ||
prop.parentPath = textParser.tokensToExp(tokens) | ||
// check prop binding type. | ||
single = tokens.length === 1 | ||
literal = literalValueRE.test(prop.parentPath) | ||
// one time: {{* prop}} | ||
prop.oneTime = | ||
tokens.length > 1 || | ||
tokens[0].oneTime || | ||
!settablePathRE.test(prop.value) | ||
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 // > | ||
} | ||
} | ||
@@ -451,4 +498,2 @@ props.push(prop) | ||
var dataAttrRE = /^data-/ | ||
function makePropsLinkFn (props) { | ||
@@ -460,15 +505,22 @@ return function propsLinkFn (vm, el) { | ||
prop = props[i] | ||
// props could contain dashes, which will be | ||
// interpreted as minus calculations by the parser | ||
// so we need to wrap the path here | ||
path = _.camelize(prop.name.replace(dataAttrRE, '')) | ||
path = prop.path | ||
if (prop.dynamic) { | ||
vm._bindDir('prop', el, { | ||
arg: path, | ||
expression: prop.value, | ||
oneWay: prop.oneTime | ||
}, propDef) | ||
if (vm.$parent) { | ||
if (prop.oneTime) { | ||
// one time binding | ||
vm.$set(path, vm.$parent.$get(prop.parentPath)) | ||
} else { | ||
// dynamic binding | ||
vm._bindDir('prop', el, prop, propDef) | ||
} | ||
} else { | ||
_.warn( | ||
'Cannot bind dynamic prop on a root instance' + | ||
' with no parent: ' + prop.name + '="' + | ||
prop.raw + '"' | ||
) | ||
} | ||
} else { | ||
// just set once | ||
vm.$set(path, prop.value) | ||
// literal, just set once | ||
vm.$set(path, _.toNumber(prop.raw)) | ||
} | ||
@@ -711,16 +763,1 @@ } | ||
} | ||
/** | ||
* Check whether an element is transcluded | ||
* | ||
* @param {Element} el | ||
* @return {Boolean} | ||
*/ | ||
var transcludedFlagAttr = '__vue__transcluded' | ||
function checkTransclusion (el) { | ||
if (el.nodeType === 1 && el.hasAttribute(transcludedFlagAttr)) { | ||
el.removeAttribute(transcludedFlagAttr) | ||
return true | ||
} | ||
} |
var _ = require('../util') | ||
var config = require('../config') | ||
var templateParser = require('../parsers/template') | ||
var transcludedFlagAttr = '__vue__transcluded' | ||
@@ -18,32 +17,14 @@ /** | ||
module.exports = function transclude (el, options) { | ||
if (options && options._asComponent) { | ||
// extract container attributes to pass them down | ||
// to compiler, because they need to be compiled in | ||
// parent scope. we are mutating the options object here | ||
// assuming the same object will be used for compile | ||
// right after this. | ||
exports.transclude = function (el, options) { | ||
// extract container attributes to pass them down | ||
// to compiler, because they need to be compiled in | ||
// parent scope. we are mutating the options object here | ||
// assuming the same object will be used for compile | ||
// right after this. | ||
if (options) { | ||
options._containerAttrs = extractAttrs(el) | ||
// Mark content nodes and attrs so that the compiler | ||
// knows they should be compiled in parent scope. | ||
var i = el.childNodes.length | ||
while (i--) { | ||
var node = el.childNodes[i] | ||
if (node.nodeType === 1) { | ||
node.setAttribute(transcludedFlagAttr, '') | ||
} else if (node.nodeType === 3 && node.data.trim()) { | ||
// wrap transcluded textNodes in spans, because | ||
// raw textNodes can't be persisted through clones | ||
// by attaching attributes. | ||
var wrapper = document.createElement('span') | ||
wrapper.textContent = node.data | ||
wrapper.setAttribute('__vue__wrap', '') | ||
wrapper.setAttribute(transcludedFlagAttr, '') | ||
el.replaceChild(wrapper, node) | ||
} | ||
} | ||
} | ||
// for template tags, what we want is its content as | ||
// a documentFragment (for block instances) | ||
if (el.tagName === 'TEMPLATE') { | ||
if (_.isTemplate(el)) { | ||
el = templateParser.parse(el) | ||
@@ -79,3 +60,3 @@ } | ||
} else { | ||
var rawContent = options._content || _.extractContent(el) | ||
options._content = _.extractContent(el) | ||
var replacer = frag.firstChild | ||
@@ -91,3 +72,2 @@ if (options.replace) { | ||
) { | ||
transcludeContent(frag, rawContent) | ||
return frag | ||
@@ -97,3 +77,2 @@ } else { | ||
mergeAttrs(el, replacer) | ||
transcludeContent(replacer, rawContent) | ||
return replacer | ||
@@ -103,3 +82,2 @@ } | ||
el.appendChild(frag) | ||
transcludeContent(el, rawContent) | ||
return el | ||
@@ -111,108 +89,19 @@ } | ||
/** | ||
* Resolve <content> insertion points mimicking the behavior | ||
* of the Shadow DOM spec: | ||
* | ||
* http://w3c.github.io/webcomponents/spec/shadow/#insertion-points | ||
* | ||
* @param {Element|DocumentFragment} el | ||
* @param {Element} raw | ||
*/ | ||
function transcludeContent (el, raw) { | ||
var outlets = getOutlets(el) | ||
var i = outlets.length | ||
if (!i) return | ||
var outlet, select, selected, j, main | ||
function isDirectChild (node) { | ||
return node.parentNode === raw | ||
} | ||
// first pass, collect corresponding content | ||
// for each outlet. | ||
while (i--) { | ||
outlet = outlets[i] | ||
if (raw) { | ||
select = outlet.getAttribute('select') | ||
if (select) { // select content | ||
selected = raw.querySelectorAll(select) | ||
if (selected.length) { | ||
// according to Shadow DOM spec, `select` can | ||
// only select direct children of the host node. | ||
// enforcing this also fixes #786. | ||
selected = [].filter.call(selected, isDirectChild) | ||
} | ||
outlet.content = selected.length | ||
? selected | ||
: _.toArray(outlet.childNodes) | ||
} else { // default content | ||
main = outlet | ||
} | ||
} else { // fallback content | ||
outlet.content = _.toArray(outlet.childNodes) | ||
} | ||
} | ||
// second pass, actually insert the contents | ||
for (i = 0, j = outlets.length; i < j; i++) { | ||
outlet = outlets[i] | ||
if (outlet !== main) { | ||
insertContentAt(outlet, outlet.content) | ||
} | ||
} | ||
// finally insert the main content | ||
if (main) { | ||
insertContentAt(main, _.toArray(raw.childNodes)) | ||
} | ||
} | ||
/** | ||
* Get <content> outlets from the element/list | ||
* | ||
* @param {Element|Array} el | ||
* @return {Array} | ||
*/ | ||
var concat = [].concat | ||
function getOutlets (el) { | ||
return _.isArray(el) | ||
? concat.apply([], el.map(getOutlets)) | ||
: el.querySelectorAll | ||
? _.toArray(el.querySelectorAll('content')) | ||
: [] | ||
} | ||
/** | ||
* Insert an array of nodes at outlet, | ||
* then remove the outlet. | ||
* | ||
* @param {Element} outlet | ||
* @param {Array} contents | ||
*/ | ||
function insertContentAt (outlet, contents) { | ||
// not using util DOM methods here because | ||
// parentNode can be cached | ||
var parent = outlet.parentNode | ||
for (var i = 0, j = contents.length; i < j; i++) { | ||
parent.insertBefore(contents[i], outlet) | ||
} | ||
parent.removeChild(outlet) | ||
} | ||
/** | ||
* Helper to extract a component container's attribute names | ||
* into a map. The resulting map will be used in compiler to | ||
* determine whether an attribute is transcluded. | ||
* into a map. | ||
* | ||
* @param {Element} el | ||
* @return {Object} | ||
*/ | ||
function extractAttrs (el) { | ||
var attrs = el.attributes | ||
var res = {} | ||
var i = attrs.length | ||
while (i--) { | ||
res[attrs[i].name] = attrs[i].value | ||
if (el.nodeType === 1 && el.hasAttributes()) { | ||
var attrs = el.attributes | ||
var res = {} | ||
var i = attrs.length | ||
while (i--) { | ||
res[attrs[i].name] = attrs[i].value | ||
} | ||
return res | ||
} | ||
return res | ||
} | ||
@@ -219,0 +108,0 @@ |
@@ -9,25 +9,42 @@ // xlink | ||
bind: function () { | ||
var name = this.arg | ||
this.update = xlinkRE.test(name) | ||
? xlinkHandler | ||
: defaultHandler | ||
} | ||
update: function (value) { | ||
if (this.arg) { | ||
this.setAttr(this.arg, value) | ||
} else if (typeof value === 'object') { | ||
this.objectHandler(value) | ||
} | ||
}, | ||
} | ||
objectHandler: function (value) { | ||
// cache object attrs so that only changed attrs | ||
// are actually updated. | ||
var cache = this.cache || (this.cache = {}) | ||
var attr, val | ||
for (attr in cache) { | ||
if (!(attr in value)) { | ||
this.setAttr(attr, null) | ||
delete cache[attr] | ||
} | ||
} | ||
for (attr in value) { | ||
val = value[attr] | ||
if (val !== cache[attr]) { | ||
cache[attr] = val | ||
this.setAttr(attr, val) | ||
} | ||
} | ||
}, | ||
function defaultHandler (value) { | ||
if (value || value === 0) { | ||
this.el.setAttribute(this.arg, value) | ||
} else { | ||
this.el.removeAttribute(this.arg) | ||
setAttr: function (attr, value) { | ||
if (value || value === 0) { | ||
if (xlinkRE.test(attr)) { | ||
this.el.setAttributeNS(xlinkNS, attr, value) | ||
} else { | ||
this.el.setAttribute(attr, value) | ||
} | ||
} else { | ||
this.el.removeAttribute(attr) | ||
} | ||
} | ||
} | ||
function xlinkHandler (value) { | ||
if (value != null) { | ||
this.el.setAttributeNS(xlinkNS, this.arg, value) | ||
} else { | ||
this.el.removeAttributeNS(xlinkNS, 'href') | ||
} | ||
} |
@@ -5,15 +5,42 @@ var _ = require('../util') | ||
module.exports = function (value) { | ||
if (this.arg) { | ||
var method = value ? addClass : removeClass | ||
method(this.el, this.arg) | ||
} else { | ||
module.exports = { | ||
update: function (value) { | ||
if (this.arg) { | ||
// single toggle | ||
var method = value ? addClass : removeClass | ||
method(this.el, this.arg) | ||
} else { | ||
this.cleanup() | ||
if (value && typeof value === 'string') { | ||
// raw class text | ||
addClass(this.el, value) | ||
this.lastVal = value | ||
} else if (_.isPlainObject(value)) { | ||
// object toggle | ||
for (var key in value) { | ||
if (value[key]) { | ||
addClass(this.el, key) | ||
} else { | ||
removeClass(this.el, key) | ||
} | ||
} | ||
this.prevKeys = Object.keys(value) | ||
} | ||
} | ||
}, | ||
cleanup: function (value) { | ||
if (this.lastVal) { | ||
removeClass(this.el, this.lastVal) | ||
} | ||
if (value) { | ||
addClass(this.el, value) | ||
this.lastVal = value | ||
if (this.prevKeys) { | ||
var i = this.prevKeys.length | ||
while (i--) { | ||
if (!value || !value[this.prevKeys[i]]) { | ||
removeClass(this.el, this.prevKeys[i]) | ||
} | ||
} | ||
} | ||
} | ||
} |
@@ -69,3 +69,3 @@ var _ = require('../util') | ||
update: function (value) { | ||
this.realUpdate(value) | ||
this.setComponent(value) | ||
}, | ||
@@ -76,11 +76,12 @@ | ||
* asynchronously, and perform transition based on | ||
* specified transition mode. Accepts an async callback | ||
* which is called when the transition ends. (This is | ||
* exposed for vue-router) | ||
* specified transition mode. Accepts a few additional | ||
* arguments specifically for vue-router. | ||
* | ||
* @param {String} value | ||
* @param {Function} [cb] | ||
* @param {Object} data | ||
* @param {Function} afterBuild | ||
* @param {Function} afterTransition | ||
*/ | ||
realUpdate: function (value, cb) { | ||
setComponent: function (value, data, afterBuild, afterTransition) { | ||
this.invalidatePending() | ||
@@ -90,3 +91,3 @@ if (!value) { | ||
this.unbuild() | ||
this.remove(this.childVM, cb) | ||
this.remove(this.childVM, afterTransition) | ||
this.unsetCurrent() | ||
@@ -96,10 +97,12 @@ } else { | ||
this.unbuild() | ||
var newComponent = this.build() | ||
var newComponent = this.build(data) | ||
/* istanbul ignore if */ | ||
if (afterBuild) afterBuild(newComponent) | ||
var self = this | ||
if (this.readyEvent) { | ||
newComponent.$once(this.readyEvent, function () { | ||
self.swapTo(newComponent, cb) | ||
self.transition(newComponent, afterTransition) | ||
}) | ||
} else { | ||
this.swapTo(newComponent, cb) | ||
this.transition(newComponent, afterTransition) | ||
} | ||
@@ -117,10 +120,8 @@ }, this)) | ||
var self = this | ||
var pendingCb = this._pendingCb = function (ctor) { | ||
if (!pendingCb.invalidated) { | ||
self.ctorId = id | ||
self.Ctor = ctor | ||
cb() | ||
} | ||
} | ||
this.vm._resolveComponent(id, pendingCb) | ||
this._pendingCb = _.cancellable(function (ctor) { | ||
self.ctorId = id | ||
self.Ctor = ctor | ||
cb() | ||
}) | ||
this.vm._resolveComponent(id, this._pendingCb) | ||
}, | ||
@@ -136,3 +137,3 @@ | ||
if (this._pendingCb) { | ||
this._pendingCb.invalidated = true | ||
this._pendingCb.cancel() | ||
this._pendingCb = null | ||
@@ -147,6 +148,7 @@ } | ||
* | ||
* @param {Object} [data] | ||
* @return {Vue} - the created instance | ||
*/ | ||
build: function () { | ||
build: function (data) { | ||
if (this.keepAlive) { | ||
@@ -163,5 +165,10 @@ var cached = this.cache[this.ctorId] | ||
el: el, | ||
data: data, | ||
template: this.template, | ||
// if no inline-template, then the compiled | ||
// linker can be cached for better performance. | ||
_linkerCachable: !this.template, | ||
_asComponent: true, | ||
_host: this._host | ||
_host: this._host, | ||
_isRouterView: this._isRouterView | ||
}, this.Ctor) | ||
@@ -218,3 +225,3 @@ if (this.keepAlive) { | ||
swapTo: function (target, cb) { | ||
transition: function (target, cb) { | ||
var self = this | ||
@@ -232,3 +239,5 @@ var current = this.childVM | ||
self.remove(current, function () { | ||
target.$before(self.anchor, cb) | ||
if (!target._isDestroyed) { | ||
target.$before(self.anchor, cb) | ||
} | ||
}) | ||
@@ -283,2 +292,2 @@ break | ||
} | ||
} |
var _ = require('../util') | ||
var compile = require('../compiler/compile') | ||
var compiler = require('../compiler') | ||
var templateParser = require('../parsers/template') | ||
@@ -15,3 +15,3 @@ var transition = require('../transition') | ||
_.before(this.start, this.end) | ||
if (el.tagName === 'TEMPLATE') { | ||
if (_.isTemplate(el)) { | ||
this.template = templateParser.parse(el, true) | ||
@@ -23,3 +23,3 @@ } else { | ||
// compile the nested partial | ||
this.linker = compile( | ||
this.linker = compiler.compile( | ||
this.template, | ||
@@ -95,3 +95,6 @@ this.vm.$options, | ||
next = cur.nextSibling | ||
if (cur.contains(c.$el)) { | ||
if ( | ||
cur === c.$el || | ||
cur.contains && cur.contains(c.$el) | ||
) { | ||
return true | ||
@@ -98,0 +101,0 @@ } |
@@ -21,5 +21,2 @@ // manipulation directives | ||
// child vm communication directives | ||
exports.events = require('./events') | ||
// internal directives that should not be used directly | ||
@@ -26,0 +23,0 @@ // but we still want to expose them for advanced usage. |
@@ -68,3 +68,4 @@ var _ = require('../../util') | ||
this.hasRead = true | ||
} else if (filter.write) { | ||
} | ||
if (filter.write) { | ||
this.hasWrite = true | ||
@@ -71,0 +72,0 @@ } |
@@ -1,2 +0,1 @@ | ||
var _ = require('../util') | ||
var Watcher = require('../watcher') | ||
@@ -10,4 +9,6 @@ | ||
var parent = child.$parent | ||
var childKey = this.arg | ||
var parentKey = this.expression | ||
// passed in from compiler directly | ||
var prop = this._descriptor | ||
var childKey = prop.path | ||
var parentKey = prop.parentPath | ||
@@ -18,29 +19,27 @@ // simple lock to avoid circular updates. | ||
var locked = false | ||
var lock = function () { | ||
locked = true | ||
_.nextTick(unlock) | ||
if (!prop.oneWayUp) { | ||
this.parentWatcher = new Watcher( | ||
parent, | ||
parentKey, | ||
function (val) { | ||
if (!locked) { | ||
locked = true | ||
// all props have been initialized already | ||
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) | ||
} | ||
var unlock = function () { | ||
locked = false | ||
} | ||
this.parentWatcher = new Watcher( | ||
parent, | ||
parentKey, | ||
function (val) { | ||
if (!locked) { | ||
lock() | ||
child.$set(childKey, val) | ||
} | ||
} | ||
) | ||
// set the child initial value first, before setting | ||
// up the child watcher to avoid triggering it | ||
// immediately. | ||
child.$set(childKey, this.parentWatcher.value) | ||
// only setup two-way binding if this is not a one-way | ||
// binding. | ||
if (!this._descriptor.oneWay) { | ||
if (!prop.oneWayDown) { | ||
this.childWatcher = new Watcher( | ||
@@ -51,7 +50,14 @@ child, | ||
if (!locked) { | ||
lock() | ||
locked = true | ||
parent.$set(parentKey, val) | ||
locked = false | ||
} | ||
} | ||
}, | ||
{ sync: true } | ||
) | ||
// set initial value for one-way up binding | ||
if (prop.oneWayUp) { | ||
parent.$set(parentKey, this.childWatcher.value) | ||
} | ||
} | ||
@@ -68,3 +74,2 @@ }, | ||
} | ||
} | ||
} |
@@ -7,4 +7,3 @@ var _ = require('../util') | ||
var templateParser = require('../parsers/template') | ||
var compile = require('../compiler/compile') | ||
var transclude = require('../compiler/transclude') | ||
var compiler = require('../compiler') | ||
var uid = 0 | ||
@@ -27,7 +26,9 @@ | ||
this.id = '__v_repeat_' + (++uid) | ||
// setup anchor node | ||
this.anchor = _.createAnchor('v-repeat') | ||
_.replace(this.el, this.anchor) | ||
// setup anchor nodes | ||
this.start = _.createAnchor('v-repeat-start') | ||
this.end = _.createAnchor('v-repeat-end') | ||
_.replace(this.el, this.end) | ||
_.before(this.start, this.end) | ||
// check if this is a block repeat | ||
this.template = this.el.tagName === 'TEMPLATE' | ||
this.template = _.isTemplate(this.el) | ||
? templateParser.parse(this.el, true) | ||
@@ -44,2 +45,6 @@ : this.el | ||
this._checkParam('trackby') // 0.11.0 compat | ||
// check for transition stagger | ||
var stagger = +this._checkParam('stagger') | ||
this.enterStagger = +this._checkParam('enter-stagger') || stagger | ||
this.leaveStagger = +this._checkParam('leave-stagger') || stagger | ||
this.cache = Object.create(null) | ||
@@ -93,6 +98,6 @@ }, | ||
// to ensure block start and block end | ||
this.template = transclude(this.template) | ||
this.template = compiler.transclude(this.template) | ||
var copy = _.extend({}, options) | ||
copy._asComponent = false | ||
this._linkFn = compile(this.template, copy) | ||
this._linkFn = compiler.compile(this.template, copy) | ||
} else { | ||
@@ -126,14 +131,2 @@ this.Ctor = null | ||
this.Ctor = Ctor | ||
var merged = _.mergeOptions(Ctor.options, {}, { | ||
$parent: this.vm | ||
}) | ||
merged.template = this.inlineTempalte || merged.template | ||
merged._asComponent = true | ||
merged._parent = this.vm | ||
this.template = transclude(this.template, merged) | ||
// Important: mark the template as a root node so that | ||
// custom element components don't get compiled twice. | ||
// fixes #822 | ||
this.template.__vue__ = true | ||
this._linkFn = compile(this.template, merged) | ||
this.componentState = RESOLVED | ||
@@ -217,3 +210,5 @@ this.realUpdate(this.pendingData) | ||
if (this.refID) { | ||
this.vm.$[this.refID] = this.vms | ||
this.vm.$[this.refID] = this.converted | ||
? toRefObject(this.vms) | ||
: this.vms | ||
} | ||
@@ -246,7 +241,9 @@ if (this.elId) { | ||
var converted = this.converted | ||
var anchor = this.anchor | ||
var start = this.start | ||
var end = this.end | ||
var inDoc = _.inDoc(start) | ||
var alias = this.arg | ||
var init = !oldVms | ||
var vms = new Array(data.length) | ||
var obj, raw, vm, i, l | ||
var obj, raw, vm, i, l, primitive | ||
// First pass, go through the new Array and fill up | ||
@@ -259,3 +256,4 @@ // the new vms array. If a piece of data has a cached | ||
raw = converted ? obj.$value : obj | ||
vm = !init && this.getVm(raw, converted ? obj.$key : null) | ||
primitive = !isObject(raw) | ||
vm = !init && this.getVm(raw, i, converted ? obj.$key : null) | ||
if (vm) { // reusable instance | ||
@@ -267,3 +265,3 @@ vm._reused = true | ||
// rather than mutated. | ||
if (idKey || converted) { | ||
if (idKey || converted || primitive) { | ||
if (alias) { | ||
@@ -279,6 +277,2 @@ vm[alias] = raw | ||
vm = this.build(obj, i, true) | ||
// the _new flag is used in the second pass for | ||
// vm cache retrival, but if this is the init phase | ||
// the flag can just be set to false directly. | ||
vm._new = !init | ||
vm._reused = false | ||
@@ -289,3 +283,3 @@ } | ||
if (init) { | ||
vm.$before(anchor) | ||
vm.$before(end) | ||
} | ||
@@ -300,2 +294,4 @@ } | ||
// from cache) | ||
var removalIndex = 0 | ||
var totalRemoved = oldVms.length - vms.length | ||
for (i = 0, l = oldVms.length; i < l; i++) { | ||
@@ -305,39 +301,29 @@ vm = oldVms[i] | ||
this.uncacheVm(vm) | ||
vm.$destroy(true) | ||
vm.$destroy(false, true) // defer cleanup until removal | ||
this.remove(vm, removalIndex++, totalRemoved, inDoc) | ||
} | ||
} | ||
// final pass, move/insert new instances into the | ||
// right place. We're going in reverse here because | ||
// insertBefore relies on the next sibling to be | ||
// resolved. | ||
var targetNext, currentNext | ||
i = vms.length | ||
while (i--) { | ||
// right place. | ||
var targetPrev, prevEl, currentPrev | ||
var insertionIndex = 0 | ||
for (i = 0, l = vms.length; i < l; i++) { | ||
vm = vms[i] | ||
// this is the vm that we should be in front of | ||
targetNext = vms[i + 1] | ||
if (!targetNext) { | ||
// This is the last item. If it's reused then | ||
// everything else will eventually be in the right | ||
// place, so no need to touch it. Otherwise, insert | ||
// it. | ||
if (!vm._reused) { | ||
vm.$before(anchor) | ||
// this is the vm that we should be after | ||
targetPrev = vms[i - 1] | ||
prevEl = targetPrev | ||
? targetPrev._staggerCb | ||
? targetPrev._staggerAnchor | ||
: targetPrev._blockEnd || targetPrev.$el | ||
: start | ||
if (vm._reused && !vm._staggerCb) { | ||
currentPrev = findPrevVm(vm, start, this.id) | ||
if (currentPrev !== targetPrev) { | ||
this.move(vm, prevEl) | ||
} | ||
} else { | ||
var nextEl = targetNext.$el | ||
if (vm._reused) { | ||
// this is the vm we are actually in front of | ||
currentNext = findNextVm(vm, anchor) | ||
// we only need to move if we are not in the right | ||
// place already. | ||
if (currentNext !== targetNext) { | ||
vm.$before(nextEl, null, false) | ||
} | ||
} else { | ||
// new instance, insert to existing next | ||
vm.$before(nextEl) | ||
} | ||
// new instance, or still in stagger. | ||
// insert with updated stagger index. | ||
this.insert(vm, insertionIndex++, prevEl, inDoc) | ||
} | ||
vm._new = false | ||
vm._reused = false | ||
@@ -378,16 +364,23 @@ } | ||
el: templateParser.clone(this.template), | ||
data: data, | ||
inherit: this.inherit, | ||
template: this.inlineTempalte, | ||
// repeater meta, e.g. $index, $key | ||
_meta: meta, | ||
// mark this as an inline-repeat instance | ||
_repeat: this.inherit, | ||
// is this a component? | ||
_asComponent: this.asComponent, | ||
// linker cachable if no inline-template | ||
_linkerCachable: !this.inlineTempalte, | ||
// transclusion host | ||
_host: this._host, | ||
// pre-compiled linker for simple repeats | ||
_linkFn: this._linkFn, | ||
_meta: meta, | ||
data: data, | ||
inherit: this.inherit, | ||
template: this.inlineTempalte | ||
// identifier, shows that this vm belongs to this collection | ||
_repeatId: this.id | ||
}, Ctor) | ||
// flag this instance as a repeat instance | ||
// so that we can skip it in vm._digest | ||
vm._repeat = true | ||
// cache instance | ||
if (needCache) { | ||
this.cacheVm(raw, vm, this.converted ? meta.$key : null) | ||
this.cacheVm(raw, vm, index, this.converted ? meta.$key : null) | ||
} | ||
@@ -402,2 +395,12 @@ // sync back changes for two-way bindings of primitive values | ||
vm.$watch(alias || '$value', function (val) { | ||
if (dir.filters) { | ||
_.warn( | ||
'You seem to be mutating the $value reference of ' + | ||
'a v-repeat instance (likely through v-model) ' + | ||
'and filtering the v-repeat at the same time. ' + | ||
'This will not work properly with an Array of ' + | ||
'primitive values. Please use an Array of ' + | ||
'Objects instead.' | ||
) | ||
} | ||
dir._withLock(function () { | ||
@@ -445,17 +448,23 @@ if (dir.converted) { | ||
* @param {Vue} vm | ||
* @param {Number} index | ||
* @param {String} [key] | ||
*/ | ||
cacheVm: function (data, vm, key) { | ||
cacheVm: function (data, vm, index, key) { | ||
var idKey = this.idKey | ||
var cache = this.cache | ||
var primitive = !isObject(data) | ||
var id | ||
if (key || idKey) { | ||
id = idKey ? data[idKey] : key | ||
if (key || idKey || primitive) { | ||
id = idKey | ||
? idKey === '$index' | ||
? index | ||
: data[idKey] | ||
: (key || index) | ||
if (!cache[id]) { | ||
cache[id] = vm | ||
} else { | ||
} else if (!primitive && idKey !== '$index') { | ||
_.warn('Duplicate track-by key in v-repeat: ' + id) | ||
} | ||
} else if (isObject(data)) { | ||
} else { | ||
id = this.id | ||
@@ -474,8 +483,2 @@ if (data.hasOwnProperty(id)) { | ||
} | ||
} else { | ||
if (!cache[data]) { | ||
cache[data] = [vm] | ||
} else { | ||
cache[data].push(vm) | ||
} | ||
} | ||
@@ -489,2 +492,3 @@ vm._raw = data | ||
* @param {Object} data | ||
* @param {Number} index | ||
* @param {String} [key] | ||
@@ -494,22 +498,14 @@ * @return {Vue|undefined} | ||
getVm: function (data, key) { | ||
getVm: function (data, index, key) { | ||
var idKey = this.idKey | ||
if (key || idKey) { | ||
var id = idKey ? data[idKey] : key | ||
var primitive = !isObject(data) | ||
if (key || idKey || primitive) { | ||
var id = idKey | ||
? idKey === '$index' | ||
? index | ||
: data[idKey] | ||
: (key || index) | ||
return this.cache[id] | ||
} else if (isObject(data)) { | ||
} else { | ||
return data[this.id] | ||
} else { | ||
var cached = this.cache[data] | ||
if (cached) { | ||
var i = 0 | ||
var vm = cached[i] | ||
// since duplicated vm instances might be a reused | ||
// one OR a newly created one, we need to return the | ||
// first instance that is neither of these. | ||
while (vm && (vm._reused || vm._new)) { | ||
vm = cached[++i] | ||
} | ||
return vm | ||
} | ||
} | ||
@@ -527,11 +523,15 @@ }, | ||
var idKey = this.idKey | ||
var convertedKey = vm.$key | ||
if (idKey || convertedKey) { | ||
var id = idKey ? data[idKey] : convertedKey | ||
var index = vm.$index | ||
var key = vm.$key | ||
var primitive = !isObject(data) | ||
if (idKey || key || primitive) { | ||
var id = idKey | ||
? idKey === '$index' | ||
? index | ||
: data[idKey] | ||
: (key || index) | ||
this.cache[id] = null | ||
} else if (isObject(data)) { | ||
} else { | ||
data[this.id] = null | ||
vm._raw = null | ||
} else { | ||
this.cache[data].pop() | ||
} | ||
@@ -580,2 +580,104 @@ }, | ||
} | ||
}, | ||
/** | ||
* Insert an instance. | ||
* | ||
* @param {Vue} vm | ||
* @param {Number} index | ||
* @param {Node} prevEl | ||
* @param {Boolean} inDoc | ||
*/ | ||
insert: function (vm, index, prevEl, inDoc) { | ||
if (vm._staggerCb) { | ||
vm._staggerCb.cancel() | ||
vm._staggerCb = null | ||
} | ||
var staggerAmount = this.getStagger(vm, index, null, 'enter') | ||
if (inDoc && staggerAmount) { | ||
// create an anchor and insert it synchronously, | ||
// so that we can resolve the correct order without | ||
// worrying about some elements not inserted yet | ||
var anchor = vm._staggerAnchor | ||
if (!anchor) { | ||
anchor = vm._staggerAnchor = _.createAnchor('stagger-anchor') | ||
anchor.__vue__ = vm | ||
} | ||
_.after(anchor, prevEl) | ||
var op = vm._staggerCb = _.cancellable(function () { | ||
vm._staggerCb = null | ||
vm.$before(anchor) | ||
_.remove(anchor) | ||
}) | ||
setTimeout(op, staggerAmount) | ||
} else { | ||
vm.$after(prevEl) | ||
} | ||
}, | ||
/** | ||
* Move an already inserted instance. | ||
* | ||
* @param {Vue} vm | ||
* @param {Node} prevEl | ||
*/ | ||
move: function (vm, prevEl) { | ||
vm.$after(prevEl, null, false) | ||
}, | ||
/** | ||
* Remove an instance. | ||
* | ||
* @param {Vue} vm | ||
* @param {Number} index | ||
* @param {Boolean} inDoc | ||
*/ | ||
remove: function (vm, index, total, inDoc) { | ||
if (vm._staggerCb) { | ||
vm._staggerCb.cancel() | ||
vm._staggerCb = null | ||
// it's not possible for the same vm to be removed | ||
// twice, so if we have a pending stagger callback, | ||
// it means this vm is queued for enter but removed | ||
// before its transition started. Since it is already | ||
// destroyed, we can just leave it in detached state. | ||
return | ||
} | ||
var staggerAmount = this.getStagger(vm, index, total, 'leave') | ||
if (inDoc && staggerAmount) { | ||
var op = vm._staggerCb = _.cancellable(function () { | ||
vm._staggerCb = null | ||
remove() | ||
}) | ||
setTimeout(op, staggerAmount) | ||
} else { | ||
remove() | ||
} | ||
function remove () { | ||
vm.$remove(function () { | ||
vm._cleanup() | ||
}) | ||
} | ||
}, | ||
/** | ||
* Get the stagger amount for an insertion/removal. | ||
* | ||
* @param {Vue} vm | ||
* @param {Number} index | ||
* @param {String} type | ||
* @param {Number} total | ||
*/ | ||
getStagger: function (vm, index, total, type) { | ||
type = type + 'Stagger' | ||
var transition = vm.$el.__v_trans | ||
var hooks = transition && transition.hooks | ||
var hook = hooks && (hooks[type] || hooks.stagger) | ||
return hook | ||
? hook.call(vm, index, total) | ||
: index * this[type] | ||
} | ||
@@ -586,3 +688,3 @@ | ||
/** | ||
* Helper to find the next element that is an instance | ||
* Helper to find the previous element that is an instance | ||
* root node. This is necessary because a destroyed vm's | ||
@@ -593,2 +695,5 @@ * element could still be lingering in the DOM before its | ||
* | ||
* If this is a block repeat, we want to make sure we only | ||
* return vm that is bound to this v-repeat. (see #929) | ||
* | ||
* @param {Vue} vm | ||
@@ -599,6 +704,9 @@ * @param {Comment|Text} anchor | ||
function findNextVm (vm, anchor) { | ||
var el = (vm._blockEnd || vm.$el).nextSibling | ||
while (!el.__vue__ && el !== anchor) { | ||
el = el.nextSibling | ||
function findPrevVm (vm, anchor, id) { | ||
var el = vm.$el.previousSibling | ||
while ( | ||
(!el.__vue__ || el.__vue__.$options._repeatId !== id) && | ||
el !== anchor | ||
) { | ||
el = el.previousSibling | ||
} | ||
@@ -622,2 +730,18 @@ return el.__vue__ | ||
return ret | ||
} | ||
} | ||
/** | ||
* Convert a vms array to an object ref for v-ref on an | ||
* Object value. | ||
* | ||
* @param {Array} vms | ||
* @return {Object} | ||
*/ | ||
function toRefObject (vms) { | ||
var ref = {} | ||
for (var i = 0, l = vms.length; i < l; i++) { | ||
ref[vms[i].$key] = vms[i] | ||
} | ||
return ref | ||
} |
@@ -18,13 +18,3 @@ var _ = require('../util') | ||
if (typeof value === 'object') { | ||
// cache object styles so that only changed props | ||
// are actually updated. | ||
if (!this.cache) this.cache = {} | ||
for (var prop in value) { | ||
this.setProp(prop, value[prop]) | ||
/* jshint eqeqeq: false */ | ||
if (value[prop] != this.cache[prop]) { | ||
this.cache[prop] = value[prop] | ||
this.setProp(prop, value[prop]) | ||
} | ||
} | ||
this.objectHandler(value) | ||
} else { | ||
@@ -36,2 +26,22 @@ this.el.style.cssText = value | ||
objectHandler: function (value) { | ||
// cache object styles so that only changed props | ||
// are actually updated. | ||
var cache = this.cache || (this.cache = {}) | ||
var prop, val | ||
for (prop in cache) { | ||
if (!(prop in value)) { | ||
this.setProp(prop, null) | ||
delete cache[prop] | ||
} | ||
} | ||
for (prop in value) { | ||
val = value[prop] | ||
if (val !== cache[prop]) { | ||
cache[prop] = val | ||
this.setProp(prop, val) | ||
} | ||
} | ||
}, | ||
setProp: function (prop, value) { | ||
@@ -38,0 +48,0 @@ prop = normalize(prop) |
@@ -18,3 +18,4 @@ var _ = require('../util') | ||
} | ||
if (!search) { | ||
/* jshint eqeqeq: false */ | ||
if (search == null) { | ||
return arr | ||
@@ -86,2 +87,2 @@ } | ||
} | ||
} | ||
} |
var _ = require('../util') | ||
var Directive = require('../directive') | ||
var compile = require('../compiler/compile') | ||
var transclude = require('../compiler/transclude') | ||
var compiler = require('../compiler') | ||
@@ -21,15 +20,44 @@ /** | ||
var options = this.$options | ||
var host = this._host | ||
if (options._linkFn) { | ||
// pre-transcluded with linker, just use it | ||
this._initElement(el) | ||
this._unlinkFn = options._linkFn(this, el) | ||
this._unlinkFn = options._linkFn(this, el, host) | ||
} else { | ||
// transclude and init element | ||
// transclude can potentially replace original | ||
// so we need to keep reference | ||
// so we need to keep reference; this step also injects | ||
// the template and caches the original attributes | ||
// on the container node and replacer node. | ||
var original = el | ||
el = transclude(el, options) | ||
el = compiler.transclude(el, options) | ||
this._initElement(el) | ||
// root is always compiled per-instance, because | ||
// container attrs and props can be different every time. | ||
var rootUnlinkFn = | ||
compiler.compileAndLinkRoot(this, el, options) | ||
// compile and link the rest | ||
this._unlinkFn = compile(el, options)(this, el) | ||
var linker | ||
var ctor = this.constructor | ||
// component compilation can be cached | ||
// as long as it's not using inline-template | ||
if (options._linkerCachable) { | ||
linker = ctor.linker | ||
if (!linker) { | ||
linker = ctor.linker = compiler.compile(el, options) | ||
} | ||
} | ||
var contentUnlinkFn = linker | ||
? linker(this, el) | ||
: compiler.compile(el, options)(this, el, host) | ||
this._unlinkFn = function () { | ||
rootUnlinkFn() | ||
// passing destroying: true to avoid searching and | ||
// splicing the directives | ||
contentUnlinkFn(true) | ||
} | ||
// finally replace original | ||
@@ -118,5 +146,3 @@ if (options.replace) { | ||
if (this._unlinkFn) { | ||
// passing destroying: true to avoid searching and | ||
// splicing the directives | ||
this._unlinkFn(true) | ||
this._unlinkFn() | ||
} | ||
@@ -123,0 +149,0 @@ i = this._watchers.length |
@@ -66,4 +66,4 @@ var mergeOptions = require('../util').mergeOptions | ||
// props used in v-repeat diffing | ||
this._new = true | ||
this._reused = false | ||
this._staggerOp = null | ||
@@ -70,0 +70,0 @@ // merge options. |
@@ -60,2 +60,3 @@ var _ = require('../util') | ||
} else if (factory.requested) { | ||
// pool callbacks | ||
factory.pendingCallbacks.push(cb) | ||
@@ -75,2 +76,7 @@ } else { | ||
} | ||
}, function reject (reason) { | ||
_.warn( | ||
'Failed to resolve async component: ' + id + '. ' + | ||
(reason ? '\nReason: ' + reason : '') | ||
) | ||
}) | ||
@@ -77,0 +83,0 @@ } |
@@ -34,4 +34,4 @@ var _ = require('../util') | ||
key = _.camelize(props[i]) | ||
if (!(key in data)) { | ||
data[key] = null | ||
if (!(key in data) && key !== '$data') { | ||
data[key] = undefined | ||
} | ||
@@ -63,2 +63,15 @@ } | ||
var keys, key, i | ||
// copy props. | ||
// this should only happen during a v-repeat of component | ||
// that also happens to have compiled props. | ||
var props = this.$options.props | ||
if (props) { | ||
i = props.length | ||
while (i--) { | ||
key = props[i] | ||
if (key !== '$data' && !newData.hasOwnProperty(key)) { | ||
newData.$set(key, oldData[key]) | ||
} | ||
} | ||
} | ||
// unproxy keys not present in new data | ||
@@ -215,5 +228,3 @@ keys = Object.keys(oldData) | ||
get: function metaGetter () { | ||
if (Observer.target) { | ||
Observer.target.addDep(dep) | ||
} | ||
dep.depend() | ||
return value | ||
@@ -228,2 +239,2 @@ }, | ||
}) | ||
} | ||
} |
@@ -14,2 +14,7 @@ var _ = require('../util') | ||
// the current target watcher being evaluated. | ||
// this is globally unique because there could be only one | ||
// watcher being evaluated at any time. | ||
Dep.target = null | ||
var p = Dep.prototype | ||
@@ -38,2 +43,12 @@ | ||
/** | ||
* Add self as a dependency to the target watcher. | ||
*/ | ||
p.depend = function () { | ||
if (Dep.target) { | ||
Dep.target.addDep(this) | ||
} | ||
} | ||
/** | ||
* Notify all subscribers of a new value. | ||
@@ -50,2 +65,2 @@ */ | ||
module.exports = Dep | ||
module.exports = Dep |
@@ -18,31 +18,2 @@ var _ = require('../util') | ||
/** | ||
* Augment an target Object or Array by intercepting | ||
* the prototype chain using __proto__ | ||
* | ||
* @param {Object|Array} target | ||
* @param {Object} proto | ||
*/ | ||
function protoAugment (target, src) { | ||
target.__proto__ = src | ||
} | ||
/** | ||
* Augment an target Object or Array by defining | ||
* hidden properties. | ||
* | ||
* @param {Object|Array} target | ||
* @param {Object} proto | ||
*/ | ||
function copyAugment (target, src, keys) { | ||
var i = keys.length | ||
var key | ||
while (i--) { | ||
key = keys[i] | ||
_.define(target, key, src[key]) | ||
} | ||
} | ||
/** | ||
* Observer class that are attached to each observed | ||
@@ -75,6 +46,4 @@ * object. Once attached, the observer converts target | ||
Observer.target = null | ||
// Static methods | ||
var p = Observer.prototype | ||
/** | ||
@@ -108,2 +77,16 @@ * Attempt to create an observer instance for a value, | ||
/** | ||
* Set the target watcher that is currently being evaluated. | ||
* | ||
* @param {Watcher} watcher | ||
*/ | ||
Observer.setTarget = function (watcher) { | ||
Dep.target = watcher | ||
} | ||
// Instance methods | ||
var p = Observer.prototype | ||
/** | ||
* Walk through each property and convert them into | ||
@@ -174,6 +157,4 @@ * getter/setters. This method should only be called when | ||
get: function () { | ||
// Observer.target is a watcher whose getter is | ||
// currently being evaluated. | ||
if (ob.active && Observer.target) { | ||
Observer.target.addDep(dep) | ||
if (ob.active) { | ||
dep.depend() | ||
} | ||
@@ -224,3 +205,3 @@ return val | ||
p.addVm = function (vm) { | ||
(this.vms = this.vms || []).push(vm) | ||
(this.vms || (this.vms = [])).push(vm) | ||
} | ||
@@ -239,2 +220,33 @@ | ||
// helpers | ||
/** | ||
* Augment an target Object or Array by intercepting | ||
* the prototype chain using __proto__ | ||
* | ||
* @param {Object|Array} target | ||
* @param {Object} proto | ||
*/ | ||
function protoAugment (target, src) { | ||
target.__proto__ = src | ||
} | ||
/** | ||
* Augment an target Object or Array by defining | ||
* hidden properties. | ||
* | ||
* @param {Object|Array} target | ||
* @param {Object} proto | ||
*/ | ||
function copyAugment (target, src, keys) { | ||
var i = keys.length | ||
var key | ||
while (i--) { | ||
key = keys[i] | ||
_.define(target, key, src[key]) | ||
} | ||
} | ||
module.exports = Observer |
var _ = require('../util') | ||
var Path = require('./path') | ||
var Cache = require('../cache') | ||
var notevil = require('../../vendor/notevil') | ||
var expressionCache = new Cache(1000) | ||
@@ -27,3 +28,3 @@ | ||
var restoreRE = /"(\d+)"/g | ||
var pathTestRE = /^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\]|\[\d+\])*$/ | ||
var pathTestRE = /^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\]|\[\d+\]|\[[A-Za-z_$][\w$]*\])*$/ | ||
var pathReplaceRE = /[^\w$\.]([A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\])*)/g | ||
@@ -150,2 +151,3 @@ var booleanLiteralRE = /^(true|false)$/ | ||
path = exp.split('.') | ||
path.raw = exp | ||
getter = Path.compileGetter(path) | ||
@@ -178,3 +180,9 @@ } else { | ||
try { | ||
return new Function('scope', 'return ' + body + ';') | ||
var fn = notevil.Function( | ||
'scope', 'Math', | ||
'return ' + body + ';' | ||
) | ||
return function (scope) { | ||
return fn.call(this, scope, Math) | ||
} | ||
} catch (e) { | ||
@@ -204,3 +212,11 @@ _.warn( | ||
try { | ||
return new Function('scope', 'value', body + '=value;') | ||
var fn = notevil.Function( | ||
'scope', 'value', 'Math', | ||
body + ' = value;' | ||
) | ||
return function (scope, value) { | ||
try { | ||
fn.call(this, scope, value, Math) | ||
} catch (e) {} | ||
} | ||
} catch (e) { | ||
@@ -266,2 +282,2 @@ _.warn('Invalid setter function body: ' + body) | ||
exp.slice(0, 5) !== 'Math.' | ||
} | ||
} |
var _ = require('../util') | ||
var Cache = require('../cache') | ||
var pathCache = new Cache(1000) | ||
var identRE = /^[$_a-zA-Z]+[\w$]*$/ | ||
exports.identRE = /^[$_a-zA-Z]+[\w$]*$/ | ||
@@ -37,3 +37,4 @@ /** | ||
'[': ['beforeElement', 'push'], | ||
'eof': ['afterPath', 'push'] | ||
'eof': ['afterPath', 'push'], | ||
']': ['inPath', 'push'] | ||
}, | ||
@@ -46,3 +47,4 @@ | ||
"'": ['inSingleQuote', 'append', ''], | ||
'"': ['inDoubleQuote', 'append', ''] | ||
'"': ['inDoubleQuote', 'append', ''], | ||
"ident": ['inIdent', 'append', '*'] | ||
}, | ||
@@ -194,8 +196,12 @@ | ||
action = actions[transition[1]] || noop | ||
newChar = transition[2] === undefined | ||
newChar = transition[2] | ||
newChar = newChar === undefined | ||
? c | ||
: transition[2] | ||
: newChar === '*' | ||
? newChar + c | ||
: newChar | ||
action() | ||
if (mode === 'afterPath') { | ||
keys.raw = path | ||
return keys | ||
@@ -207,19 +213,2 @@ } | ||
/** | ||
* Format a accessor segment based on its type. | ||
* | ||
* @param {String} key | ||
* @return {Boolean} | ||
*/ | ||
function formatAccessor(key) { | ||
if (identRE.test(key)) { // identifier | ||
return '.' + key | ||
} else if (+key === key >>> 0) { // bracket index | ||
return '[' + key + ']' | ||
} else { // bracket string | ||
return '["' + key.replace(/"/g, '\\"') + '"]' | ||
} | ||
} | ||
/** | ||
* Compiles a getter function with a fixed path. | ||
@@ -233,4 +222,18 @@ * The fixed path getter supresses errors. | ||
exports.compileGetter = function (path) { | ||
var body = 'return o' + path.map(formatAccessor).join('') | ||
return new Function('o', 'try {' + body + '} catch (e) {}') | ||
return function get (obj) { | ||
var original = obj | ||
var segment | ||
for (var i = 0, l = path.length; i < l; i++) { | ||
segment = path[i] | ||
if (segment.charAt(0) === '*') { | ||
segment = original[segment.slice(1)] | ||
} | ||
obj = obj[segment] | ||
if (i === l - 1) { | ||
return obj | ||
} else if (!_.isObject(obj)) { | ||
return | ||
} | ||
} | ||
} | ||
} | ||
@@ -280,2 +283,3 @@ | ||
exports.set = function (obj, path, val) { | ||
var original = obj | ||
if (typeof path === 'string') { | ||
@@ -288,18 +292,36 @@ path = exports.parse(path) | ||
var last, key | ||
for (var i = 0, l = path.length - 1; i < l; i++) { | ||
for (var i = 0, l = path.length; i < l; i++) { | ||
last = obj | ||
key = path[i] | ||
obj = obj[key] | ||
if (!_.isObject(obj)) { | ||
obj = {} | ||
last.$add(key, obj) | ||
if (key.charAt(0) === '*') { | ||
key = original[key.slice(1)] | ||
} | ||
if (i < l - 1) { | ||
obj = obj[key] | ||
if (!_.isObject(obj)) { | ||
obj = {} | ||
last.$add(key, obj) | ||
warnNonExistent(path) | ||
} | ||
} else { | ||
if (_.isArray(obj)) { | ||
obj.$set(key, val) | ||
} else if (key in obj) { | ||
obj[key] = val | ||
} else { | ||
obj.$add(key, val) | ||
warnNonExistent(path) | ||
} | ||
} | ||
} | ||
key = path[i] | ||
if (key in obj) { | ||
obj[key] = val | ||
} else { | ||
obj.$add(key, val) | ||
} | ||
return true | ||
} | ||
} | ||
function warnNonExistent (path) { | ||
_.warn( | ||
'You are setting a non-existent path "' + path.raw + '" ' + | ||
'on a vm instance. Consider pre-initializing the property ' + | ||
'with the "data" option for more reliable reactivity ' + | ||
'and better performance.' | ||
) | ||
} |
@@ -120,7 +120,6 @@ var _ = require('../util') | ||
function nodeToFragment (node) { | ||
var tag = node.tagName | ||
// if its a template tag and the browser supports it, | ||
// its content is already a document fragment. | ||
if ( | ||
tag === 'TEMPLATE' && | ||
_.isTemplate(node) && | ||
node.content instanceof DocumentFragment | ||
@@ -131,3 +130,3 @@ ) { | ||
// script template | ||
if (tag === 'SCRIPT') { | ||
if (node.tagName === 'SCRIPT') { | ||
return stringToFragment(node.textContent) | ||
@@ -134,0 +133,0 @@ } |
@@ -73,3 +73,3 @@ var Cache = require('../cache') | ||
var lastIndex = tagRE.lastIndex = 0 | ||
var match, index, value, first, oneTime | ||
var match, index, value, first, oneTime, oneWay | ||
/* jshint boss:true */ | ||
@@ -86,4 +86,5 @@ while (match = tagRE.exec(text)) { | ||
first = match[1].charCodeAt(0) | ||
oneTime = first === 0x2A // * | ||
value = oneTime | ||
oneTime = first === 42 // * | ||
oneWay = first === 62 || first === 60 // > or < | ||
value = oneTime || oneWay | ||
? match[1].slice(1) | ||
@@ -95,3 +96,4 @@ : match[1] | ||
html: htmlRE.test(match[0]), | ||
oneTime: oneTime | ||
oneTime: oneTime, | ||
oneWay: oneWay ? first : 0 | ||
}) | ||
@@ -175,2 +177,2 @@ lastIndex = index + match[0].length | ||
} | ||
} | ||
} |
@@ -9,3 +9,2 @@ var _ = require('../util') | ||
var animDurationProp = _.animationProp + 'Duration' | ||
var doc = typeof document === 'undefined' ? null : document | ||
@@ -34,3 +33,3 @@ var TYPE_TRANSITION = 1 | ||
this.pendingCssCb = | ||
this.jsCancel = | ||
this.cancel = | ||
this.pendingJsCb = | ||
@@ -82,2 +81,3 @@ this.op = | ||
this.callHookWithCb('enter') | ||
this.cancel = this.hooks && this.hooks.enterCancelled | ||
queue.push(this.enterNextTick) | ||
@@ -111,3 +111,3 @@ } | ||
p.enterDone = function () { | ||
this.jsCancel = this.pendingJsCb = null | ||
this.cancel = this.pendingJsCb = null | ||
removeClass(this.el, this.enterClass) | ||
@@ -146,2 +146,3 @@ this.callHook('afterEnter') | ||
this.callHookWithCb('leave') | ||
this.cancel = this.hooks && this.hooks.enterCancelled | ||
// only need to do leaveNextTick if there's no explicit | ||
@@ -175,2 +176,3 @@ // js callback | ||
p.leaveDone = function () { | ||
this.cancel = this.pendingJsCb = null | ||
this.op() | ||
@@ -204,5 +206,5 @@ removeClass(this.el, this.leaveClass) | ||
} | ||
if (this.jsCancel) { | ||
this.jsCancel.call(null) | ||
this.jsCancel = null | ||
if (this.cancel) { | ||
this.cancel.call(this.vm, this.el) | ||
this.cancel = null | ||
} | ||
@@ -240,3 +242,3 @@ } | ||
} | ||
this.jsCancel = hook.call(this.vm, this.el, this.pendingJsCb) | ||
hook.call(this.vm, this.el, this.pendingJsCb) | ||
} | ||
@@ -254,9 +256,14 @@ } | ||
p.getCssTransitionType = function (className) { | ||
// skip CSS transitions if page is not visible - | ||
// this solves the issue of transitionend events not | ||
// firing until the page is visible again. | ||
// pageVisibility API is supported in IE10+, same as | ||
// CSS transitions. | ||
/* istanbul ignore if */ | ||
if (!transitionEndEvent || (doc && doc.hidden)) { | ||
if ( | ||
!transitionEndEvent || | ||
// skip CSS transitions if page is not visible - | ||
// this solves the issue of transitionend events not | ||
// firing until the page is visible again. | ||
// pageVisibility API is supported in IE10+, same as | ||
// CSS transitions. | ||
document.hidden || | ||
// explicit js-only transition | ||
(this.hooks && this.hooks.css === false) | ||
) { | ||
return | ||
@@ -263,0 +270,0 @@ } |
@@ -33,3 +33,3 @@ var config = require('../config') | ||
exports.warn = function (msg) { | ||
exports.warn = function (msg, e) { | ||
if (hasConsole && (!config.silent || config.debug)) { | ||
@@ -40,3 +40,3 @@ console.warn('[Vue warn]: ' + msg) | ||
/* jshint debug: true */ | ||
debugger | ||
console.warn((e || new Error('Warning Stack Trace')).stack) | ||
} | ||
@@ -51,2 +51,26 @@ } | ||
exports.assertAsset = function (val, type, id) { | ||
/* istanbul ignore if */ | ||
if (type === 'directive') { | ||
if (id === 'component') { | ||
exports.warn( | ||
'v-component can only be used on table elements ' + | ||
'in ^0.12.0. Use custom element syntax instead.' | ||
) | ||
return | ||
} | ||
if (id === 'with') { | ||
exports.warn( | ||
'v-with has been deprecated in ^0.12.0. ' + | ||
'Use props instead.' | ||
) | ||
return | ||
} | ||
if (id === 'events') { | ||
exports.warn( | ||
'v-events has been deprecated in ^0.12.0. ' + | ||
'Pass down methods as callback props instead.' | ||
) | ||
return | ||
} | ||
} | ||
if (!val) { | ||
@@ -53,0 +77,0 @@ exports.warn('Failed to resolve ' + type + ': ' + id) |
@@ -15,7 +15,4 @@ var config = require('../config') | ||
var doc = | ||
typeof document !== 'undefined' && | ||
document.documentElement | ||
exports.inDoc = function (node) { | ||
var doc = document.documentElement | ||
var parent = node && node.parentNode | ||
@@ -184,3 +181,3 @@ return doc === node || | ||
if ( | ||
el.tagName === 'TEMPLATE' && | ||
exports.isTemplate(el) && | ||
el.content instanceof DocumentFragment | ||
@@ -201,1 +198,14 @@ ) { | ||
} | ||
/** | ||
* Check if an element is a template tag. | ||
* Note if the template appears inside an SVG its tagName | ||
* will be in lowercase. | ||
* | ||
* @param {Element} el | ||
*/ | ||
exports.isTemplate = function (el) { | ||
return el.tagName && | ||
el.tagName.toLowerCase() === 'template' | ||
} |
var _ = require('./index') | ||
var config = require('../config') | ||
var commonTagRE = /^(div|p|span|img|a|br|ul|ol|li|h1|h2|h3|h4|h5|table|tbody|tr|td|pre)$/ | ||
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$/ | ||
@@ -26,2 +27,7 @@ /** | ||
return tag | ||
} else if ( | ||
tableElementsRE.test(tag) && | ||
(tag = _.attr(el, 'component')) | ||
) { | ||
return tag | ||
} | ||
@@ -52,2 +58,2 @@ } | ||
: document.createTextNode(persist ? ' ' : '') | ||
} | ||
} |
@@ -127,2 +127,14 @@ var _ = require('./index') | ||
/** | ||
* 0.11 deprecation warning | ||
*/ | ||
strats.paramAttributes = function () { | ||
/* istanbul ignore next */ | ||
_.warn( | ||
'"paramAttributes" option has been deprecated in 0.12. ' + | ||
'Use "props" instead.' | ||
) | ||
} | ||
/** | ||
* Assets | ||
@@ -129,0 +141,0 @@ * |
@@ -38,7 +38,9 @@ var _ = require('./util') | ||
Vue.options = { | ||
directives : require('./directives'), | ||
filters : require('./filters'), | ||
transitions : {}, | ||
components : {}, | ||
elementDirectives: {} | ||
directives: require('./directives'), | ||
filters: require('./filters'), | ||
transitions: {}, | ||
components: {}, | ||
elementDirectives: { | ||
content: require('./compiler/content') | ||
} | ||
} | ||
@@ -45,0 +47,0 @@ |
@@ -21,2 +21,3 @@ var _ = require('./util') | ||
* - {Boolean} user | ||
* - {Boolean} sync | ||
* - {Function} [preProcess] | ||
@@ -26,6 +27,7 @@ * @constructor | ||
function Watcher (vm, expression, cb, options) { | ||
function Watcher (vm, expOrFn, cb, options) { | ||
var isFn = typeof expOrFn === 'function' | ||
this.vm = vm | ||
vm._watchers.push(this) | ||
this.expression = expression | ||
this.expression = isFn ? '' : expOrFn | ||
this.cb = cb | ||
@@ -38,2 +40,3 @@ this.id = ++uid // uid for batching | ||
this.twoWay = !!options.twoWay | ||
this.sync = !!options.sync | ||
this.filters = options.filters | ||
@@ -44,5 +47,10 @@ this.preProcess = options.preProcess | ||
// parse expression for getter/setter | ||
var res = expParser.parse(expression, options.twoWay) | ||
this.getter = res.get | ||
this.setter = res.set | ||
if (isFn) { | ||
this.getter = expOrFn | ||
this.setter = undefined | ||
} else { | ||
var res = expParser.parse(expOrFn, options.twoWay) | ||
this.getter = res.get | ||
this.setter = res.set | ||
} | ||
this.value = this.get() | ||
@@ -87,3 +95,3 @@ } | ||
'Error when evaluating expression "' + | ||
this.expression + '":\n ' + e | ||
this.expression + '"', e | ||
) | ||
@@ -125,3 +133,3 @@ } | ||
'Error when evaluating setter "' + | ||
this.expression + '":\n ' + e | ||
this.expression + '"', e | ||
) | ||
@@ -137,3 +145,3 @@ } | ||
p.beforeGet = function () { | ||
Observer.target = this | ||
Observer.setTarget(this) | ||
} | ||
@@ -146,3 +154,3 @@ | ||
p.afterGet = function () { | ||
Observer.target = null | ||
Observer.setTarget(null) | ||
var i = this.deps.length | ||
@@ -165,3 +173,3 @@ while (i--) { | ||
p.update = function () { | ||
if (!config.async || config.debug) { | ||
if (this.sync || !config.async) { | ||
this.run() | ||
@@ -236,2 +244,2 @@ } else { | ||
module.exports = Watcher | ||
module.exports = Watcher |
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
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
1302119
79
24756
0
1
46
+ Addednotevil@^1.0.0
+ Addedesprima@1.0.4(transitive)
+ Addedhoister@0.0.2(transitive)
+ Addednotevil@1.3.3(transitive)