user model added; message model changed; tag model added
This commit is contained in:
1 parent
d27216c8a8
commit
f6a8c83586
5156 files changed
+62
-437424
No files matched your search
-21
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-present, Yuxi (Evan) You
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
-11
@@ -1,11 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
export default function bind (el: ASTElement, dir: ASTDirective) {
|
||||
el.wrapData = (code: string) => {
|
||||
return `_b(${code},'${el.tag}',${dir.value},${
|
||||
dir.modifiers && dir.modifiers.prop ? 'true' : 'false'
|
||||
}${
|
||||
dir.modifiers && dir.modifiers.sync ? ',true' : ''
|
||||
})`
|
||||
}
|
||||
}
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import on from './on'
|
||||
import bind from './bind'
|
||||
import { noop } from 'shared/util'
|
||||
|
||||
export default {
|
||||
on,
|
||||
bind,
|
||||
cloak: noop
|
||||
}
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { warn } from 'core/util/index'
|
||||
|
||||
export default function on (el: ASTElement, dir: ASTDirective) {
|
||||
if (process.env.NODE_ENV !== 'production' && dir.modifiers) {
|
||||
warn(`v-on without argument does not support modifiers.`)
|
||||
}
|
||||
el.wrapListeners = (code: string) => `_g(${code},${dir.value})`
|
||||
}
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { parse } from './parser/index'
|
||||
import { optimize } from './optimizer'
|
||||
import { generate } from './codegen/index'
|
||||
import { createCompilerCreator } from './create-compiler'
|
||||
|
||||
// `createCompilerCreator` allows creating compilers that use alternative
|
||||
// parser/optimizer/codegen, e.g the SSR optimizing compiler.
|
||||
// Here we just export a default compiler using the default parts.
|
||||
export const createCompiler = createCompilerCreator(function baseCompile (
|
||||
template: string,
|
||||
options: CompilerOptions
|
||||
): CompiledResult {
|
||||
const ast = parse(template.trim(), options)
|
||||
if (options.optimize !== false) {
|
||||
optimize(ast, options)
|
||||
}
|
||||
const code = generate(ast, options)
|
||||
return {
|
||||
ast,
|
||||
render: code.render,
|
||||
staticRenderFns: code.staticRenderFns
|
||||
}
|
||||
})
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
let decoder
|
||||
|
||||
export default {
|
||||
decode (html: string): string {
|
||||
decoder = decoder || document.createElement('div')
|
||||
decoder.innerHTML = html
|
||||
return decoder.textContent
|
||||
}
|
||||
}
|
||||
-97
@@ -1,97 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
const validDivisionCharRE = /[\w).+\-_$\]]/
|
||||
|
||||
export function parseFilters (exp: string): string {
|
||||
let inSingle = false
|
||||
let inDouble = false
|
||||
let inTemplateString = false
|
||||
let inRegex = false
|
||||
let curly = 0
|
||||
let square = 0
|
||||
let paren = 0
|
||||
let lastFilterIndex = 0
|
||||
let c, prev, i, expression, filters
|
||||
|
||||
for (i = 0; i < exp.length; i++) {
|
||||
prev = c
|
||||
c = exp.charCodeAt(i)
|
||||
if (inSingle) {
|
||||
if (c === 0x27 && prev !== 0x5C) inSingle = false
|
||||
} else if (inDouble) {
|
||||
if (c === 0x22 && prev !== 0x5C) inDouble = false
|
||||
} else if (inTemplateString) {
|
||||
if (c === 0x60 && prev !== 0x5C) inTemplateString = false
|
||||
} else if (inRegex) {
|
||||
if (c === 0x2f && prev !== 0x5C) inRegex = false
|
||||
} else if (
|
||||
c === 0x7C && // pipe
|
||||
exp.charCodeAt(i + 1) !== 0x7C &&
|
||||
exp.charCodeAt(i - 1) !== 0x7C &&
|
||||
!curly && !square && !paren
|
||||
) {
|
||||
if (expression === undefined) {
|
||||
// first filter, end of expression
|
||||
lastFilterIndex = i + 1
|
||||
expression = exp.slice(0, i).trim()
|
||||
} else {
|
||||
pushFilter()
|
||||
}
|
||||
} else {
|
||||
switch (c) {
|
||||
case 0x22: inDouble = true; break // "
|
||||
case 0x27: inSingle = true; break // '
|
||||
case 0x60: inTemplateString = true; break // `
|
||||
case 0x28: paren++; break // (
|
||||
case 0x29: paren--; break // )
|
||||
case 0x5B: square++; break // [
|
||||
case 0x5D: square--; break // ]
|
||||
case 0x7B: curly++; break // {
|
||||
case 0x7D: curly--; break // }
|
||||
}
|
||||
if (c === 0x2f) { // /
|
||||
let j = i - 1
|
||||
let p
|
||||
// find first non-whitespace prev char
|
||||
for (; j >= 0; j--) {
|
||||
p = exp.charAt(j)
|
||||
if (p !== ' ') break
|
||||
}
|
||||
if (!p || !validDivisionCharRE.test(p)) {
|
||||
inRegex = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (expression === undefined) {
|
||||
expression = exp.slice(0, i).trim()
|
||||
} else if (lastFilterIndex !== 0) {
|
||||
pushFilter()
|
||||
}
|
||||
|
||||
function pushFilter () {
|
||||
(filters || (filters = [])).push(exp.slice(lastFilterIndex, i).trim())
|
||||
lastFilterIndex = i + 1
|
||||
}
|
||||
|
||||
if (filters) {
|
||||
for (i = 0; i < filters.length; i++) {
|
||||
expression = wrapFilter(expression, filters[i])
|
||||
}
|
||||
}
|
||||
|
||||
return expression
|
||||
}
|
||||
|
||||
function wrapFilter (exp: string, filter: string): string {
|
||||
const i = filter.indexOf('(')
|
||||
if (i < 0) {
|
||||
// _f: resolveFilter
|
||||
return `_f("${filter}")(${exp})`
|
||||
} else {
|
||||
const name = filter.slice(0, i)
|
||||
const args = filter.slice(i + 1)
|
||||
return `_f("${name}")(${exp}${args !== ')' ? ',' + args : args}`
|
||||
}
|
||||
}
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
import KeepAlive from './keep-alive'
|
||||
|
||||
export default {
|
||||
KeepAlive
|
||||
}
|
||||
-124
@@ -1,124 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { isRegExp, remove } from 'shared/util'
|
||||
import { getFirstComponentChild } from 'core/vdom/helpers/index'
|
||||
|
||||
type VNodeCache = { [key: string]: ?VNode };
|
||||
|
||||
function getComponentName (opts: ?VNodeComponentOptions): ?string {
|
||||
return opts && (opts.Ctor.options.name || opts.tag)
|
||||
}
|
||||
|
||||
function matches (pattern: string | RegExp | Array<string>, name: string): boolean {
|
||||
if (Array.isArray(pattern)) {
|
||||
return pattern.indexOf(name) > -1
|
||||
} else if (typeof pattern === 'string') {
|
||||
return pattern.split(',').indexOf(name) > -1
|
||||
} else if (isRegExp(pattern)) {
|
||||
return pattern.test(name)
|
||||
}
|
||||
/* istanbul ignore next */
|
||||
return false
|
||||
}
|
||||
|
||||
function pruneCache (keepAliveInstance: any, filter: Function) {
|
||||
const { cache, keys, _vnode } = keepAliveInstance
|
||||
for (const key in cache) {
|
||||
const cachedNode: ?VNode = cache[key]
|
||||
if (cachedNode) {
|
||||
const name: ?string = getComponentName(cachedNode.componentOptions)
|
||||
if (name && !filter(name)) {
|
||||
pruneCacheEntry(cache, key, keys, _vnode)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function pruneCacheEntry (
|
||||
cache: VNodeCache,
|
||||
key: string,
|
||||
keys: Array<string>,
|
||||
current?: VNode
|
||||
) {
|
||||
const cached = cache[key]
|
||||
if (cached && (!current || cached.tag !== current.tag)) {
|
||||
cached.componentInstance.$destroy()
|
||||
}
|
||||
cache[key] = null
|
||||
remove(keys, key)
|
||||
}
|
||||
|
||||
const patternTypes: Array<Function> = [String, RegExp, Array]
|
||||
|
||||
export default {
|
||||
name: 'keep-alive',
|
||||
abstract: true,
|
||||
|
||||
props: {
|
||||
include: patternTypes,
|
||||
exclude: patternTypes,
|
||||
max: [String, Number]
|
||||
},
|
||||
|
||||
created () {
|
||||
this.cache = Object.create(null)
|
||||
this.keys = []
|
||||
},
|
||||
|
||||
destroyed () {
|
||||
for (const key in this.cache) {
|
||||
pruneCacheEntry(this.cache, key, this.keys)
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.$watch('include', val => {
|
||||
pruneCache(this, name => matches(val, name))
|
||||
})
|
||||
this.$watch('exclude', val => {
|
||||
pruneCache(this, name => !matches(val, name))
|
||||
})
|
||||
},
|
||||
|
||||
render () {
|
||||
const slot = this.$slots.default
|
||||
const vnode: VNode = getFirstComponentChild(slot)
|
||||
const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions
|
||||
if (componentOptions) {
|
||||
// check pattern
|
||||
const name: ?string = getComponentName(componentOptions)
|
||||
const { include, exclude } = this
|
||||
if (
|
||||
// not included
|
||||
(include && (!name || !matches(include, name))) ||
|
||||
// excluded
|
||||
(exclude && name && matches(exclude, name))
|
||||
) {
|
||||
return vnode
|
||||
}
|
||||
|
||||
const { cache, keys } = this
|
||||
const key: ?string = vnode.key == null
|
||||
// same constructor may get registered as different local components
|
||||
// so cid alone is not enough (#3269)
|
||||
? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')
|
||||
: vnode.key
|
||||
if (cache[key]) {
|
||||
vnode.componentInstance = cache[key].componentInstance
|
||||
// make current key freshest
|
||||
remove(keys, key)
|
||||
keys.push(key)
|
||||
} else {
|
||||
cache[key] = vnode
|
||||
keys.push(key)
|
||||
// prune oldest entry
|
||||
if (this.max && keys.length > parseInt(this.max)) {
|
||||
pruneCacheEntry(cache, keys[0], keys, this._vnode)
|
||||
}
|
||||
}
|
||||
|
||||
vnode.data.keepAlive = true
|
||||
}
|
||||
return vnode || (slot && slot[0])
|
||||
}
|
||||
}
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { ASSET_TYPES } from 'shared/constants'
|
||||
import { isPlainObject, validateComponentName } from '../util/index'
|
||||
|
||||
export function initAssetRegisters (Vue: GlobalAPI) {
|
||||
/**
|
||||
* Create asset registration methods.
|
||||
*/
|
||||
ASSET_TYPES.forEach(type => {
|
||||
Vue[type] = function (
|
||||
id: string,
|
||||
definition: Function | Object
|
||||
): Function | Object | void {
|
||||
if (!definition) {
|
||||
return this.options[type + 's'][id]
|
||||
} else {
|
||||
/* istanbul ignore if */
|
||||
if (process.env.NODE_ENV !== 'production' && type === 'component') {
|
||||
validateComponentName(id)
|
||||
}
|
||||
if (type === 'component' && isPlainObject(definition)) {
|
||||
definition.name = definition.name || id
|
||||
definition = this.options._base.extend(definition)
|
||||
}
|
||||
if (type === 'directive' && typeof definition === 'function') {
|
||||
definition = { bind: definition, update: definition }
|
||||
}
|
||||
this.options[type + 's'][id] = definition
|
||||
return definition
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
-95
@@ -1,95 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { ASSET_TYPES } from 'shared/constants'
|
||||
import { defineComputed, proxy } from '../instance/state'
|
||||
import { extend, mergeOptions, validateComponentName } from '../util/index'
|
||||
|
||||
export function initExtend (Vue: GlobalAPI) {
|
||||
/**
|
||||
* Each instance constructor, including Vue, has a unique
|
||||
* cid. This enables us to create wrapped "child
|
||||
* constructors" for prototypal inheritance and cache them.
|
||||
*/
|
||||
Vue.cid = 0
|
||||
let cid = 1
|
||||
|
||||
/**
|
||||
* Class inheritance
|
||||
*/
|
||||
Vue.extend = function (extendOptions: Object): Function {
|
||||
extendOptions = extendOptions || {}
|
||||
const Super = this
|
||||
const SuperId = Super.cid
|
||||
const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
|
||||
if (cachedCtors[SuperId]) {
|
||||
return cachedCtors[SuperId]
|
||||
}
|
||||
|
||||
const name = extendOptions.name || Super.options.name
|
||||
if (process.env.NODE_ENV !== 'production' && name) {
|
||||
validateComponentName(name)
|
||||
}
|
||||
|
||||
const Sub = function VueComponent (options) {
|
||||
this._init(options)
|
||||
}
|
||||
Sub.prototype = Object.create(Super.prototype)
|
||||
Sub.prototype.constructor = Sub
|
||||
Sub.cid = cid++
|
||||
Sub.options = mergeOptions(
|
||||
Super.options,
|
||||
extendOptions
|
||||
)
|
||||
Sub['super'] = Super
|
||||
|
||||
// For props and computed properties, we define the proxy getters on
|
||||
// the Vue instances at extension time, on the extended prototype. This
|
||||
// avoids Object.defineProperty calls for each instance created.
|
||||
if (Sub.options.props) {
|
||||
initProps(Sub)
|
||||
}
|
||||
if (Sub.options.computed) {
|
||||
initComputed(Sub)
|
||||
}
|
||||
|
||||
// allow further extension/mixin/plugin usage
|
||||
Sub.extend = Super.extend
|
||||
Sub.mixin = Super.mixin
|
||||
Sub.use = Super.use
|
||||
|
||||
// create asset registers, so extended classes
|
||||
// can have their private assets too.
|
||||
ASSET_TYPES.forEach(function (type) {
|
||||
Sub[type] = Super[type]
|
||||
})
|
||||
// enable recursive self-lookup
|
||||
if (name) {
|
||||
Sub.options.components[name] = Sub
|
||||
}
|
||||
|
||||
// keep a reference to the super options at extension time.
|
||||
// later at instantiation we can check if Super's options have
|
||||
// been updated.
|
||||
Sub.superOptions = Super.options
|
||||
Sub.extendOptions = extendOptions
|
||||
Sub.sealedOptions = extend({}, Sub.options)
|
||||
|
||||
// cache constructor
|
||||
cachedCtors[SuperId] = Sub
|
||||
return Sub
|
||||
}
|
||||
}
|
||||
|
||||
function initProps (Comp) {
|
||||
const props = Comp.options.props
|
||||
for (const key in props) {
|
||||
proxy(Comp.prototype, `_props`, key)
|
||||
}
|
||||
}
|
||||
|
||||
function initComputed (Comp) {
|
||||
const computed = Comp.options.computed
|
||||
for (const key in computed) {
|
||||
defineComputed(Comp.prototype, key, computed[key])
|
||||
}
|
||||
}
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { mergeOptions } from '../util/index'
|
||||
|
||||
export function initMixin (Vue: GlobalAPI) {
|
||||
Vue.mixin = function (mixin: Object) {
|
||||
this.options = mergeOptions(this.options, mixin)
|
||||
return this
|
||||
}
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { toArray } from '../util/index'
|
||||
|
||||
export function initUse (Vue: GlobalAPI) {
|
||||
Vue.use = function (plugin: Function | Object) {
|
||||
const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
|
||||
if (installedPlugins.indexOf(plugin) > -1) {
|
||||
return this
|
||||
}
|
||||
|
||||
// additional parameters
|
||||
const args = toArray(arguments, 1)
|
||||
args.unshift(this)
|
||||
if (typeof plugin.install === 'function') {
|
||||
plugin.install.apply(plugin, args)
|
||||
} else if (typeof plugin === 'function') {
|
||||
plugin.apply(null, args)
|
||||
}
|
||||
installedPlugins.push(plugin)
|
||||
return this
|
||||
}
|
||||
}
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
import Vue from './instance/index'
|
||||
import { initGlobalAPI } from './global-api/index'
|
||||
import { isServerRendering } from 'core/util/env'
|
||||
import { FunctionalRenderContext } from 'core/vdom/create-functional-component'
|
||||
|
||||
initGlobalAPI(Vue)
|
||||
|
||||
Object.defineProperty(Vue.prototype, '$isServer', {
|
||||
get: isServerRendering
|
||||
})
|
||||
|
||||
Object.defineProperty(Vue.prototype, '$ssrContext', {
|
||||
get () {
|
||||
/* istanbul ignore next */
|
||||
return this.$vnode && this.$vnode.ssrContext
|
||||
}
|
||||
})
|
||||
|
||||
// expose FunctionalRenderContext for ssr runtime helper installation
|
||||
Object.defineProperty(Vue, 'FunctionalRenderContext', {
|
||||
value: FunctionalRenderContext
|
||||
})
|
||||
|
||||
Vue.version = '__VERSION__'
|
||||
|
||||
export default Vue
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
import { initMixin } from './init'
|
||||
import { stateMixin } from './state'
|
||||
import { renderMixin } from './render'
|
||||
import { eventsMixin } from './events'
|
||||
import { lifecycleMixin } from './lifecycle'
|
||||
import { warn } from '../util/index'
|
||||
|
||||
function Vue (options) {
|
||||
if (process.env.NODE_ENV !== 'production' &&
|
||||
!(this instanceof Vue)
|
||||
) {
|
||||
warn('Vue is a constructor and should be called with the `new` keyword')
|
||||
}
|
||||
this._init(options)
|
||||
}
|
||||
|
||||
initMixin(Vue)
|
||||
stateMixin(Vue)
|
||||
eventsMixin(Vue)
|
||||
lifecycleMixin(Vue)
|
||||
renderMixin(Vue)
|
||||
|
||||
export default Vue
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { warn, extend, isPlainObject } from 'core/util/index'
|
||||
|
||||
export function bindObjectListeners (data: any, value: any): VNodeData {
|
||||
if (value) {
|
||||
if (!isPlainObject(value)) {
|
||||
process.env.NODE_ENV !== 'production' && warn(
|
||||
'v-on without argument expects an Object value',
|
||||
this
|
||||
)
|
||||
} else {
|
||||
const on = data.on = data.on ? extend({}, data.on) : {}
|
||||
for (const key in value) {
|
||||
const existing = on[key]
|
||||
const ours = value[key]
|
||||
on[key] = existing ? [].concat(existing, ours) : ours
|
||||
}
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import config from 'core/config'
|
||||
import { hyphenate } from 'shared/util'
|
||||
|
||||
function isKeyNotMatch<T> (expect: T | Array<T>, actual: T): boolean {
|
||||
if (Array.isArray(expect)) {
|
||||
return expect.indexOf(actual) === -1
|
||||
} else {
|
||||
return expect !== actual
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runtime helper for checking keyCodes from config.
|
||||
* exposed as Vue.prototype._k
|
||||
* passing in eventKeyName as last argument separately for backwards compat
|
||||
*/
|
||||
export function checkKeyCodes (
|
||||
eventKeyCode: number,
|
||||
key: string,
|
||||
builtInKeyCode?: number | Array<number>,
|
||||
eventKeyName?: string,
|
||||
builtInKeyName?: string | Array<string>
|
||||
): ?boolean {
|
||||
const mappedKeyCode = config.keyCodes[key] || builtInKeyCode
|
||||
if (builtInKeyName && eventKeyName && !config.keyCodes[key]) {
|
||||
return isKeyNotMatch(builtInKeyName, eventKeyName)
|
||||
} else if (mappedKeyCode) {
|
||||
return isKeyNotMatch(mappedKeyCode, eventKeyCode)
|
||||
} else if (eventKeyName) {
|
||||
return hyphenate(eventKeyName) !== key
|
||||
}
|
||||
}
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
/**
|
||||
* Runtime helper for rendering static trees.
|
||||
*/
|
||||
export function renderStatic (
|
||||
index: number,
|
||||
isInFor: boolean
|
||||
): VNode | Array<VNode> {
|
||||
const cached = this._staticTrees || (this._staticTrees = [])
|
||||
let tree = cached[index]
|
||||
// if has already-rendered static tree and not inside v-for,
|
||||
// we can reuse the same tree.
|
||||
if (tree && !isInFor) {
|
||||
return tree
|
||||
}
|
||||
// otherwise, render a fresh tree.
|
||||
tree = cached[index] = this.$options.staticRenderFns[index].call(
|
||||
this._renderProxy,
|
||||
null,
|
||||
this // for render fns generated for functional component templates
|
||||
)
|
||||
markStatic(tree, `__static__${index}`, false)
|
||||
return tree
|
||||
}
|
||||
|
||||
/**
|
||||
* Runtime helper for v-once.
|
||||
* Effectively it means marking the node as static with a unique key.
|
||||
*/
|
||||
export function markOnce (
|
||||
tree: VNode | Array<VNode>,
|
||||
index: number,
|
||||
key: string
|
||||
) {
|
||||
markStatic(tree, `__once__${index}${key ? `_${key}` : ``}`, true)
|
||||
return tree
|
||||
}
|
||||
|
||||
function markStatic (
|
||||
tree: VNode | Array<VNode>,
|
||||
key: string,
|
||||
isOnce: boolean
|
||||
) {
|
||||
if (Array.isArray(tree)) {
|
||||
for (let i = 0; i < tree.length; i++) {
|
||||
if (tree[i] && typeof tree[i] !== 'string') {
|
||||
markStaticNode(tree[i], `${key}_${i}`, isOnce)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
markStaticNode(tree, key, isOnce)
|
||||
}
|
||||
}
|
||||
|
||||
function markStaticNode (node, key, isOnce) {
|
||||
node.isStatic = true
|
||||
node.key = key
|
||||
node.isOnce = isOnce
|
||||
}
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { identity, resolveAsset } from 'core/util/index'
|
||||
|
||||
/**
|
||||
* Runtime helper for resolving filters
|
||||
*/
|
||||
export function resolveFilter (id: string): Function {
|
||||
return resolveAsset(this.$options, 'filters', id, true) || identity
|
||||
}
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* not type checking this file because flow doesn't play well with
|
||||
* dynamically accessing methods on Array prototype
|
||||
*/
|
||||
|
||||
import { def } from '../util/index'
|
||||
|
||||
const arrayProto = Array.prototype
|
||||
export const arrayMethods = Object.create(arrayProto)
|
||||
|
||||
const methodsToPatch = [
|
||||
'push',
|
||||
'pop',
|
||||
'shift',
|
||||
'unshift',
|
||||
'splice',
|
||||
'sort',
|
||||
'reverse'
|
||||
]
|
||||
|
||||
/**
|
||||
* Intercept mutating methods and emit events
|
||||
*/
|
||||
methodsToPatch.forEach(function (method) {
|
||||
// cache original method
|
||||
const original = arrayProto[method]
|
||||
def(arrayMethods, method, function mutator (...args) {
|
||||
const result = original.apply(this, args)
|
||||
const ob = this.__ob__
|
||||
let inserted
|
||||
switch (method) {
|
||||
case 'push':
|
||||
case 'unshift':
|
||||
inserted = args
|
||||
break
|
||||
case 'splice':
|
||||
inserted = args.slice(2)
|
||||
break
|
||||
}
|
||||
if (inserted) ob.observeArray(inserted)
|
||||
// notify change
|
||||
ob.dep.notify()
|
||||
return result
|
||||
})
|
||||
})
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { _Set as Set, isObject } from '../util/index'
|
||||
import type { SimpleSet } from '../util/index'
|
||||
import VNode from '../vdom/vnode'
|
||||
|
||||
const seenObjects = new Set()
|
||||
|
||||
/**
|
||||
* Recursively traverse an object to evoke all converted
|
||||
* getters, so that every nested property inside the object
|
||||
* is collected as a "deep" dependency.
|
||||
*/
|
||||
export function traverse (val: any) {
|
||||
_traverse(val, seenObjects)
|
||||
seenObjects.clear()
|
||||
}
|
||||
|
||||
function _traverse (val: any, seen: SimpleSet) {
|
||||
let i, keys
|
||||
const isA = Array.isArray(val)
|
||||
if ((!isA && !isObject(val)) || Object.isFrozen(val) || val instanceof VNode) {
|
||||
return
|
||||
}
|
||||
if (val.__ob__) {
|
||||
const depId = val.__ob__.dep.id
|
||||
if (seen.has(depId)) {
|
||||
return
|
||||
}
|
||||
seen.add(depId)
|
||||
}
|
||||
if (isA) {
|
||||
i = val.length
|
||||
while (i--) _traverse(val[i], seen)
|
||||
} else {
|
||||
keys = Object.keys(val)
|
||||
i = keys.length
|
||||
while (i--) _traverse(val[keys[i]], seen)
|
||||
}
|
||||
}
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
export * from 'shared/util'
|
||||
export * from './lang'
|
||||
export * from './env'
|
||||
export * from './options'
|
||||
export * from './debug'
|
||||
export * from './props'
|
||||
export * from './error'
|
||||
export * from './next-tick'
|
||||
export { defineReactive } from '../observer/index'
|
||||
-75
@@ -1,75 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import {
|
||||
tip,
|
||||
hasOwn,
|
||||
isDef,
|
||||
isUndef,
|
||||
hyphenate,
|
||||
formatComponentName
|
||||
} from 'core/util/index'
|
||||
|
||||
export function extractPropsFromVNodeData (
|
||||
data: VNodeData,
|
||||
Ctor: Class<Component>,
|
||||
tag?: string
|
||||
): ?Object {
|
||||
// we are only extracting raw values here.
|
||||
// validation and default values are handled in the child
|
||||
// component itself.
|
||||
const propOptions = Ctor.options.props
|
||||
if (isUndef(propOptions)) {
|
||||
return
|
||||
}
|
||||
const res = {}
|
||||
const { attrs, props } = data
|
||||
if (isDef(attrs) || isDef(props)) {
|
||||
for (const key in propOptions) {
|
||||
const altKey = hyphenate(key)
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
const keyInLowerCase = key.toLowerCase()
|
||||
if (
|
||||
key !== keyInLowerCase &&
|
||||
attrs && hasOwn(attrs, keyInLowerCase)
|
||||
) {
|
||||
tip(
|
||||
`Prop "${keyInLowerCase}" is passed to component ` +
|
||||
`${formatComponentName(tag || Ctor)}, but the declared prop name is` +
|
||||
` "${key}". ` +
|
||||
`Note that HTML attributes are case-insensitive and camelCased ` +
|
||||
`props need to use their kebab-case equivalents when using in-DOM ` +
|
||||
`templates. You should probably use "${altKey}" instead of "${key}".`
|
||||
)
|
||||
}
|
||||
}
|
||||
checkProp(res, props, key, altKey, true) ||
|
||||
checkProp(res, attrs, key, altKey, false)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
function checkProp (
|
||||
res: Object,
|
||||
hash: ?Object,
|
||||
key: string,
|
||||
altKey: string,
|
||||
preserve: boolean
|
||||
): boolean {
|
||||
if (isDef(hash)) {
|
||||
if (hasOwn(hash, key)) {
|
||||
res[key] = hash[key]
|
||||
if (!preserve) {
|
||||
delete hash[key]
|
||||
}
|
||||
return true
|
||||
} else if (hasOwn(hash, altKey)) {
|
||||
res[key] = hash[altKey]
|
||||
if (!preserve) {
|
||||
delete hash[altKey]
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { isDef } from 'shared/util'
|
||||
import { isAsyncPlaceholder } from './is-async-placeholder'
|
||||
|
||||
export function getFirstComponentChild (children: ?Array<VNode>): ?VNode {
|
||||
if (Array.isArray(children)) {
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
const c = children[i]
|
||||
if (isDef(c) && (isDef(c.componentOptions) || isAsyncPlaceholder(c))) {
|
||||
return c
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
export * from './merge-hook'
|
||||
export * from './extract-props'
|
||||
export * from './update-listeners'
|
||||
export * from './normalize-children'
|
||||
export * from './resolve-async-component'
|
||||
export * from './get-first-component-child'
|
||||
export * from './is-async-placeholder'
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
export function isAsyncPlaceholder (node: VNode): boolean {
|
||||
return node.isComment && node.asyncFactory
|
||||
}
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import VNode from '../vnode'
|
||||
import { createFnInvoker } from './update-listeners'
|
||||
import { remove, isDef, isUndef, isTrue } from 'shared/util'
|
||||
|
||||
export function mergeVNodeHook (def: Object, hookKey: string, hook: Function) {
|
||||
if (def instanceof VNode) {
|
||||
def = def.data.hook || (def.data.hook = {})
|
||||
}
|
||||
let invoker
|
||||
const oldHook = def[hookKey]
|
||||
|
||||
function wrappedHook () {
|
||||
hook.apply(this, arguments)
|
||||
// important: remove merged hook to ensure it's called only once
|
||||
// and prevent memory leak
|
||||
remove(invoker.fns, wrappedHook)
|
||||
}
|
||||
|
||||
if (isUndef(oldHook)) {
|
||||
// no existing hook
|
||||
invoker = createFnInvoker([wrappedHook])
|
||||
} else {
|
||||
/* istanbul ignore if */
|
||||
if (isDef(oldHook.fns) && isTrue(oldHook.merged)) {
|
||||
// already a merged invoker
|
||||
invoker = oldHook
|
||||
invoker.fns.push(wrappedHook)
|
||||
} else {
|
||||
// existing plain hook
|
||||
invoker = createFnInvoker([oldHook, wrappedHook])
|
||||
}
|
||||
}
|
||||
|
||||
invoker.merged = true
|
||||
def[hookKey] = invoker
|
||||
}
|
||||
-89
@@ -1,89 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import VNode, { createTextVNode } from 'core/vdom/vnode'
|
||||
import { isFalse, isTrue, isDef, isUndef, isPrimitive } from 'shared/util'
|
||||
|
||||
// The template compiler attempts to minimize the need for normalization by
|
||||
// statically analyzing the template at compile time.
|
||||
//
|
||||
// For plain HTML markup, normalization can be completely skipped because the
|
||||
// generated render function is guaranteed to return Array<VNode>. There are
|
||||
// two cases where extra normalization is needed:
|
||||
|
||||
// 1. When the children contains components - because a functional component
|
||||
// may return an Array instead of a single root. In this case, just a simple
|
||||
// normalization is needed - if any child is an Array, we flatten the whole
|
||||
// thing with Array.prototype.concat. It is guaranteed to be only 1-level deep
|
||||
// because functional components already normalize their own children.
|
||||
export function simpleNormalizeChildren (children: any) {
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
if (Array.isArray(children[i])) {
|
||||
return Array.prototype.concat.apply([], children)
|
||||
}
|
||||
}
|
||||
return children
|
||||
}
|
||||
|
||||
// 2. When the children contains constructs that always generated nested Arrays,
|
||||
// e.g. <template>, <slot>, v-for, or when the children is provided by user
|
||||
// with hand-written render functions / JSX. In such cases a full normalization
|
||||
// is needed to cater to all possible types of children values.
|
||||
export function normalizeChildren (children: any): ?Array<VNode> {
|
||||
return isPrimitive(children)
|
||||
? [createTextVNode(children)]
|
||||
: Array.isArray(children)
|
||||
? normalizeArrayChildren(children)
|
||||
: undefined
|
||||
}
|
||||
|
||||
function isTextNode (node): boolean {
|
||||
return isDef(node) && isDef(node.text) && isFalse(node.isComment)
|
||||
}
|
||||
|
||||
function normalizeArrayChildren (children: any, nestedIndex?: string): Array<VNode> {
|
||||
const res = []
|
||||
let i, c, lastIndex, last
|
||||
for (i = 0; i < children.length; i++) {
|
||||
c = children[i]
|
||||
if (isUndef(c) || typeof c === 'boolean') continue
|
||||
lastIndex = res.length - 1
|
||||
last = res[lastIndex]
|
||||
// nested
|
||||
if (Array.isArray(c)) {
|
||||
if (c.length > 0) {
|
||||
c = normalizeArrayChildren(c, `${nestedIndex || ''}_${i}`)
|
||||
// merge adjacent text nodes
|
||||
if (isTextNode(c[0]) && isTextNode(last)) {
|
||||
res[lastIndex] = createTextVNode(last.text + (c[0]: any).text)
|
||||
c.shift()
|
||||
}
|
||||
res.push.apply(res, c)
|
||||
}
|
||||
} else if (isPrimitive(c)) {
|
||||
if (isTextNode(last)) {
|
||||
// merge adjacent text nodes
|
||||
// this is necessary for SSR hydration because text nodes are
|
||||
// essentially merged when rendered to HTML strings
|
||||
res[lastIndex] = createTextVNode(last.text + c)
|
||||
} else if (c !== '') {
|
||||
// convert primitive to vnode
|
||||
res.push(createTextVNode(c))
|
||||
}
|
||||
} else {
|
||||
if (isTextNode(c) && isTextNode(last)) {
|
||||
// merge adjacent text nodes
|
||||
res[lastIndex] = createTextVNode(last.text + c.text)
|
||||
} else {
|
||||
// default key for nested array children (likely generated by v-for)
|
||||
if (isTrue(children._isVList) &&
|
||||
isDef(c.tag) &&
|
||||
isUndef(c.key) &&
|
||||
isDef(nestedIndex)) {
|
||||
c.key = `__vlist${nestedIndex}_${i}__`
|
||||
}
|
||||
res.push(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
import directives from './directives'
|
||||
import ref from './ref'
|
||||
|
||||
export default [
|
||||
ref,
|
||||
directives
|
||||
]
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { remove, isDef } from 'shared/util'
|
||||
|
||||
export default {
|
||||
create (_: any, vnode: VNodeWithData) {
|
||||
registerRef(vnode)
|
||||
},
|
||||
update (oldVnode: VNodeWithData, vnode: VNodeWithData) {
|
||||
if (oldVnode.data.ref !== vnode.data.ref) {
|
||||
registerRef(oldVnode, true)
|
||||
registerRef(vnode)
|
||||
}
|
||||
},
|
||||
destroy (vnode: VNodeWithData) {
|
||||
registerRef(vnode, true)
|
||||
}
|
||||
}
|
||||
|
||||
export function registerRef (vnode: VNodeWithData, isRemoval: ?boolean) {
|
||||
const key = vnode.data.ref
|
||||
if (!isDef(key)) return
|
||||
|
||||
const vm = vnode.context
|
||||
const ref = vnode.componentInstance || vnode.elm
|
||||
const refs = vm.$refs
|
||||
if (isRemoval) {
|
||||
if (Array.isArray(refs[key])) {
|
||||
remove(refs[key], ref)
|
||||
} else if (refs[key] === ref) {
|
||||
refs[key] = undefined
|
||||
}
|
||||
} else {
|
||||
if (vnode.data.refInFor) {
|
||||
if (!Array.isArray(refs[key])) {
|
||||
refs[key] = [ref]
|
||||
} else if (refs[key].indexOf(ref) < 0) {
|
||||
// $flow-disable-line
|
||||
refs[key].push(ref)
|
||||
}
|
||||
} else {
|
||||
refs[key] = ref
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
Binary file not shown.
-9
@@ -1,9 +0,0 @@
|
||||
import model from './model'
|
||||
import text from './text'
|
||||
import html from './html'
|
||||
|
||||
export default {
|
||||
model,
|
||||
text,
|
||||
html
|
||||
}
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { baseOptions } from './options'
|
||||
import { createCompiler } from 'compiler/index'
|
||||
|
||||
const { compile, compileToFunctions } = createCompiler(baseOptions)
|
||||
|
||||
export { compile, compileToFunctions }
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
import klass from './class'
|
||||
import style from './style'
|
||||
import model from './model'
|
||||
|
||||
export default [
|
||||
klass,
|
||||
style,
|
||||
model
|
||||
]
|
||||
-94
@@ -1,94 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
/**
|
||||
* Expand input[v-model] with dyanmic type bindings into v-if-else chains
|
||||
* Turn this:
|
||||
* <input v-model="data[type]" :type="type">
|
||||
* into this:
|
||||
* <input v-if="type === 'checkbox'" type="checkbox" v-model="data[type]">
|
||||
* <input v-else-if="type === 'radio'" type="radio" v-model="data[type]">
|
||||
* <input v-else :type="type" v-model="data[type]">
|
||||
*/
|
||||
|
||||
import {
|
||||
addRawAttr,
|
||||
getBindingAttr,
|
||||
getAndRemoveAttr
|
||||
} from 'compiler/helpers'
|
||||
|
||||
import {
|
||||
processFor,
|
||||
processElement,
|
||||
addIfCondition,
|
||||
createASTElement
|
||||
} from 'compiler/parser/index'
|
||||
|
||||
function preTransformNode (el: ASTElement, options: CompilerOptions) {
|
||||
if (el.tag === 'input') {
|
||||
const map = el.attrsMap
|
||||
if (!map['v-model']) {
|
||||
return
|
||||
}
|
||||
|
||||
let typeBinding
|
||||
if (map[':type'] || map['v-bind:type']) {
|
||||
typeBinding = getBindingAttr(el, 'type')
|
||||
}
|
||||
if (!map.type && !typeBinding && map['v-bind']) {
|
||||
typeBinding = `(${map['v-bind']}).type`
|
||||
}
|
||||
|
||||
if (typeBinding) {
|
||||
const ifCondition = getAndRemoveAttr(el, 'v-if', true)
|
||||
const ifConditionExtra = ifCondition ? `&&(${ifCondition})` : ``
|
||||
const hasElse = getAndRemoveAttr(el, 'v-else', true) != null
|
||||
const elseIfCondition = getAndRemoveAttr(el, 'v-else-if', true)
|
||||
// 1. checkbox
|
||||
const branch0 = cloneASTElement(el)
|
||||
// process for on the main node
|
||||
processFor(branch0)
|
||||
addRawAttr(branch0, 'type', 'checkbox')
|
||||
processElement(branch0, options)
|
||||
branch0.processed = true // prevent it from double-processed
|
||||
branch0.if = `(${typeBinding})==='checkbox'` + ifConditionExtra
|
||||
addIfCondition(branch0, {
|
||||
exp: branch0.if,
|
||||
block: branch0
|
||||
})
|
||||
// 2. add radio else-if condition
|
||||
const branch1 = cloneASTElement(el)
|
||||
getAndRemoveAttr(branch1, 'v-for', true)
|
||||
addRawAttr(branch1, 'type', 'radio')
|
||||
processElement(branch1, options)
|
||||
addIfCondition(branch0, {
|
||||
exp: `(${typeBinding})==='radio'` + ifConditionExtra,
|
||||
block: branch1
|
||||
})
|
||||
// 3. other
|
||||
const branch2 = cloneASTElement(el)
|
||||
getAndRemoveAttr(branch2, 'v-for', true)
|
||||
addRawAttr(branch2, ':type', typeBinding)
|
||||
processElement(branch2, options)
|
||||
addIfCondition(branch0, {
|
||||
exp: ifCondition,
|
||||
block: branch2
|
||||
})
|
||||
|
||||
if (hasElse) {
|
||||
branch0.else = true
|
||||
} else if (elseIfCondition) {
|
||||
branch0.elseif = elseIfCondition
|
||||
}
|
||||
|
||||
return branch0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function cloneASTElement (el) {
|
||||
return createASTElement(el.tag, el.attrsList.slice(), el.parent)
|
||||
}
|
||||
|
||||
export default {
|
||||
preTransformNode
|
||||
}
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import {
|
||||
isPreTag,
|
||||
mustUseProp,
|
||||
isReservedTag,
|
||||
getTagNamespace
|
||||
} from '../util/index'
|
||||
|
||||
import modules from './modules/index'
|
||||
import directives from './directives/index'
|
||||
import { genStaticKeys } from 'shared/util'
|
||||
import { isUnaryTag, canBeLeftOpenTag } from './util'
|
||||
|
||||
export const baseOptions: CompilerOptions = {
|
||||
expectHTML: true,
|
||||
modules,
|
||||
directives,
|
||||
isPreTag,
|
||||
isUnaryTag,
|
||||
mustUseProp,
|
||||
canBeLeftOpenTag,
|
||||
isReservedTag,
|
||||
getTagNamespace,
|
||||
staticKeys: genStaticKeys(modules)
|
||||
}
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { makeMap } from 'shared/util'
|
||||
|
||||
export const isUnaryTag = makeMap(
|
||||
'area,base,br,col,embed,frame,hr,img,input,isindex,keygen,' +
|
||||
'link,meta,param,source,track,wbr'
|
||||
)
|
||||
|
||||
// Elements that you can, intentionally, leave open
|
||||
// (and which close themselves)
|
||||
export const canBeLeftOpenTag = makeMap(
|
||||
'colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source'
|
||||
)
|
||||
|
||||
// HTML5 tags https://html.spec.whatwg.org/multipage/indices.html#elements-3
|
||||
// Phrasing Content https://html.spec.whatwg.org/multipage/dom.html#phrasing-content
|
||||
export const isNonPhrasingTag = makeMap(
|
||||
'address,article,aside,base,blockquote,body,caption,col,colgroup,dd,' +
|
||||
'details,dialog,div,dl,dt,fieldset,figcaption,figure,footer,form,' +
|
||||
'h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,legend,li,menuitem,meta,' +
|
||||
'optgroup,option,param,rp,rt,source,style,summary,tbody,td,tfoot,th,thead,' +
|
||||
'title,tr,track'
|
||||
)
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import Vue from './runtime/index'
|
||||
|
||||
export default Vue
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import modules from './server/modules/index'
|
||||
import directives from './server/directives/index'
|
||||
import { isUnaryTag, canBeLeftOpenTag } from './compiler/util'
|
||||
import { createBasicRenderer } from 'server/create-basic-renderer'
|
||||
|
||||
export default createBasicRenderer({
|
||||
modules,
|
||||
directives,
|
||||
isUnaryTag,
|
||||
canBeLeftOpenTag
|
||||
})
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
process.env.VUE_ENV = 'server'
|
||||
|
||||
import { extend } from 'shared/util'
|
||||
import modules from './server/modules/index'
|
||||
import baseDirectives from './server/directives/index'
|
||||
import { isUnaryTag, canBeLeftOpenTag } from './compiler/util'
|
||||
|
||||
import { createRenderer as _createRenderer } from 'server/create-renderer'
|
||||
import { createBundleRendererCreator } from 'server/bundle-renderer/create-bundle-renderer'
|
||||
|
||||
export function createRenderer (options?: Object = {}): {
|
||||
renderToString: Function,
|
||||
renderToStream: Function
|
||||
} {
|
||||
return _createRenderer(extend(extend({}, options), {
|
||||
isUnaryTag,
|
||||
canBeLeftOpenTag,
|
||||
modules,
|
||||
// user can provide server-side implementations for custom directives
|
||||
// when creating the renderer.
|
||||
directives: extend(baseDirectives, options.directives)
|
||||
}))
|
||||
}
|
||||
|
||||
export const createBundleRenderer = createBundleRendererCreator(createRenderer)
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
import Transition from './transition'
|
||||
import TransitionGroup from './transition-group'
|
||||
|
||||
export default {
|
||||
Transition,
|
||||
TransitionGroup
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
import model from './model'
|
||||
import show from './show'
|
||||
|
||||
export default {
|
||||
model,
|
||||
show
|
||||
}
|
||||
-147
@@ -1,147 +0,0 @@
|
||||
/**
|
||||
* Not type checking this file because flow doesn't like attaching
|
||||
* properties to Elements.
|
||||
*/
|
||||
|
||||
import { isTextInputType } from 'web/util/element'
|
||||
import { looseEqual, looseIndexOf } from 'shared/util'
|
||||
import { mergeVNodeHook } from 'core/vdom/helpers/index'
|
||||
import { warn, isIE9, isIE, isEdge } from 'core/util/index'
|
||||
|
||||
/* istanbul ignore if */
|
||||
if (isIE9) {
|
||||
// http://www.matts411.com/post/internet-explorer-9-oninput/
|
||||
document.addEventListener('selectionchange', () => {
|
||||
const el = document.activeElement
|
||||
if (el && el.vmodel) {
|
||||
trigger(el, 'input')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const directive = {
|
||||
inserted (el, binding, vnode, oldVnode) {
|
||||
if (vnode.tag === 'select') {
|
||||
// #6903
|
||||
if (oldVnode.elm && !oldVnode.elm._vOptions) {
|
||||
mergeVNodeHook(vnode, 'postpatch', () => {
|
||||
directive.componentUpdated(el, binding, vnode)
|
||||
})
|
||||
} else {
|
||||
setSelected(el, binding, vnode.context)
|
||||
}
|
||||
el._vOptions = [].map.call(el.options, getValue)
|
||||
} else if (vnode.tag === 'textarea' || isTextInputType(el.type)) {
|
||||
el._vModifiers = binding.modifiers
|
||||
if (!binding.modifiers.lazy) {
|
||||
el.addEventListener('compositionstart', onCompositionStart)
|
||||
el.addEventListener('compositionend', onCompositionEnd)
|
||||
// Safari < 10.2 & UIWebView doesn't fire compositionend when
|
||||
// switching focus before confirming composition choice
|
||||
// this also fixes the issue where some browsers e.g. iOS Chrome
|
||||
// fires "change" instead of "input" on autocomplete.
|
||||
el.addEventListener('change', onCompositionEnd)
|
||||
/* istanbul ignore if */
|
||||
if (isIE9) {
|
||||
el.vmodel = true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
componentUpdated (el, binding, vnode) {
|
||||
if (vnode.tag === 'select') {
|
||||
setSelected(el, binding, vnode.context)
|
||||
// in case the options rendered by v-for have changed,
|
||||
// it's possible that the value is out-of-sync with the rendered options.
|
||||
// detect such cases and filter out values that no longer has a matching
|
||||
// option in the DOM.
|
||||
const prevOptions = el._vOptions
|
||||
const curOptions = el._vOptions = [].map.call(el.options, getValue)
|
||||
if (curOptions.some((o, i) => !looseEqual(o, prevOptions[i]))) {
|
||||
// trigger change event if
|
||||
// no matching option found for at least one value
|
||||
const needReset = el.multiple
|
||||
? binding.value.some(v => hasNoMatchingOption(v, curOptions))
|
||||
: binding.value !== binding.oldValue && hasNoMatchingOption(binding.value, curOptions)
|
||||
if (needReset) {
|
||||
trigger(el, 'change')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setSelected (el, binding, vm) {
|
||||
actuallySetSelected(el, binding, vm)
|
||||
/* istanbul ignore if */
|
||||
if (isIE || isEdge) {
|
||||
setTimeout(() => {
|
||||
actuallySetSelected(el, binding, vm)
|
||||
}, 0)
|
||||
}
|
||||
}
|
||||
|
||||
function actuallySetSelected (el, binding, vm) {
|
||||
const value = binding.value
|
||||
const isMultiple = el.multiple
|
||||
if (isMultiple && !Array.isArray(value)) {
|
||||
process.env.NODE_ENV !== 'production' && warn(
|
||||
`<select multiple v-model="${binding.expression}"> ` +
|
||||
`expects an Array value for its binding, but got ${
|
||||
Object.prototype.toString.call(value).slice(8, -1)
|
||||
}`,
|
||||
vm
|
||||
)
|
||||
return
|
||||
}
|
||||
let selected, option
|
||||
for (let i = 0, l = el.options.length; i < l; i++) {
|
||||
option = el.options[i]
|
||||
if (isMultiple) {
|
||||
selected = looseIndexOf(value, getValue(option)) > -1
|
||||
if (option.selected !== selected) {
|
||||
option.selected = selected
|
||||
}
|
||||
} else {
|
||||
if (looseEqual(getValue(option), value)) {
|
||||
if (el.selectedIndex !== i) {
|
||||
el.selectedIndex = i
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isMultiple) {
|
||||
el.selectedIndex = -1
|
||||
}
|
||||
}
|
||||
|
||||
function hasNoMatchingOption (value, options) {
|
||||
return options.every(o => !looseEqual(o, value))
|
||||
}
|
||||
|
||||
function getValue (option) {
|
||||
return '_value' in option
|
||||
? option._value
|
||||
: option.value
|
||||
}
|
||||
|
||||
function onCompositionStart (e) {
|
||||
e.target.composing = true
|
||||
}
|
||||
|
||||
function onCompositionEnd (e) {
|
||||
// prevent triggering an input event for no reason
|
||||
if (!e.target.composing) return
|
||||
e.target.composing = false
|
||||
trigger(e.target, 'input')
|
||||
}
|
||||
|
||||
function trigger (el, type) {
|
||||
const e = document.createEvent('HTMLEvents')
|
||||
e.initEvent(type, true, true)
|
||||
el.dispatchEvent(e)
|
||||
}
|
||||
|
||||
export default directive
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { enter, leave } from '../modules/transition'
|
||||
|
||||
// recursively search for possible transition defined inside the component root
|
||||
function locateNode (vnode: VNode): VNodeWithData {
|
||||
return vnode.componentInstance && (!vnode.data || !vnode.data.transition)
|
||||
? locateNode(vnode.componentInstance._vnode)
|
||||
: vnode
|
||||
}
|
||||
|
||||
export default {
|
||||
bind (el: any, { value }: VNodeDirective, vnode: VNodeWithData) {
|
||||
vnode = locateNode(vnode)
|
||||
const transition = vnode.data && vnode.data.transition
|
||||
const originalDisplay = el.__vOriginalDisplay =
|
||||
el.style.display === 'none' ? '' : el.style.display
|
||||
if (value && transition) {
|
||||
vnode.data.show = true
|
||||
enter(vnode, () => {
|
||||
el.style.display = originalDisplay
|
||||
})
|
||||
} else {
|
||||
el.style.display = value ? originalDisplay : 'none'
|
||||
}
|
||||
},
|
||||
|
||||
update (el: any, { value, oldValue }: VNodeDirective, vnode: VNodeWithData) {
|
||||
/* istanbul ignore if */
|
||||
if (!value === !oldValue) return
|
||||
vnode = locateNode(vnode)
|
||||
const transition = vnode.data && vnode.data.transition
|
||||
if (transition) {
|
||||
vnode.data.show = true
|
||||
if (value) {
|
||||
enter(vnode, () => {
|
||||
el.style.display = el.__vOriginalDisplay
|
||||
})
|
||||
} else {
|
||||
leave(vnode, () => {
|
||||
el.style.display = 'none'
|
||||
})
|
||||
}
|
||||
} else {
|
||||
el.style.display = value ? el.__vOriginalDisplay : 'none'
|
||||
}
|
||||
},
|
||||
|
||||
unbind (
|
||||
el: any,
|
||||
binding: VNodeDirective,
|
||||
vnode: VNodeWithData,
|
||||
oldVnode: VNodeWithData,
|
||||
isDestroy: boolean
|
||||
) {
|
||||
if (!isDestroy) {
|
||||
el.style.display = el.__vOriginalDisplay
|
||||
}
|
||||
}
|
||||
}
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import {
|
||||
isDef,
|
||||
isUndef
|
||||
} from 'shared/util'
|
||||
|
||||
import {
|
||||
concat,
|
||||
stringifyClass,
|
||||
genClassForVnode
|
||||
} from 'web/util/index'
|
||||
|
||||
function updateClass (oldVnode: any, vnode: any) {
|
||||
const el = vnode.elm
|
||||
const data: VNodeData = vnode.data
|
||||
const oldData: VNodeData = oldVnode.data
|
||||
if (
|
||||
isUndef(data.staticClass) &&
|
||||
isUndef(data.class) && (
|
||||
isUndef(oldData) || (
|
||||
isUndef(oldData.staticClass) &&
|
||||
isUndef(oldData.class)
|
||||
)
|
||||
)
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
let cls = genClassForVnode(vnode)
|
||||
|
||||
// handle transition classes
|
||||
const transitionClass = el._transitionClasses
|
||||
if (isDef(transitionClass)) {
|
||||
cls = concat(cls, stringifyClass(transitionClass))
|
||||
}
|
||||
|
||||
// set the class
|
||||
if (cls !== el._prevClass) {
|
||||
el.setAttribute('class', cls)
|
||||
el._prevClass = cls
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
create: updateClass,
|
||||
update: updateClass
|
||||
}
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
import attrs from './attrs'
|
||||
import klass from './class'
|
||||
import events from './events'
|
||||
import domProps from './dom-props'
|
||||
import style from './style'
|
||||
import transition from './transition'
|
||||
|
||||
export default [
|
||||
attrs,
|
||||
klass,
|
||||
events,
|
||||
domProps,
|
||||
style,
|
||||
transition
|
||||
]
|
||||
-59
@@ -1,59 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { namespaceMap } from 'web/util/index'
|
||||
|
||||
export function createElement (tagName: string, vnode: VNode): Element {
|
||||
const elm = document.createElement(tagName)
|
||||
if (tagName !== 'select') {
|
||||
return elm
|
||||
}
|
||||
// false or null will remove the attribute but undefined will not
|
||||
if (vnode.data && vnode.data.attrs && vnode.data.attrs.multiple !== undefined) {
|
||||
elm.setAttribute('multiple', 'multiple')
|
||||
}
|
||||
return elm
|
||||
}
|
||||
|
||||
export function createElementNS (namespace: string, tagName: string): Element {
|
||||
return document.createElementNS(namespaceMap[namespace], tagName)
|
||||
}
|
||||
|
||||
export function createTextNode (text: string): Text {
|
||||
return document.createTextNode(text)
|
||||
}
|
||||
|
||||
export function createComment (text: string): Comment {
|
||||
return document.createComment(text)
|
||||
}
|
||||
|
||||
export function insertBefore (parentNode: Node, newNode: Node, referenceNode: Node) {
|
||||
parentNode.insertBefore(newNode, referenceNode)
|
||||
}
|
||||
|
||||
export function removeChild (node: Node, child: Node) {
|
||||
node.removeChild(child)
|
||||
}
|
||||
|
||||
export function appendChild (node: Node, child: Node) {
|
||||
node.appendChild(child)
|
||||
}
|
||||
|
||||
export function parentNode (node: Node): ?Node {
|
||||
return node.parentNode
|
||||
}
|
||||
|
||||
export function nextSibling (node: Node): ?Node {
|
||||
return node.nextSibling
|
||||
}
|
||||
|
||||
export function tagName (node: Element): string {
|
||||
return node.tagName
|
||||
}
|
||||
|
||||
export function setTextContent (node: Node, text: string) {
|
||||
node.textContent = text
|
||||
}
|
||||
|
||||
export function setStyleScope (node: Element, scopeId: string) {
|
||||
node.setAttribute(scopeId, '')
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import * as nodeOps from 'web/runtime/node-ops'
|
||||
import { createPatchFunction } from 'core/vdom/patch'
|
||||
import baseModules from 'core/vdom/modules/index'
|
||||
import platformModules from 'web/runtime/modules/index'
|
||||
|
||||
// the directive module should be applied last, after all
|
||||
// built-in modules have been applied.
|
||||
const modules = platformModules.concat(baseModules)
|
||||
|
||||
export const patch: Function = createPatchFunction({ nodeOps, modules })
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { baseOptions } from '../compiler/options'
|
||||
import { createCompiler } from 'server/optimizing-compiler/index'
|
||||
|
||||
const { compile, compileToFunctions } = createCompiler(baseOptions)
|
||||
|
||||
export {
|
||||
compile as ssrCompile,
|
||||
compileToFunctions as ssrCompileToFunctions
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
import show from './show'
|
||||
import model from './model'
|
||||
|
||||
export default {
|
||||
show,
|
||||
model
|
||||
}
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { looseEqual, looseIndexOf } from 'shared/util'
|
||||
|
||||
// this is only applied for <select v-model> because it is the only edge case
|
||||
// that must be done at runtime instead of compile time.
|
||||
export default function model (node: VNodeWithData, dir: VNodeDirective) {
|
||||
if (!node.children) return
|
||||
const value = dir.value
|
||||
const isMultiple = node.data.attrs && node.data.attrs.multiple
|
||||
for (let i = 0, l = node.children.length; i < l; i++) {
|
||||
const option = node.children[i]
|
||||
if (option.tag === 'option') {
|
||||
if (isMultiple) {
|
||||
const selected =
|
||||
Array.isArray(value) &&
|
||||
(looseIndexOf(value, getValue(option)) > -1)
|
||||
if (selected) {
|
||||
setSelected(option)
|
||||
}
|
||||
} else {
|
||||
if (looseEqual(value, getValue(option))) {
|
||||
setSelected(option)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getValue (option) {
|
||||
const data = option.data || {}
|
||||
return (
|
||||
(data.attrs && data.attrs.value) ||
|
||||
(data.domProps && data.domProps.value) ||
|
||||
(option.children && option.children[0] && option.children[0].text)
|
||||
)
|
||||
}
|
||||
|
||||
function setSelected (option) {
|
||||
const data = option.data || (option.data = {})
|
||||
const attrs = data.attrs || (data.attrs = {})
|
||||
attrs.selected = ''
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
export default function show (node: VNodeWithData, dir: VNodeDirective) {
|
||||
if (!dir.value) {
|
||||
const style: any = node.data.style || (node.data.style = {})
|
||||
if (Array.isArray(style)) {
|
||||
style.push({ display: 'none' })
|
||||
} else {
|
||||
style.display = 'none'
|
||||
}
|
||||
}
|
||||
}
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { escape } from '../util'
|
||||
import { genClassForVnode } from 'web/util/index'
|
||||
|
||||
export default function renderClass (node: VNodeWithData): ?string {
|
||||
const classList = genClassForVnode(node)
|
||||
if (classList !== '') {
|
||||
return ` class="${escape(classList)}"`
|
||||
}
|
||||
}
|
||||
-50
@@ -1,50 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import VNode from 'core/vdom/vnode'
|
||||
import { renderAttr } from './attrs'
|
||||
import { isDef, isUndef, extend } from 'shared/util'
|
||||
import { propsToAttrMap, isRenderableAttr } from '../util'
|
||||
|
||||
export default function renderDOMProps (node: VNodeWithData): string {
|
||||
let props = node.data.domProps
|
||||
let res = ''
|
||||
|
||||
let parent = node.parent
|
||||
while (isDef(parent)) {
|
||||
if (parent.data && parent.data.domProps) {
|
||||
props = extend(extend({}, props), parent.data.domProps)
|
||||
}
|
||||
parent = parent.parent
|
||||
}
|
||||
|
||||
if (isUndef(props)) {
|
||||
return res
|
||||
}
|
||||
|
||||
const attrs = node.data.attrs
|
||||
for (const key in props) {
|
||||
if (key === 'innerHTML') {
|
||||
setText(node, props[key], true)
|
||||
} else if (key === 'textContent') {
|
||||
setText(node, props[key], false)
|
||||
} else if (key === 'value' && node.tag === 'textarea') {
|
||||
setText(node, props[key], false)
|
||||
} else {
|
||||
// $flow-disable-line (WTF?)
|
||||
const attr = propsToAttrMap[key] || key.toLowerCase()
|
||||
if (isRenderableAttr(attr) &&
|
||||
// avoid rendering double-bound props/attrs twice
|
||||
!(isDef(attrs) && isDef(attrs[attr]))
|
||||
) {
|
||||
res += renderAttr(attr, props[key])
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
function setText (node, text, raw) {
|
||||
const child = new VNode(undefined, undefined, undefined, text)
|
||||
child.raw = raw
|
||||
node.children = [child]
|
||||
}
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
import attrs from './attrs'
|
||||
import domProps from './dom-props'
|
||||
import klass from './class'
|
||||
import style from './style'
|
||||
|
||||
export default [
|
||||
attrs,
|
||||
domProps,
|
||||
klass,
|
||||
style
|
||||
]
|
||||
-85
@@ -1,85 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { isDef, isObject } from 'shared/util'
|
||||
|
||||
export function genClassForVnode (vnode: VNodeWithData): string {
|
||||
let data = vnode.data
|
||||
let parentNode = vnode
|
||||
let childNode = vnode
|
||||
while (isDef(childNode.componentInstance)) {
|
||||
childNode = childNode.componentInstance._vnode
|
||||
if (childNode && childNode.data) {
|
||||
data = mergeClassData(childNode.data, data)
|
||||
}
|
||||
}
|
||||
while (isDef(parentNode = parentNode.parent)) {
|
||||
if (parentNode && parentNode.data) {
|
||||
data = mergeClassData(data, parentNode.data)
|
||||
}
|
||||
}
|
||||
return renderClass(data.staticClass, data.class)
|
||||
}
|
||||
|
||||
function mergeClassData (child: VNodeData, parent: VNodeData): {
|
||||
staticClass: string,
|
||||
class: any
|
||||
} {
|
||||
return {
|
||||
staticClass: concat(child.staticClass, parent.staticClass),
|
||||
class: isDef(child.class)
|
||||
? [child.class, parent.class]
|
||||
: parent.class
|
||||
}
|
||||
}
|
||||
|
||||
export function renderClass (
|
||||
staticClass: ?string,
|
||||
dynamicClass: any
|
||||
): string {
|
||||
if (isDef(staticClass) || isDef(dynamicClass)) {
|
||||
return concat(staticClass, stringifyClass(dynamicClass))
|
||||
}
|
||||
/* istanbul ignore next */
|
||||
return ''
|
||||
}
|
||||
|
||||
export function concat (a: ?string, b: ?string): string {
|
||||
return a ? b ? (a + ' ' + b) : a : (b || '')
|
||||
}
|
||||
|
||||
export function stringifyClass (value: any): string {
|
||||
if (Array.isArray(value)) {
|
||||
return stringifyArray(value)
|
||||
}
|
||||
if (isObject(value)) {
|
||||
return stringifyObject(value)
|
||||
}
|
||||
if (typeof value === 'string') {
|
||||
return value
|
||||
}
|
||||
/* istanbul ignore next */
|
||||
return ''
|
||||
}
|
||||
|
||||
function stringifyArray (value: Array<any>): string {
|
||||
let res = ''
|
||||
let stringified
|
||||
for (let i = 0, l = value.length; i < l; i++) {
|
||||
if (isDef(stringified = stringifyClass(value[i])) && stringified !== '') {
|
||||
if (res) res += ' '
|
||||
res += stringified
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
function stringifyObject (value: Object): string {
|
||||
let res = ''
|
||||
for (const key in value) {
|
||||
if (value[key]) {
|
||||
if (res) res += ' '
|
||||
res += key
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { inBrowser } from 'core/util/index'
|
||||
|
||||
// check whether current browser encodes a char inside attribute values
|
||||
let div
|
||||
function getShouldDecode (href: boolean): boolean {
|
||||
div = div || document.createElement('div')
|
||||
div.innerHTML = href ? `<a href="\n"/>` : `<div a="\n"/>`
|
||||
return div.innerHTML.indexOf(' ') > 0
|
||||
}
|
||||
|
||||
// #3663: IE encodes newlines inside attribute values while other browsers don't
|
||||
export const shouldDecodeNewlines = inBrowser ? getShouldDecode(false) : false
|
||||
// #6828: chrome encodes content in a[href]
|
||||
export const shouldDecodeNewlinesForHref = inBrowser ? getShouldDecode(true) : false
|
||||
-77
@@ -1,77 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { inBrowser } from 'core/util/env'
|
||||
import { makeMap } from 'shared/util'
|
||||
|
||||
export const namespaceMap = {
|
||||
svg: 'http://www.w3.org/2000/svg',
|
||||
math: 'http://www.w3.org/1998/Math/MathML'
|
||||
}
|
||||
|
||||
export const isHTMLTag = makeMap(
|
||||
'html,body,base,head,link,meta,style,title,' +
|
||||
'address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,' +
|
||||
'div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,' +
|
||||
'a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,' +
|
||||
's,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,' +
|
||||
'embed,object,param,source,canvas,script,noscript,del,ins,' +
|
||||
'caption,col,colgroup,table,thead,tbody,td,th,tr,' +
|
||||
'button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,' +
|
||||
'output,progress,select,textarea,' +
|
||||
'details,dialog,menu,menuitem,summary,' +
|
||||
'content,element,shadow,template,blockquote,iframe,tfoot'
|
||||
)
|
||||
|
||||
// this map is intentionally selective, only covering SVG elements that may
|
||||
// contain child elements.
|
||||
export const isSVG = makeMap(
|
||||
'svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face,' +
|
||||
'foreignObject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,' +
|
||||
'polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view',
|
||||
true
|
||||
)
|
||||
|
||||
export const isPreTag = (tag: ?string): boolean => tag === 'pre'
|
||||
|
||||
export const isReservedTag = (tag: string): ?boolean => {
|
||||
return isHTMLTag(tag) || isSVG(tag)
|
||||
}
|
||||
|
||||
export function getTagNamespace (tag: string): ?string {
|
||||
if (isSVG(tag)) {
|
||||
return 'svg'
|
||||
}
|
||||
// basic support for MathML
|
||||
// note it doesn't support other MathML elements being component roots
|
||||
if (tag === 'math') {
|
||||
return 'math'
|
||||
}
|
||||
}
|
||||
|
||||
const unknownElementCache = Object.create(null)
|
||||
export function isUnknownElement (tag: string): boolean {
|
||||
/* istanbul ignore if */
|
||||
if (!inBrowser) {
|
||||
return true
|
||||
}
|
||||
if (isReservedTag(tag)) {
|
||||
return false
|
||||
}
|
||||
tag = tag.toLowerCase()
|
||||
/* istanbul ignore if */
|
||||
if (unknownElementCache[tag] != null) {
|
||||
return unknownElementCache[tag]
|
||||
}
|
||||
const el = document.createElement(tag)
|
||||
if (tag.indexOf('-') > -1) {
|
||||
// http://stackoverflow.com/a/28210364/1070244
|
||||
return (unknownElementCache[tag] = (
|
||||
el.constructor === window.HTMLUnknownElement ||
|
||||
el.constructor === window.HTMLElement
|
||||
))
|
||||
} else {
|
||||
return (unknownElementCache[tag] = /HTMLUnknownElement/.test(el.toString()))
|
||||
}
|
||||
}
|
||||
|
||||
export const isTextInputType = makeMap('text,number,password,search,email,tel,url')
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { warn } from 'core/util/index'
|
||||
|
||||
export * from './attrs'
|
||||
export * from './class'
|
||||
export * from './element'
|
||||
|
||||
/**
|
||||
* Query an element selector if it's not an element already.
|
||||
*/
|
||||
export function query (el: string | Element): Element {
|
||||
if (typeof el === 'string') {
|
||||
const selected = document.querySelector(el)
|
||||
if (!selected) {
|
||||
process.env.NODE_ENV !== 'production' && warn(
|
||||
'Cannot find element: ' + el
|
||||
)
|
||||
return document.createElement('div')
|
||||
}
|
||||
return selected
|
||||
} else {
|
||||
return el
|
||||
}
|
||||
}
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
-5
@@ -1,5 +0,0 @@
|
||||
import model from './model'
|
||||
|
||||
export default {
|
||||
model
|
||||
}
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { genStaticKeys } from 'shared/util'
|
||||
import { createCompiler } from 'compiler/index'
|
||||
|
||||
import modules from './modules/index'
|
||||
import directives from './directives/index'
|
||||
|
||||
import {
|
||||
isUnaryTag,
|
||||
mustUseProp,
|
||||
isReservedTag,
|
||||
canBeLeftOpenTag,
|
||||
getTagNamespace
|
||||
} from '../util/element'
|
||||
|
||||
export const baseOptions: WeexCompilerOptions = {
|
||||
modules,
|
||||
directives,
|
||||
isUnaryTag,
|
||||
mustUseProp,
|
||||
canBeLeftOpenTag,
|
||||
isReservedTag,
|
||||
getTagNamespace,
|
||||
preserveWhitespace: false,
|
||||
recyclable: false,
|
||||
staticKeys: genStaticKeys(modules)
|
||||
}
|
||||
|
||||
const compiler = createCompiler(baseOptions)
|
||||
|
||||
export function compile (
|
||||
template: string,
|
||||
options?: WeexCompilerOptions
|
||||
): WeexCompiledResult {
|
||||
let generateAltRender = false
|
||||
if (options && options.recyclable === true) {
|
||||
generateAltRender = true
|
||||
options.recyclable = false
|
||||
}
|
||||
const result = compiler.compile(template, options)
|
||||
|
||||
// generate @render function for <recycle-list>
|
||||
if (options && generateAltRender) {
|
||||
options.recyclable = true
|
||||
// disable static optimizations
|
||||
options.optimize = false
|
||||
const { render } = compiler.compile(template, options)
|
||||
result['@render'] = render
|
||||
}
|
||||
return result
|
||||
}
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
import klass from './class'
|
||||
import style from './style'
|
||||
import props from './props'
|
||||
import append from './append'
|
||||
import recycleList from './recycle-list/index'
|
||||
|
||||
export default [
|
||||
recycleList,
|
||||
klass,
|
||||
style,
|
||||
props,
|
||||
append
|
||||
]
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { addAttr } from 'compiler/helpers'
|
||||
import { RECYCLE_LIST_MARKER } from 'weex/util/index'
|
||||
|
||||
// mark components as inside recycle-list so that we know we need to invoke
|
||||
// their special @render function instead of render in create-component.js
|
||||
export function postTransformComponent (
|
||||
el: ASTElement,
|
||||
options: WeexCompilerOptions
|
||||
) {
|
||||
// $flow-disable-line (we know isReservedTag is there)
|
||||
if (!options.isReservedTag(el.tag) && el.tag !== 'cell-slot') {
|
||||
addAttr(el, RECYCLE_LIST_MARKER, 'true')
|
||||
}
|
||||
}
|
||||
Generated
Vendored
-50
@@ -1,50 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { parseFor } from 'compiler/parser/index'
|
||||
import { getAndRemoveAttr, addRawAttr } from 'compiler/helpers'
|
||||
|
||||
/**
|
||||
* Map the following syntax to corresponding attrs:
|
||||
*
|
||||
* <recycle-list for="(item, i) in longList" switch="cellType">
|
||||
* <cell-slot case="A"> ... </cell-slot>
|
||||
* <cell-slot case="B"> ... </cell-slot>
|
||||
* </recycle-list>
|
||||
*/
|
||||
|
||||
export function preTransformRecycleList (
|
||||
el: ASTElement,
|
||||
options: WeexCompilerOptions
|
||||
) {
|
||||
const exp = getAndRemoveAttr(el, 'for')
|
||||
if (!exp) {
|
||||
if (options.warn) {
|
||||
options.warn(`Invalid <recycle-list> syntax: missing "for" expression.`)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const res = parseFor(exp)
|
||||
if (!res) {
|
||||
if (options.warn) {
|
||||
options.warn(`Invalid <recycle-list> syntax: ${exp}.`)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
addRawAttr(el, ':list-data', res.for)
|
||||
addRawAttr(el, 'binding-expression', res.for)
|
||||
addRawAttr(el, 'alias', res.alias)
|
||||
if (res.iterator2) {
|
||||
// (item, key, index) for object iteration
|
||||
// is this even supported?
|
||||
addRawAttr(el, 'index', res.iterator2)
|
||||
} else if (res.iterator1) {
|
||||
addRawAttr(el, 'index', res.iterator1)
|
||||
}
|
||||
|
||||
const switchKey = getAndRemoveAttr(el, 'switch')
|
||||
if (switchKey) {
|
||||
addRawAttr(el, 'switch', switchKey)
|
||||
}
|
||||
}
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { parseFor } from 'compiler/parser/index'
|
||||
import { getAndRemoveAttr, addRawAttr } from 'compiler/helpers'
|
||||
|
||||
export function preTransformVFor (el: ASTElement, options: WeexCompilerOptions) {
|
||||
const exp = getAndRemoveAttr(el, 'v-for')
|
||||
if (!exp) {
|
||||
return
|
||||
}
|
||||
|
||||
const res = parseFor(exp)
|
||||
if (!res) {
|
||||
if (process.env.NODE_ENV !== 'production' && options.warn) {
|
||||
options.warn(`Invalid v-for expression: ${exp}`)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const desc: Object = {
|
||||
'@expression': res.for,
|
||||
'@alias': res.alias
|
||||
}
|
||||
if (res.iterator2) {
|
||||
desc['@key'] = res.iterator1
|
||||
desc['@index'] = res.iterator2
|
||||
} else {
|
||||
desc['@index'] = res.iterator1
|
||||
}
|
||||
|
||||
delete el.attrsMap['v-for']
|
||||
addRawAttr(el, '[[repeat]]', desc)
|
||||
}
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { addIfCondition } from 'compiler/parser/index'
|
||||
import { getAndRemoveAttr, addRawAttr } from 'compiler/helpers'
|
||||
|
||||
function hasConditionDirective (el: ASTElement): boolean {
|
||||
for (const attr in el.attrsMap) {
|
||||
if (/^v\-if|v\-else|v\-else\-if$/.test(attr)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function getPreviousConditions (el: ASTElement): Array<string> {
|
||||
const conditions = []
|
||||
if (el.parent && el.parent.children) {
|
||||
for (let c = 0, n = el.parent.children.length; c < n; ++c) {
|
||||
// $flow-disable-line
|
||||
const ifConditions = el.parent.children[c].ifConditions
|
||||
if (ifConditions) {
|
||||
for (let i = 0, l = ifConditions.length; i < l; ++i) {
|
||||
const condition = ifConditions[i]
|
||||
if (condition && condition.exp) {
|
||||
conditions.push(condition.exp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return conditions
|
||||
}
|
||||
|
||||
export function preTransformVIf (el: ASTElement, options: WeexCompilerOptions) {
|
||||
if (hasConditionDirective(el)) {
|
||||
let exp
|
||||
const ifExp = getAndRemoveAttr(el, 'v-if', true /* remove from attrsMap */)
|
||||
const elseifExp = getAndRemoveAttr(el, 'v-else-if', true)
|
||||
// don't need the value, but remove it to avoid being generated as a
|
||||
// custom directive
|
||||
getAndRemoveAttr(el, 'v-else', true)
|
||||
if (ifExp) {
|
||||
exp = ifExp
|
||||
addIfCondition(el, { exp: ifExp, block: el })
|
||||
} else {
|
||||
elseifExp && addIfCondition(el, { exp: elseifExp, block: el })
|
||||
const prevConditions = getPreviousConditions(el)
|
||||
if (prevConditions.length) {
|
||||
const prevMatch = prevConditions.join(' || ')
|
||||
exp = elseifExp
|
||||
? `!(${prevMatch}) && (${elseifExp})` // v-else-if
|
||||
: `!(${prevMatch})` // v-else
|
||||
} else if (process.env.NODE_ENV !== 'production' && options.warn) {
|
||||
options.warn(
|
||||
`v-${elseifExp ? ('else-if="' + elseifExp + '"') : 'else'} ` +
|
||||
`used on element <${el.tag}> without corresponding v-if.`
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
addRawAttr(el, '[[match]]', exp)
|
||||
}
|
||||
}
|
||||
-187
@@ -1,187 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
// this will be preserved during build
|
||||
// $flow-disable-line
|
||||
const VueFactory = require('./factory')
|
||||
|
||||
const instanceOptions: { [key: string]: WeexInstanceOption } = {}
|
||||
|
||||
/**
|
||||
* Create instance context.
|
||||
*/
|
||||
export function createInstanceContext (
|
||||
instanceId: string,
|
||||
runtimeContext: WeexRuntimeContext,
|
||||
data: Object = {}
|
||||
): WeexInstanceContext {
|
||||
const weex: Weex = runtimeContext.weex
|
||||
const instance: WeexInstanceOption = instanceOptions[instanceId] = {
|
||||
instanceId,
|
||||
config: weex.config,
|
||||
document: weex.document,
|
||||
data
|
||||
}
|
||||
|
||||
// Each instance has a independent `Vue` module instance
|
||||
const Vue = instance.Vue = createVueModuleInstance(instanceId, weex)
|
||||
|
||||
// DEPRECATED
|
||||
const timerAPIs = getInstanceTimer(instanceId, weex.requireModule)
|
||||
|
||||
const instanceContext = Object.assign({ Vue }, timerAPIs)
|
||||
Object.freeze(instanceContext)
|
||||
return instanceContext
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy an instance with id. It will make sure all memory of
|
||||
* this instance released and no more leaks.
|
||||
*/
|
||||
export function destroyInstance (instanceId: string): void {
|
||||
const instance = instanceOptions[instanceId]
|
||||
if (instance && instance.app instanceof instance.Vue) {
|
||||
try {
|
||||
instance.app.$destroy()
|
||||
instance.document.destroy()
|
||||
} catch (e) {}
|
||||
delete instance.document
|
||||
delete instance.app
|
||||
}
|
||||
delete instanceOptions[instanceId]
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh an instance with id and new top-level component data.
|
||||
* It will use `Vue.set` on all keys of the new data. So it's better
|
||||
* define all possible meaningful keys when instance created.
|
||||
*/
|
||||
export function refreshInstance (
|
||||
instanceId: string,
|
||||
data: Object
|
||||
): Error | void {
|
||||
const instance = instanceOptions[instanceId]
|
||||
if (!instance || !(instance.app instanceof instance.Vue)) {
|
||||
return new Error(`refreshInstance: instance ${instanceId} not found!`)
|
||||
}
|
||||
if (instance.Vue && instance.Vue.set) {
|
||||
for (const key in data) {
|
||||
instance.Vue.set(instance.app, key, data[key])
|
||||
}
|
||||
}
|
||||
// Finally `refreshFinish` signal needed.
|
||||
instance.document.taskCenter.send('dom', { action: 'refreshFinish' }, [])
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a fresh instance of Vue for each Weex instance.
|
||||
*/
|
||||
function createVueModuleInstance (
|
||||
instanceId: string,
|
||||
weex: Weex
|
||||
): GlobalAPI {
|
||||
const exports = {}
|
||||
VueFactory(exports, weex.document)
|
||||
const Vue = exports.Vue
|
||||
|
||||
const instance = instanceOptions[instanceId]
|
||||
|
||||
// patch reserved tag detection to account for dynamically registered
|
||||
// components
|
||||
const weexRegex = /^weex:/i
|
||||
const isReservedTag = Vue.config.isReservedTag || (() => false)
|
||||
const isRuntimeComponent = Vue.config.isRuntimeComponent || (() => false)
|
||||
Vue.config.isReservedTag = name => {
|
||||
return (!isRuntimeComponent(name) && weex.supports(`@component/${name}`)) ||
|
||||
isReservedTag(name) ||
|
||||
weexRegex.test(name)
|
||||
}
|
||||
Vue.config.parsePlatformTagName = name => name.replace(weexRegex, '')
|
||||
|
||||
// expose weex-specific info
|
||||
Vue.prototype.$instanceId = instanceId
|
||||
Vue.prototype.$document = instance.document
|
||||
|
||||
// expose weex native module getter on subVue prototype so that
|
||||
// vdom runtime modules can access native modules via vnode.context
|
||||
Vue.prototype.$requireWeexModule = weex.requireModule
|
||||
|
||||
// Hack `Vue` behavior to handle instance information and data
|
||||
// before root component created.
|
||||
Vue.mixin({
|
||||
beforeCreate () {
|
||||
const options = this.$options
|
||||
// root component (vm)
|
||||
if (options.el) {
|
||||
// set external data of instance
|
||||
const dataOption = options.data
|
||||
const internalData = (typeof dataOption === 'function' ? dataOption() : dataOption) || {}
|
||||
options.data = Object.assign(internalData, instance.data)
|
||||
// record instance by id
|
||||
instance.app = this
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const options = this.$options
|
||||
// root component (vm)
|
||||
if (options.el && weex.document && instance.app === this) {
|
||||
try {
|
||||
// Send "createFinish" signal to native.
|
||||
weex.document.taskCenter.send('dom', { action: 'createFinish' }, [])
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* @deprecated Just instance variable `weex.config`
|
||||
* Get instance config.
|
||||
* @return {object}
|
||||
*/
|
||||
Vue.prototype.$getConfig = function () {
|
||||
if (instance.app instanceof Vue) {
|
||||
return instance.config
|
||||
}
|
||||
}
|
||||
|
||||
return Vue
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED
|
||||
* Generate HTML5 Timer APIs. An important point is that the callback
|
||||
* will be converted into callback id when sent to native. So the
|
||||
* framework can make sure no side effect of the callback happened after
|
||||
* an instance destroyed.
|
||||
*/
|
||||
function getInstanceTimer (
|
||||
instanceId: string,
|
||||
moduleGetter: Function
|
||||
): Object {
|
||||
const instance = instanceOptions[instanceId]
|
||||
const timer = moduleGetter('timer')
|
||||
const timerAPIs = {
|
||||
setTimeout: (...args) => {
|
||||
const handler = function () {
|
||||
args[0](...args.slice(2))
|
||||
}
|
||||
|
||||
timer.setTimeout(handler, args[1])
|
||||
return instance.document.taskCenter.callbackManager.lastCallbackId.toString()
|
||||
},
|
||||
setInterval: (...args) => {
|
||||
const handler = function () {
|
||||
args[0](...args.slice(2))
|
||||
}
|
||||
|
||||
timer.setInterval(handler, args[1])
|
||||
return instance.document.taskCenter.callbackManager.lastCallbackId.toString()
|
||||
},
|
||||
clearTimeout: (n) => {
|
||||
timer.clearTimeout(n)
|
||||
},
|
||||
clearInterval: (n) => {
|
||||
timer.clearInterval(n)
|
||||
}
|
||||
}
|
||||
return timerAPIs
|
||||
}
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
// this entry is built and wrapped with a factory function
|
||||
// used to generate a fresh copy of Vue for every Weex instance.
|
||||
|
||||
import Vue from './runtime/index'
|
||||
|
||||
exports.Vue = Vue
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
import Richtext from './richtext'
|
||||
import Transition from './transition'
|
||||
import TransitionGroup from './transition-group'
|
||||
|
||||
export default {
|
||||
Richtext,
|
||||
Transition,
|
||||
TransitionGroup
|
||||
}
|
||||
-82
@@ -1,82 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
function getVNodeType (vnode: VNode): string {
|
||||
if (!vnode.tag) {
|
||||
return ''
|
||||
}
|
||||
return vnode.tag.replace(/vue\-component\-(\d+\-)?/, '')
|
||||
}
|
||||
|
||||
function isSimpleSpan (vnode: VNode): boolean {
|
||||
return vnode.children &&
|
||||
vnode.children.length === 1 &&
|
||||
!vnode.children[0].tag
|
||||
}
|
||||
|
||||
function parseStyle (vnode: VNode): Object | void {
|
||||
if (!vnode || !vnode.data) {
|
||||
return
|
||||
}
|
||||
const { staticStyle, staticClass } = vnode.data
|
||||
if (vnode.data.style || vnode.data.class || staticStyle || staticClass) {
|
||||
const styles = Object.assign({}, staticStyle, vnode.data.style)
|
||||
const cssMap = vnode.context.$options.style || {}
|
||||
const classList = [].concat(staticClass, vnode.data.class)
|
||||
classList.forEach(name => {
|
||||
if (name && cssMap[name]) {
|
||||
Object.assign(styles, cssMap[name])
|
||||
}
|
||||
})
|
||||
return styles
|
||||
}
|
||||
}
|
||||
|
||||
function convertVNodeChildren (children: Array<VNode>): Array<VNode> | void {
|
||||
if (!children.length) {
|
||||
return
|
||||
}
|
||||
|
||||
return children.map(vnode => {
|
||||
const type: string = getVNodeType(vnode)
|
||||
const props: Object = { type }
|
||||
|
||||
// convert raw text node
|
||||
if (!type) {
|
||||
props.type = 'span'
|
||||
props.attr = {
|
||||
value: (vnode.text || '').trim()
|
||||
}
|
||||
} else {
|
||||
props.style = parseStyle(vnode)
|
||||
if (vnode.data) {
|
||||
props.attr = vnode.data.attrs
|
||||
if (vnode.data.on) {
|
||||
props.events = vnode.data.on
|
||||
}
|
||||
}
|
||||
if (type === 'span' && isSimpleSpan(vnode)) {
|
||||
props.attr = props.attr || {}
|
||||
props.attr.value = vnode.children[0].text.trim()
|
||||
return props
|
||||
}
|
||||
}
|
||||
|
||||
if (vnode.children && vnode.children.length) {
|
||||
props.children = convertVNodeChildren(vnode.children)
|
||||
}
|
||||
|
||||
return props
|
||||
})
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'richtext',
|
||||
render (h: Function) {
|
||||
return h('weex:richtext', {
|
||||
on: this._events,
|
||||
attrs: {
|
||||
value: convertVNodeChildren(this.$options._renderChildren || [])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
-148
@@ -1,148 +0,0 @@
|
||||
import { warn, extend } from 'core/util/index'
|
||||
import { transitionProps, extractTransitionData } from './transition'
|
||||
|
||||
const props = extend({
|
||||
tag: String,
|
||||
moveClass: String
|
||||
}, transitionProps)
|
||||
|
||||
delete props.mode
|
||||
|
||||
export default {
|
||||
props,
|
||||
|
||||
created () {
|
||||
const dom = this.$requireWeexModule('dom')
|
||||
this.getPosition = el => new Promise((resolve, reject) => {
|
||||
dom.getComponentRect(el.ref, res => {
|
||||
if (!res.result) {
|
||||
reject(new Error(`failed to get rect for element: ${el.tag}`))
|
||||
} else {
|
||||
resolve(res.size)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const animation = this.$requireWeexModule('animation')
|
||||
this.animate = (el, options) => new Promise(resolve => {
|
||||
animation.transition(el.ref, options, resolve)
|
||||
})
|
||||
},
|
||||
|
||||
render (h) {
|
||||
const tag = this.tag || this.$vnode.data.tag || 'span'
|
||||
const map = Object.create(null)
|
||||
const prevChildren = this.prevChildren = this.children
|
||||
const rawChildren = this.$slots.default || []
|
||||
const children = this.children = []
|
||||
const transitionData = extractTransitionData(this)
|
||||
|
||||
for (let i = 0; i < rawChildren.length; i++) {
|
||||
const c = rawChildren[i]
|
||||
if (c.tag) {
|
||||
if (c.key != null && String(c.key).indexOf('__vlist') !== 0) {
|
||||
children.push(c)
|
||||
map[c.key] = c
|
||||
;(c.data || (c.data = {})).transition = transitionData
|
||||
} else if (process.env.NODE_ENV !== 'production') {
|
||||
const opts = c.componentOptions
|
||||
const name = opts
|
||||
? (opts.Ctor.options.name || opts.tag)
|
||||
: c.tag
|
||||
warn(`<transition-group> children must be keyed: <${name}>`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (prevChildren) {
|
||||
const kept = []
|
||||
const removed = []
|
||||
prevChildren.forEach(c => {
|
||||
c.data.transition = transitionData
|
||||
|
||||
// TODO: record before patch positions
|
||||
|
||||
if (map[c.key]) {
|
||||
kept.push(c)
|
||||
} else {
|
||||
removed.push(c)
|
||||
}
|
||||
})
|
||||
this.kept = h(tag, null, kept)
|
||||
this.removed = removed
|
||||
}
|
||||
|
||||
return h(tag, null, children)
|
||||
},
|
||||
|
||||
beforeUpdate () {
|
||||
// force removing pass
|
||||
this.__patch__(
|
||||
this._vnode,
|
||||
this.kept,
|
||||
false, // hydrating
|
||||
true // removeOnly (!important, avoids unnecessary moves)
|
||||
)
|
||||
this._vnode = this.kept
|
||||
},
|
||||
|
||||
updated () {
|
||||
const children = this.prevChildren
|
||||
const moveClass = this.moveClass || ((this.name || 'v') + '-move')
|
||||
const moveData = children.length && this.getMoveData(children[0].context, moveClass)
|
||||
if (!moveData) {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: finish implementing move animations once
|
||||
// we have access to sync getComponentRect()
|
||||
|
||||
// children.forEach(callPendingCbs)
|
||||
|
||||
// Promise.all(children.map(c => {
|
||||
// const oldPos = c.data.pos
|
||||
// const newPos = c.data.newPos
|
||||
// const dx = oldPos.left - newPos.left
|
||||
// const dy = oldPos.top - newPos.top
|
||||
// if (dx || dy) {
|
||||
// c.data.moved = true
|
||||
// return this.animate(c.elm, {
|
||||
// styles: {
|
||||
// transform: `translate(${dx}px,${dy}px)`
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
// })).then(() => {
|
||||
// children.forEach(c => {
|
||||
// if (c.data.moved) {
|
||||
// this.animate(c.elm, {
|
||||
// styles: {
|
||||
// transform: ''
|
||||
// },
|
||||
// duration: moveData.duration || 0,
|
||||
// delay: moveData.delay || 0,
|
||||
// timingFunction: moveData.timingFunction || 'linear'
|
||||
// })
|
||||
// }
|
||||
// })
|
||||
// })
|
||||
},
|
||||
|
||||
methods: {
|
||||
getMoveData (context, moveClass) {
|
||||
const stylesheet = context.$options.style || {}
|
||||
return stylesheet['@TRANSITION'] && stylesheet['@TRANSITION'][moveClass]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// function callPendingCbs (c) {
|
||||
// /* istanbul ignore if */
|
||||
// if (c.elm._moveCb) {
|
||||
// c.elm._moveCb()
|
||||
// }
|
||||
// /* istanbul ignore if */
|
||||
// if (c.elm._enterCb) {
|
||||
// c.elm._enterCb()
|
||||
// }
|
||||
// }
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
// reuse same transition component logic from web
|
||||
export {
|
||||
transitionProps,
|
||||
extractTransitionData
|
||||
} from 'web/runtime/components/transition'
|
||||
|
||||
import Transition from 'web/runtime/components/transition'
|
||||
|
||||
export default Transition
|
||||
-2
@@ -1,2 +0,0 @@
|
||||
export default {
|
||||
}
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import Vue from 'core/index'
|
||||
import { patch } from 'weex/runtime/patch'
|
||||
import { mountComponent } from 'core/instance/lifecycle'
|
||||
import platformDirectives from 'weex/runtime/directives/index'
|
||||
import platformComponents from 'weex/runtime/components/index'
|
||||
|
||||
import {
|
||||
query,
|
||||
mustUseProp,
|
||||
isReservedTag,
|
||||
isRuntimeComponent,
|
||||
isUnknownElement
|
||||
} from 'weex/util/element'
|
||||
|
||||
// install platform specific utils
|
||||
Vue.config.mustUseProp = mustUseProp
|
||||
Vue.config.isReservedTag = isReservedTag
|
||||
Vue.config.isRuntimeComponent = isRuntimeComponent
|
||||
Vue.config.isUnknownElement = isUnknownElement
|
||||
|
||||
// install platform runtime directives and components
|
||||
Vue.options.directives = platformDirectives
|
||||
Vue.options.components = platformComponents
|
||||
|
||||
// install platform patch function
|
||||
Vue.prototype.__patch__ = patch
|
||||
|
||||
// wrap mount
|
||||
Vue.prototype.$mount = function (
|
||||
el?: any,
|
||||
hydrating?: boolean
|
||||
): Component {
|
||||
return mountComponent(
|
||||
this,
|
||||
el && query(el, this.$document),
|
||||
hydrating
|
||||
)
|
||||
}
|
||||
|
||||
export default Vue
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { extend } from 'shared/util'
|
||||
|
||||
function updateAttrs (oldVnode: VNodeWithData, vnode: VNodeWithData) {
|
||||
if (!oldVnode.data.attrs && !vnode.data.attrs) {
|
||||
return
|
||||
}
|
||||
let key, cur, old
|
||||
const elm = vnode.elm
|
||||
const oldAttrs = oldVnode.data.attrs || {}
|
||||
let attrs = vnode.data.attrs || {}
|
||||
// clone observed objects, as the user probably wants to mutate it
|
||||
if (attrs.__ob__) {
|
||||
attrs = vnode.data.attrs = extend({}, attrs)
|
||||
}
|
||||
|
||||
const supportBatchUpdate = typeof elm.setAttrs === 'function'
|
||||
const batchedAttrs = {}
|
||||
for (key in attrs) {
|
||||
cur = attrs[key]
|
||||
old = oldAttrs[key]
|
||||
if (old !== cur) {
|
||||
supportBatchUpdate
|
||||
? (batchedAttrs[key] = cur)
|
||||
: elm.setAttr(key, cur)
|
||||
}
|
||||
}
|
||||
for (key in oldAttrs) {
|
||||
if (attrs[key] == null) {
|
||||
supportBatchUpdate
|
||||
? (batchedAttrs[key] = undefined)
|
||||
: elm.setAttr(key)
|
||||
}
|
||||
}
|
||||
if (supportBatchUpdate) {
|
||||
elm.setAttrs(batchedAttrs)
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
create: updateAttrs,
|
||||
update: updateAttrs
|
||||
}
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
import attrs from './attrs'
|
||||
import klass from './class'
|
||||
import events from './events'
|
||||
import style from './style'
|
||||
import transition from './transition'
|
||||
|
||||
export default [
|
||||
attrs,
|
||||
klass,
|
||||
events,
|
||||
style,
|
||||
transition
|
||||
]
|
||||
-91
@@ -1,91 +0,0 @@
|
||||
/* @flow */
|
||||
declare var document: WeexDocument;
|
||||
|
||||
import TextNode from 'weex/runtime/text-node'
|
||||
|
||||
export const namespaceMap = {}
|
||||
|
||||
export function createElement (tagName: string): WeexElement {
|
||||
return document.createElement(tagName)
|
||||
}
|
||||
|
||||
export function createElementNS (namespace: string, tagName: string): WeexElement {
|
||||
return document.createElement(namespace + ':' + tagName)
|
||||
}
|
||||
|
||||
export function createTextNode (text: string) {
|
||||
return new TextNode(text)
|
||||
}
|
||||
|
||||
export function createComment (text: string) {
|
||||
return document.createComment(text)
|
||||
}
|
||||
|
||||
export function insertBefore (
|
||||
node: WeexElement,
|
||||
target: WeexElement,
|
||||
before: WeexElement
|
||||
) {
|
||||
if (target.nodeType === 3) {
|
||||
if (node.type === 'text') {
|
||||
node.setAttr('value', target.text)
|
||||
target.parentNode = node
|
||||
} else {
|
||||
const text = createElement('text')
|
||||
text.setAttr('value', target.text)
|
||||
node.insertBefore(text, before)
|
||||
}
|
||||
return
|
||||
}
|
||||
node.insertBefore(target, before)
|
||||
}
|
||||
|
||||
export function removeChild (node: WeexElement, child: WeexElement) {
|
||||
if (child.nodeType === 3) {
|
||||
node.setAttr('value', '')
|
||||
return
|
||||
}
|
||||
node.removeChild(child)
|
||||
}
|
||||
|
||||
export function appendChild (node: WeexElement, child: WeexElement) {
|
||||
if (child.nodeType === 3) {
|
||||
if (node.type === 'text') {
|
||||
node.setAttr('value', child.text)
|
||||
child.parentNode = node
|
||||
} else {
|
||||
const text = createElement('text')
|
||||
text.setAttr('value', child.text)
|
||||
node.appendChild(text)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
node.appendChild(child)
|
||||
}
|
||||
|
||||
export function parentNode (node: WeexElement): WeexElement | void {
|
||||
return node.parentNode
|
||||
}
|
||||
|
||||
export function nextSibling (node: WeexElement): WeexElement | void {
|
||||
return node.nextSibling
|
||||
}
|
||||
|
||||
export function tagName (node: WeexElement): string {
|
||||
return node.type
|
||||
}
|
||||
|
||||
export function setTextContent (node: WeexElement, text: string) {
|
||||
if (node.parentNode) {
|
||||
node.parentNode.setAttr('value', text)
|
||||
}
|
||||
}
|
||||
|
||||
export function setAttribute (node: WeexElement, key: string, val: any) {
|
||||
node.setAttr(key, val)
|
||||
}
|
||||
|
||||
export function setStyleScope (node: WeexElement, scopeId: string) {
|
||||
node.setAttr('@styleScope', scopeId)
|
||||
}
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import * as nodeOps from 'weex/runtime/node-ops'
|
||||
import { createPatchFunction } from 'core/vdom/patch'
|
||||
import baseModules from 'core/vdom/modules/index'
|
||||
import platformModules from 'weex/runtime/modules/index'
|
||||
|
||||
// the directive module should be applied last, after all
|
||||
// built-in modules have been applied.
|
||||
const modules = platformModules.concat(baseModules)
|
||||
|
||||
export const patch: Function = createPatchFunction({
|
||||
nodeOps,
|
||||
modules,
|
||||
LONG_LIST_THRESHOLD: 10
|
||||
})
|
||||
Generated
Vendored
-34
@@ -1,34 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { warn } from 'core/util/debug'
|
||||
import { handleError } from 'core/util/error'
|
||||
import { RECYCLE_LIST_MARKER } from 'weex/util/index'
|
||||
import { createComponentInstanceForVnode } from 'core/vdom/create-component'
|
||||
import { resolveVirtualComponent } from './virtual-component'
|
||||
|
||||
export function isRecyclableComponent (vnode: VNodeWithData): boolean {
|
||||
return vnode.data.attrs
|
||||
? (RECYCLE_LIST_MARKER in vnode.data.attrs)
|
||||
: false
|
||||
}
|
||||
|
||||
export function renderRecyclableComponentTemplate (vnode: MountedComponentVNode): VNode {
|
||||
// $flow-disable-line
|
||||
delete vnode.data.attrs[RECYCLE_LIST_MARKER]
|
||||
resolveVirtualComponent(vnode)
|
||||
const vm = createComponentInstanceForVnode(vnode)
|
||||
const render = (vm.$options: any)['@render']
|
||||
if (render) {
|
||||
try {
|
||||
return render.call(vm)
|
||||
} catch (err) {
|
||||
handleError(err, vm, `@render`)
|
||||
}
|
||||
} else {
|
||||
warn(
|
||||
`@render function not defined on component used in <recycle-list>. ` +
|
||||
`Make sure to declare \`recyclable="true"\` on the component's template.`,
|
||||
vm
|
||||
)
|
||||
}
|
||||
}
|
||||
-136
@@ -1,136 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
// https://github.com/Hanks10100/weex-native-directive/tree/master/component
|
||||
|
||||
import { mergeOptions, isPlainObject, noop } from 'core/util/index'
|
||||
import Watcher from 'core/observer/watcher'
|
||||
import { initProxy } from 'core/instance/proxy'
|
||||
import { initState, getData } from 'core/instance/state'
|
||||
import { initRender } from 'core/instance/render'
|
||||
import { initEvents } from 'core/instance/events'
|
||||
import { initProvide, initInjections } from 'core/instance/inject'
|
||||
import { initLifecycle, callHook } from 'core/instance/lifecycle'
|
||||
import { initInternalComponent, resolveConstructorOptions } from 'core/instance/init'
|
||||
import { registerComponentHook, updateComponentData } from '../../util/index'
|
||||
|
||||
let uid = 0
|
||||
|
||||
// override Vue.prototype._init
|
||||
function initVirtualComponent (options: Object = {}) {
|
||||
const vm: Component = this
|
||||
const componentId = options.componentId
|
||||
|
||||
// virtual component uid
|
||||
vm._uid = `virtual-component-${uid++}`
|
||||
|
||||
// a flag to avoid this being observed
|
||||
vm._isVue = true
|
||||
// merge options
|
||||
if (options && options._isComponent) {
|
||||
// optimize internal component instantiation
|
||||
// since dynamic options merging is pretty slow, and none of the
|
||||
// internal component options needs special treatment.
|
||||
initInternalComponent(vm, options)
|
||||
} else {
|
||||
vm.$options = mergeOptions(
|
||||
resolveConstructorOptions(vm.constructor),
|
||||
options || {},
|
||||
vm
|
||||
)
|
||||
}
|
||||
|
||||
/* istanbul ignore else */
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
initProxy(vm)
|
||||
} else {
|
||||
vm._renderProxy = vm
|
||||
}
|
||||
|
||||
vm._self = vm
|
||||
initLifecycle(vm)
|
||||
initEvents(vm)
|
||||
initRender(vm)
|
||||
callHook(vm, 'beforeCreate')
|
||||
initInjections(vm) // resolve injections before data/props
|
||||
initState(vm)
|
||||
initProvide(vm) // resolve provide after data/props
|
||||
callHook(vm, 'created')
|
||||
|
||||
// send initial data to native
|
||||
const data = vm.$options.data
|
||||
const params = typeof data === 'function'
|
||||
? getData(data, vm)
|
||||
: data || {}
|
||||
if (isPlainObject(params)) {
|
||||
updateComponentData(componentId, params)
|
||||
}
|
||||
|
||||
registerComponentHook(componentId, 'lifecycle', 'attach', () => {
|
||||
callHook(vm, 'beforeMount')
|
||||
|
||||
const updateComponent = () => {
|
||||
vm._update(vm._vnode, false)
|
||||
}
|
||||
new Watcher(vm, updateComponent, noop, null, true)
|
||||
|
||||
vm._isMounted = true
|
||||
callHook(vm, 'mounted')
|
||||
})
|
||||
|
||||
registerComponentHook(componentId, 'lifecycle', 'detach', () => {
|
||||
vm.$destroy()
|
||||
})
|
||||
}
|
||||
|
||||
// override Vue.prototype._update
|
||||
function updateVirtualComponent (vnode?: VNode) {
|
||||
const vm: Component = this
|
||||
const componentId = vm.$options.componentId
|
||||
if (vm._isMounted) {
|
||||
callHook(vm, 'beforeUpdate')
|
||||
}
|
||||
vm._vnode = vnode
|
||||
if (vm._isMounted && componentId) {
|
||||
// TODO: data should be filtered and without bindings
|
||||
const data = Object.assign({}, vm._data)
|
||||
updateComponentData(componentId, data, () => {
|
||||
callHook(vm, 'updated')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// listening on native callback
|
||||
export function resolveVirtualComponent (vnode: MountedComponentVNode): VNode {
|
||||
const BaseCtor = vnode.componentOptions.Ctor
|
||||
const VirtualComponent = BaseCtor.extend({})
|
||||
const cid = VirtualComponent.cid
|
||||
VirtualComponent.prototype._init = initVirtualComponent
|
||||
VirtualComponent.prototype._update = updateVirtualComponent
|
||||
|
||||
vnode.componentOptions.Ctor = BaseCtor.extend({
|
||||
beforeCreate () {
|
||||
// const vm: Component = this
|
||||
|
||||
// TODO: listen on all events and dispatch them to the
|
||||
// corresponding virtual components according to the componentId.
|
||||
// vm._virtualComponents = {}
|
||||
const createVirtualComponent = (componentId, propsData) => {
|
||||
// create virtual component
|
||||
// const subVm =
|
||||
new VirtualComponent({
|
||||
componentId,
|
||||
propsData
|
||||
})
|
||||
// if (vm._virtualComponents) {
|
||||
// vm._virtualComponents[componentId] = subVm
|
||||
// }
|
||||
}
|
||||
|
||||
registerComponentHook(cid, 'lifecycle', 'create', createVirtualComponent)
|
||||
},
|
||||
beforeDestroy () {
|
||||
delete this._virtualComponents
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
let latestNodeId = 1
|
||||
|
||||
export default function TextNode (text) {
|
||||
this.instanceId = ''
|
||||
this.nodeId = latestNodeId++
|
||||
this.parentNode = null
|
||||
this.nodeType = 3
|
||||
this.text = text
|
||||
}
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
/* @flow */
|
||||
declare var document: WeexDocument;
|
||||
|
||||
import { warn } from 'core/util/index'
|
||||
|
||||
export const RECYCLE_LIST_MARKER = '@inRecycleList'
|
||||
|
||||
// Register the component hook to weex native render engine.
|
||||
// The hook will be triggered by native, not javascript.
|
||||
export function registerComponentHook (
|
||||
componentId: string,
|
||||
type: string, // hook type, could be "lifecycle" or "instance"
|
||||
hook: string, // hook name
|
||||
fn: Function
|
||||
) {
|
||||
if (!document || !document.taskCenter) {
|
||||
warn(`Can't find available "document" or "taskCenter".`)
|
||||
return
|
||||
}
|
||||
if (typeof document.taskCenter.registerHook === 'function') {
|
||||
return document.taskCenter.registerHook(componentId, type, hook, fn)
|
||||
}
|
||||
warn(`Failed to register component hook "${type}@${hook}#${componentId}".`)
|
||||
}
|
||||
|
||||
// Updates the state of the component to weex native render engine.
|
||||
export function updateComponentData (
|
||||
componentId: string,
|
||||
newData: Object | void,
|
||||
callback?: Function
|
||||
) {
|
||||
if (!document || !document.taskCenter) {
|
||||
warn(`Can't find available "document" or "taskCenter".`)
|
||||
return
|
||||
}
|
||||
if (typeof document.taskCenter.updateData === 'function') {
|
||||
return document.taskCenter.updateData(componentId, newData, callback)
|
||||
}
|
||||
warn(`Failed to update component data (${componentId}).`)
|
||||
}
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
// import { warn } from 'core/util/index'
|
||||
|
||||
// this will be preserved during build
|
||||
// $flow-disable-line
|
||||
const acorn = require('acorn') // $flow-disable-line
|
||||
const walk = require('acorn/dist/walk') // $flow-disable-line
|
||||
const escodegen = require('escodegen')
|
||||
|
||||
export function nodeToBinding (node: Object): any {
|
||||
switch (node.type) {
|
||||
case 'Literal': return node.value
|
||||
case 'Identifier':
|
||||
case 'UnaryExpression':
|
||||
case 'BinaryExpression':
|
||||
case 'LogicalExpression':
|
||||
case 'ConditionalExpression':
|
||||
case 'MemberExpression': return { '@binding': escodegen.generate(node) }
|
||||
case 'ArrayExpression': return node.elements.map(_ => nodeToBinding(_))
|
||||
case 'ObjectExpression': {
|
||||
const object = {}
|
||||
node.properties.forEach(prop => {
|
||||
if (!prop.key || prop.key.type !== 'Identifier') {
|
||||
return
|
||||
}
|
||||
const key = escodegen.generate(prop.key)
|
||||
const value = nodeToBinding(prop.value)
|
||||
if (key && value) {
|
||||
object[key] = value
|
||||
}
|
||||
})
|
||||
return object
|
||||
}
|
||||
default: {
|
||||
// warn(`Not support ${node.type}: "${escodegen.generate(node)}"`)
|
||||
return ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function generateBinding (exp: ?string): any {
|
||||
if (exp && typeof exp === 'string') {
|
||||
let ast = null
|
||||
try {
|
||||
ast = acorn.parse(`(${exp})`)
|
||||
} catch (e) {
|
||||
// warn(`Failed to parse the expression: "${exp}"`)
|
||||
return ''
|
||||
}
|
||||
|
||||
let output = ''
|
||||
walk.simple(ast, {
|
||||
Expression (node) {
|
||||
output = nodeToBinding(node)
|
||||
}
|
||||
})
|
||||
return output
|
||||
}
|
||||
}
|
||||
-151
@@ -1,151 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { createPromiseCallback } from '../util'
|
||||
import { createBundleRunner } from './create-bundle-runner'
|
||||
import type { Renderer, RenderOptions } from '../create-renderer'
|
||||
import { createSourceMapConsumers, rewriteErrorTrace } from './source-map-support'
|
||||
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const PassThrough = require('stream').PassThrough
|
||||
|
||||
const INVALID_MSG =
|
||||
'Invalid server-rendering bundle format. Should be a string ' +
|
||||
'or a bundle Object of type:\n\n' +
|
||||
`{
|
||||
entry: string;
|
||||
files: { [filename: string]: string; };
|
||||
maps: { [filename: string]: string; };
|
||||
}\n`
|
||||
|
||||
// The render bundle can either be a string (single bundled file)
|
||||
// or a bundle manifest object generated by vue-ssr-webpack-plugin.
|
||||
type RenderBundle = {
|
||||
basedir?: string;
|
||||
entry: string;
|
||||
files: { [filename: string]: string; };
|
||||
maps: { [filename: string]: string; };
|
||||
modules?: { [filename: string]: Array<string> };
|
||||
};
|
||||
|
||||
export function createBundleRendererCreator (
|
||||
createRenderer: (options?: RenderOptions) => Renderer
|
||||
) {
|
||||
return function createBundleRenderer (
|
||||
bundle: string | RenderBundle,
|
||||
rendererOptions?: RenderOptions = {}
|
||||
) {
|
||||
let files, entry, maps
|
||||
let basedir = rendererOptions.basedir
|
||||
|
||||
// load bundle if given filepath
|
||||
if (
|
||||
typeof bundle === 'string' &&
|
||||
/\.js(on)?$/.test(bundle) &&
|
||||
path.isAbsolute(bundle)
|
||||
) {
|
||||
if (fs.existsSync(bundle)) {
|
||||
const isJSON = /\.json$/.test(bundle)
|
||||
basedir = basedir || path.dirname(bundle)
|
||||
bundle = fs.readFileSync(bundle, 'utf-8')
|
||||
if (isJSON) {
|
||||
try {
|
||||
bundle = JSON.parse(bundle)
|
||||
} catch (e) {
|
||||
throw new Error(`Invalid JSON bundle file: ${bundle}`)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Error(`Cannot locate bundle file: ${bundle}`)
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof bundle === 'object') {
|
||||
entry = bundle.entry
|
||||
files = bundle.files
|
||||
basedir = basedir || bundle.basedir
|
||||
maps = createSourceMapConsumers(bundle.maps)
|
||||
if (typeof entry !== 'string' || typeof files !== 'object') {
|
||||
throw new Error(INVALID_MSG)
|
||||
}
|
||||
} else if (typeof bundle === 'string') {
|
||||
entry = '__vue_ssr_bundle__'
|
||||
files = { '__vue_ssr_bundle__': bundle }
|
||||
maps = {}
|
||||
} else {
|
||||
throw new Error(INVALID_MSG)
|
||||
}
|
||||
|
||||
const renderer = createRenderer(rendererOptions)
|
||||
|
||||
const run = createBundleRunner(
|
||||
entry,
|
||||
files,
|
||||
basedir,
|
||||
rendererOptions.runInNewContext
|
||||
)
|
||||
|
||||
return {
|
||||
renderToString: (context?: Object, cb: any) => {
|
||||
if (typeof context === 'function') {
|
||||
cb = context
|
||||
context = {}
|
||||
}
|
||||
|
||||
let promise
|
||||
if (!cb) {
|
||||
({ promise, cb } = createPromiseCallback())
|
||||
}
|
||||
|
||||
run(context).catch(err => {
|
||||
rewriteErrorTrace(err, maps)
|
||||
cb(err)
|
||||
}).then(app => {
|
||||
if (app) {
|
||||
renderer.renderToString(app, context, (err, res) => {
|
||||
rewriteErrorTrace(err, maps)
|
||||
cb(err, res)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return promise
|
||||
},
|
||||
|
||||
renderToStream: (context?: Object) => {
|
||||
const res = new PassThrough()
|
||||
run(context).catch(err => {
|
||||
rewriteErrorTrace(err, maps)
|
||||
// avoid emitting synchronously before user can
|
||||
// attach error listener
|
||||
process.nextTick(() => {
|
||||
res.emit('error', err)
|
||||
})
|
||||
}).then(app => {
|
||||
if (app) {
|
||||
const renderStream = renderer.renderToStream(app, context)
|
||||
|
||||
renderStream.on('error', err => {
|
||||
rewriteErrorTrace(err, maps)
|
||||
res.emit('error', err)
|
||||
})
|
||||
|
||||
// relay HTMLStream special events
|
||||
if (rendererOptions && rendererOptions.template) {
|
||||
renderStream.on('beforeStart', () => {
|
||||
res.emit('beforeStart')
|
||||
})
|
||||
renderStream.on('beforeEnd', () => {
|
||||
res.emit('beforeEnd')
|
||||
})
|
||||
}
|
||||
|
||||
renderStream.pipe(res)
|
||||
}
|
||||
})
|
||||
|
||||
return res
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-150
@@ -1,150 +0,0 @@
|
||||
import { isPlainObject } from 'shared/util'
|
||||
|
||||
const vm = require('vm')
|
||||
const path = require('path')
|
||||
const resolve = require('resolve')
|
||||
const NativeModule = require('module')
|
||||
|
||||
function createSandbox (context) {
|
||||
const sandbox = {
|
||||
Buffer,
|
||||
console,
|
||||
process,
|
||||
setTimeout,
|
||||
setInterval,
|
||||
setImmediate,
|
||||
clearTimeout,
|
||||
clearInterval,
|
||||
clearImmediate,
|
||||
__VUE_SSR_CONTEXT__: context
|
||||
}
|
||||
sandbox.global = sandbox
|
||||
return sandbox
|
||||
}
|
||||
|
||||
function compileModule (files, basedir, runInNewContext) {
|
||||
const compiledScripts = {}
|
||||
const resolvedModules = {}
|
||||
|
||||
function getCompiledScript (filename) {
|
||||
if (compiledScripts[filename]) {
|
||||
return compiledScripts[filename]
|
||||
}
|
||||
const code = files[filename]
|
||||
const wrapper = NativeModule.wrap(code)
|
||||
const script = new vm.Script(wrapper, {
|
||||
filename,
|
||||
displayErrors: true
|
||||
})
|
||||
compiledScripts[filename] = script
|
||||
return script
|
||||
}
|
||||
|
||||
function evaluateModule (filename, sandbox, evaluatedFiles = {}) {
|
||||
if (evaluatedFiles[filename]) {
|
||||
return evaluatedFiles[filename]
|
||||
}
|
||||
|
||||
const script = getCompiledScript(filename)
|
||||
const compiledWrapper = runInNewContext === false
|
||||
? script.runInThisContext()
|
||||
: script.runInNewContext(sandbox)
|
||||
const m = { exports: {}}
|
||||
const r = file => {
|
||||
file = path.posix.join('.', file)
|
||||
if (files[file]) {
|
||||
return evaluateModule(file, sandbox, evaluatedFiles)
|
||||
} else if (basedir) {
|
||||
return require(
|
||||
resolvedModules[file] ||
|
||||
(resolvedModules[file] = resolve.sync(file, { basedir }))
|
||||
)
|
||||
} else {
|
||||
return require(file)
|
||||
}
|
||||
}
|
||||
compiledWrapper.call(m.exports, m.exports, r, m)
|
||||
|
||||
const res = Object.prototype.hasOwnProperty.call(m.exports, 'default')
|
||||
? m.exports.default
|
||||
: m.exports
|
||||
evaluatedFiles[filename] = res
|
||||
return res
|
||||
}
|
||||
return evaluateModule
|
||||
}
|
||||
|
||||
function deepClone (val) {
|
||||
if (isPlainObject(val)) {
|
||||
const res = {}
|
||||
for (const key in val) {
|
||||
res[key] = deepClone(val[key])
|
||||
}
|
||||
return res
|
||||
} else if (Array.isArray(val)) {
|
||||
return val.slice()
|
||||
} else {
|
||||
return val
|
||||
}
|
||||
}
|
||||
|
||||
export function createBundleRunner (entry, files, basedir, runInNewContext) {
|
||||
const evaluate = compileModule(files, basedir, runInNewContext)
|
||||
if (runInNewContext !== false && runInNewContext !== 'once') {
|
||||
// new context mode: creates a fresh context and re-evaluate the bundle
|
||||
// on each render. Ensures entire application state is fresh for each
|
||||
// render, but incurs extra evaluation cost.
|
||||
return (userContext = {}) => new Promise(resolve => {
|
||||
userContext._registeredComponents = new Set()
|
||||
const res = evaluate(entry, createSandbox(userContext))
|
||||
resolve(typeof res === 'function' ? res(userContext) : res)
|
||||
})
|
||||
} else {
|
||||
// direct mode: instead of re-evaluating the whole bundle on
|
||||
// each render, it simply calls the exported function. This avoids the
|
||||
// module evaluation costs but requires the source code to be structured
|
||||
// slightly differently.
|
||||
let runner // lazy creation so that errors can be caught by user
|
||||
let initialContext
|
||||
return (userContext = {}) => new Promise(resolve => {
|
||||
if (!runner) {
|
||||
const sandbox = runInNewContext === 'once'
|
||||
? createSandbox()
|
||||
: global
|
||||
// the initial context is only used for collecting possible non-component
|
||||
// styles injected by vue-style-loader.
|
||||
initialContext = sandbox.__VUE_SSR_CONTEXT__ = {}
|
||||
runner = evaluate(entry, sandbox)
|
||||
// On subsequent renders, __VUE_SSR_CONTEXT__ will not be available
|
||||
// to prevent cross-request pollution.
|
||||
delete sandbox.__VUE_SSR_CONTEXT__
|
||||
if (typeof runner !== 'function') {
|
||||
throw new Error(
|
||||
'bundle export should be a function when using ' +
|
||||
'{ runInNewContext: false }.'
|
||||
)
|
||||
}
|
||||
}
|
||||
userContext._registeredComponents = new Set()
|
||||
|
||||
// vue-style-loader styles imported outside of component lifecycle hooks
|
||||
if (initialContext._styles) {
|
||||
userContext._styles = deepClone(initialContext._styles)
|
||||
// #6353 ensure "styles" is exposed even if no styles are injected
|
||||
// in component lifecycles.
|
||||
// the renderStyles fn is exposed by vue-style-loader >= 3.0.3
|
||||
const renderStyles = initialContext._renderStyles
|
||||
if (renderStyles) {
|
||||
Object.defineProperty(userContext, 'styles', {
|
||||
enumerable: true,
|
||||
get () {
|
||||
return renderStyles(userContext._styles)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
resolve(runner(userContext))
|
||||
})
|
||||
}
|
||||
}
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
const SourceMapConsumer = require('source-map').SourceMapConsumer
|
||||
|
||||
const filenameRE = /\(([^)]+\.js):(\d+):(\d+)\)$/
|
||||
|
||||
export function createSourceMapConsumers (rawMaps: Object) {
|
||||
const maps = {}
|
||||
Object.keys(rawMaps).forEach(file => {
|
||||
maps[file] = new SourceMapConsumer(rawMaps[file])
|
||||
})
|
||||
return maps
|
||||
}
|
||||
|
||||
export function rewriteErrorTrace (e: any, mapConsumers: {
|
||||
[key: string]: SourceMapConsumer
|
||||
}) {
|
||||
if (e && typeof e.stack === 'string') {
|
||||
e.stack = e.stack.split('\n').map(line => {
|
||||
return rewriteTraceLine(line, mapConsumers)
|
||||
}).join('\n')
|
||||
}
|
||||
}
|
||||
|
||||
function rewriteTraceLine (trace: string, mapConsumers: {
|
||||
[key: string]: SourceMapConsumer
|
||||
}) {
|
||||
const m = trace.match(filenameRE)
|
||||
const map = m && mapConsumers[m[1]]
|
||||
if (m != null && map) {
|
||||
const originalPosition = map.originalPositionFor({
|
||||
line: Number(m[2]),
|
||||
column: Number(m[3])
|
||||
})
|
||||
if (originalPosition.source != null) {
|
||||
const { source, line, column } = originalPosition
|
||||
const mappedPosition = `(${source.replace(/^webpack:\/\/\//, '')}:${String(line)}:${String(column)})`
|
||||
return trace.replace(filenameRE, mappedPosition)
|
||||
} else {
|
||||
return trace
|
||||
}
|
||||
} else {
|
||||
return trace
|
||||
}
|
||||
}
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { createWriteFunction } from './write'
|
||||
import { createRenderFunction } from './render'
|
||||
import type { RenderOptions } from './create-renderer'
|
||||
|
||||
export function createBasicRenderer ({
|
||||
modules = [],
|
||||
directives = {},
|
||||
isUnaryTag = (() => false),
|
||||
cache
|
||||
}: RenderOptions = {}) {
|
||||
const render = createRenderFunction(modules, directives, isUnaryTag, cache)
|
||||
|
||||
return function renderToString (
|
||||
component: Component,
|
||||
context: any,
|
||||
done: any
|
||||
): void {
|
||||
if (typeof context === 'function') {
|
||||
done = context
|
||||
context = {}
|
||||
}
|
||||
let result = ''
|
||||
const write = createWriteFunction(text => {
|
||||
result += text
|
||||
return false
|
||||
}, done)
|
||||
try {
|
||||
render(component, write, context, () => {
|
||||
done(null, result)
|
||||
})
|
||||
} catch (e) {
|
||||
done(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { parse } from 'compiler/parser/index'
|
||||
import { generate } from './codegen'
|
||||
import { optimize } from './optimizer'
|
||||
import { createCompilerCreator } from 'compiler/create-compiler'
|
||||
|
||||
export const createCompiler = createCompilerCreator(function baseCompile (
|
||||
template: string,
|
||||
options: CompilerOptions
|
||||
): CompiledResult {
|
||||
const ast = parse(template.trim(), options)
|
||||
optimize(ast, options)
|
||||
const code = generate(ast, options)
|
||||
return {
|
||||
ast,
|
||||
render: code.render,
|
||||
staticRenderFns: code.staticRenderFns
|
||||
}
|
||||
})
|
||||
-150
@@ -1,150 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import { escape, isSSRUnsafeAttr } from 'web/server/util'
|
||||
import { isObject, extend } from 'shared/util'
|
||||
import { renderAttr } from 'web/server/modules/attrs'
|
||||
import { renderClass } from 'web/util/class'
|
||||
import { genStyle } from 'web/server/modules/style'
|
||||
import { normalizeStyleBinding } from 'web/util/style'
|
||||
|
||||
import {
|
||||
normalizeChildren,
|
||||
simpleNormalizeChildren
|
||||
} from 'core/vdom/helpers/normalize-children'
|
||||
|
||||
import {
|
||||
propsToAttrMap,
|
||||
isRenderableAttr
|
||||
} from 'web/server/util'
|
||||
|
||||
const ssrHelpers = {
|
||||
_ssrEscape: escape,
|
||||
_ssrNode: renderStringNode,
|
||||
_ssrList: renderStringList,
|
||||
_ssrAttr: renderAttr,
|
||||
_ssrAttrs: renderAttrs,
|
||||
_ssrDOMProps: renderDOMProps,
|
||||
_ssrClass: renderSSRClass,
|
||||
_ssrStyle: renderSSRStyle
|
||||
}
|
||||
|
||||
export function installSSRHelpers (vm: Component) {
|
||||
if (vm._ssrNode) {
|
||||
return
|
||||
}
|
||||
let Vue = vm.constructor
|
||||
while (Vue.super) {
|
||||
Vue = Vue.super
|
||||
}
|
||||
extend(Vue.prototype, ssrHelpers)
|
||||
if (Vue.FunctionalRenderContext) {
|
||||
extend(Vue.FunctionalRenderContext.prototype, ssrHelpers)
|
||||
}
|
||||
}
|
||||
|
||||
class StringNode {
|
||||
isString: boolean;
|
||||
open: string;
|
||||
close: ?string;
|
||||
children: ?Array<any>;
|
||||
|
||||
constructor (
|
||||
open: string,
|
||||
close?: string,
|
||||
children?: Array<any>,
|
||||
normalizationType?: number
|
||||
) {
|
||||
this.isString = true
|
||||
this.open = open
|
||||
this.close = close
|
||||
if (children) {
|
||||
this.children = normalizationType === 1
|
||||
? simpleNormalizeChildren(children)
|
||||
: normalizationType === 2
|
||||
? normalizeChildren(children)
|
||||
: children
|
||||
} else {
|
||||
this.children = void 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function renderStringNode (
|
||||
open: string,
|
||||
close?: string,
|
||||
children?: Array<any>,
|
||||
normalizationType?: number
|
||||
): StringNode {
|
||||
return new StringNode(open, close, children, normalizationType)
|
||||
}
|
||||
|
||||
function renderStringList (
|
||||
val: any,
|
||||
render: (
|
||||
val: any,
|
||||
keyOrIndex: string | number,
|
||||
index?: number
|
||||
) => string
|
||||
): string {
|
||||
let ret = ''
|
||||
let i, l, keys, key
|
||||
if (Array.isArray(val) || typeof val === 'string') {
|
||||
for (i = 0, l = val.length; i < l; i++) {
|
||||
ret += render(val[i], i)
|
||||
}
|
||||
} else if (typeof val === 'number') {
|
||||
for (i = 0; i < val; i++) {
|
||||
ret += render(i + 1, i)
|
||||
}
|
||||
} else if (isObject(val)) {
|
||||
keys = Object.keys(val)
|
||||
for (i = 0, l = keys.length; i < l; i++) {
|
||||
key = keys[i]
|
||||
ret += render(val[key], key, i)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
function renderAttrs (obj: Object): string {
|
||||
let res = ''
|
||||
for (const key in obj) {
|
||||
if (isSSRUnsafeAttr(key)) {
|
||||
continue
|
||||
}
|
||||
res += renderAttr(key, obj[key])
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
function renderDOMProps (obj: Object): string {
|
||||
let res = ''
|
||||
for (const key in obj) {
|
||||
const attr = propsToAttrMap[key] || key.toLowerCase()
|
||||
if (isRenderableAttr(attr)) {
|
||||
res += renderAttr(attr, obj[key])
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
function renderSSRClass (
|
||||
staticClass: ?string,
|
||||
dynamic: any
|
||||
): string {
|
||||
const res = renderClass(staticClass, dynamic)
|
||||
return res === '' ? res : ` class="${escape(res)}"`
|
||||
}
|
||||
|
||||
function renderSSRStyle (
|
||||
staticStyle: ?Object,
|
||||
dynamic: any,
|
||||
extra: ?Object
|
||||
): string {
|
||||
const style = {}
|
||||
if (staticStyle) extend(style, staticStyle)
|
||||
if (dynamic) extend(style, normalizeStyleBinding(dynamic))
|
||||
if (extra) extend(style, extra)
|
||||
const res = genStyle(style)
|
||||
return res === '' ? res : ` style=${JSON.stringify(escape(res))}`
|
||||
}
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
const compile = require('lodash.template')
|
||||
const compileOptions = {
|
||||
escape: /{{([^{][\s\S]+?[^}])}}/g,
|
||||
interpolate: /{{{([\s\S]+?)}}}/g
|
||||
}
|
||||
|
||||
export type ParsedTemplate = {
|
||||
head: (data: any) => string;
|
||||
neck: (data: any) => string;
|
||||
tail: (data: any) => string;
|
||||
};
|
||||
|
||||
export function parseTemplate (
|
||||
template: string,
|
||||
contentPlaceholder?: string = '<!--vue-ssr-outlet-->'
|
||||
): ParsedTemplate {
|
||||
if (typeof template === 'object') {
|
||||
return template
|
||||
}
|
||||
|
||||
let i = template.indexOf('</head>')
|
||||
const j = template.indexOf(contentPlaceholder)
|
||||
|
||||
if (j < 0) {
|
||||
throw new Error(`Content placeholder not found in template.`)
|
||||
}
|
||||
|
||||
if (i < 0) {
|
||||
i = template.indexOf('<body>')
|
||||
if (i < 0) {
|
||||
i = j
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
head: compile(template.slice(0, i), compileOptions),
|
||||
neck: compile(template.slice(i, j), compileOptions),
|
||||
tail: compile(template.slice(j + contentPlaceholder.length), compileOptions)
|
||||
}
|
||||
}
|
||||
-82
@@ -1,82 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
const Transform = require('stream').Transform
|
||||
import type TemplateRenderer from './index'
|
||||
import type { ParsedTemplate } from './parse-template'
|
||||
|
||||
export default class TemplateStream extends Transform {
|
||||
started: boolean;
|
||||
renderer: TemplateRenderer;
|
||||
template: ParsedTemplate;
|
||||
context: Object;
|
||||
inject: boolean;
|
||||
|
||||
constructor (
|
||||
renderer: TemplateRenderer,
|
||||
template: ParsedTemplate,
|
||||
context: Object
|
||||
) {
|
||||
super()
|
||||
this.started = false
|
||||
this.renderer = renderer
|
||||
this.template = template
|
||||
this.context = context || {}
|
||||
this.inject = renderer.inject
|
||||
}
|
||||
|
||||
_transform (data: Buffer | string, encoding: string, done: Function) {
|
||||
if (!this.started) {
|
||||
this.emit('beforeStart')
|
||||
this.start()
|
||||
}
|
||||
this.push(data)
|
||||
done()
|
||||
}
|
||||
|
||||
start () {
|
||||
this.started = true
|
||||
this.push(this.template.head(this.context))
|
||||
|
||||
if (this.inject) {
|
||||
// inline server-rendered head meta information
|
||||
if (this.context.head) {
|
||||
this.push(this.context.head)
|
||||
}
|
||||
|
||||
// inline preload/prefetch directives for initial/async chunks
|
||||
const links = this.renderer.renderResourceHints(this.context)
|
||||
if (links) {
|
||||
this.push(links)
|
||||
}
|
||||
|
||||
// CSS files and inline server-rendered CSS collected by vue-style-loader
|
||||
const styles = this.renderer.renderStyles(this.context)
|
||||
if (styles) {
|
||||
this.push(styles)
|
||||
}
|
||||
}
|
||||
|
||||
this.push(this.template.neck(this.context))
|
||||
}
|
||||
|
||||
_flush (done: Function) {
|
||||
this.emit('beforeEnd')
|
||||
|
||||
if (this.inject) {
|
||||
// inline initial store state
|
||||
const state = this.renderer.renderState(this.context)
|
||||
if (state) {
|
||||
this.push(state)
|
||||
}
|
||||
|
||||
// embed scripts needed
|
||||
const scripts = this.renderer.renderScripts(this.context)
|
||||
if (scripts) {
|
||||
this.push(scripts)
|
||||
}
|
||||
}
|
||||
|
||||
this.push(this.template.tail(this.context))
|
||||
done()
|
||||
}
|
||||
}
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
export const isJS = (file: string): boolean => /\.js(\?[^.]+)?$/.test(file)
|
||||
|
||||
export const isCSS = (file: string): boolean => /\.css(\?[^.]+)?$/.test(file)
|
||||
|
||||
export function createPromiseCallback () {
|
||||
let resolve, reject
|
||||
const promise: Promise<string> = new Promise((_resolve, _reject) => {
|
||||
resolve = _resolve
|
||||
reject = _reject
|
||||
})
|
||||
const cb = (err: Error, res?: string) => {
|
||||
if (err) return reject(err)
|
||||
resolve(res || '')
|
||||
}
|
||||
return { promise, cb }
|
||||
}
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
import { Vue as _Vue } from "./vue";
|
||||
|
||||
export type PluginFunction<T> = (Vue: typeof _Vue, options?: T) => void;
|
||||
|
||||
export interface PluginObject<T> {
|
||||
install: PluginFunction<T>;
|
||||
[key: string]: any;
|
||||
}
|
||||
Reference in new issue
Block a user