aboutsummaryrefslogtreecommitdiff
path: root/node_modules/vue/src/platforms/web/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/vue/src/platforms/web/compiler')
-rw-r--r--node_modules/vue/src/platforms/web/compiler/directives/html.js9
-rw-r--r--node_modules/vue/src/platforms/web/compiler/directives/index.js9
-rw-r--r--node_modules/vue/src/platforms/web/compiler/directives/model.js172
-rw-r--r--node_modules/vue/src/platforms/web/compiler/directives/text.js9
-rw-r--r--node_modules/vue/src/platforms/web/compiler/index.js8
-rw-r--r--node_modules/vue/src/platforms/web/compiler/modules/class.js48
-rw-r--r--node_modules/vue/src/platforms/web/compiler/modules/index.js9
-rw-r--r--node_modules/vue/src/platforms/web/compiler/modules/model.js94
-rw-r--r--node_modules/vue/src/platforms/web/compiler/modules/style.js51
-rw-r--r--node_modules/vue/src/platforms/web/compiler/options.js26
-rw-r--r--node_modules/vue/src/platforms/web/compiler/util.js24
11 files changed, 459 insertions, 0 deletions
diff --git a/node_modules/vue/src/platforms/web/compiler/directives/html.js b/node_modules/vue/src/platforms/web/compiler/directives/html.js
new file mode 100644
index 00000000..58569d8e
--- /dev/null
+++ b/node_modules/vue/src/platforms/web/compiler/directives/html.js
@@ -0,0 +1,9 @@
+/* @flow */
+
+import { addProp } from 'compiler/helpers'
+
+export default function html (el: ASTElement, dir: ASTDirective) {
+ if (dir.value) {
+ addProp(el, 'innerHTML', `_s(${dir.value})`)
+ }
+}
diff --git a/node_modules/vue/src/platforms/web/compiler/directives/index.js b/node_modules/vue/src/platforms/web/compiler/directives/index.js
new file mode 100644
index 00000000..0955b51e
--- /dev/null
+++ b/node_modules/vue/src/platforms/web/compiler/directives/index.js
@@ -0,0 +1,9 @@
+import model from './model'
+import text from './text'
+import html from './html'
+
+export default {
+ model,
+ text,
+ html
+}
diff --git a/node_modules/vue/src/platforms/web/compiler/directives/model.js b/node_modules/vue/src/platforms/web/compiler/directives/model.js
new file mode 100644
index 00000000..126f0c7d
--- /dev/null
+++ b/node_modules/vue/src/platforms/web/compiler/directives/model.js
@@ -0,0 +1,172 @@
+/* @flow */
+
+import config from 'core/config'
+import { addHandler, addProp, getBindingAttr } from 'compiler/helpers'
+import { genComponentModel, genAssignmentCode } from 'compiler/directives/model'
+
+let warn
+
+// in some cases, the event used has to be determined at runtime
+// so we used some reserved tokens during compile.
+export const RANGE_TOKEN = '__r'
+export const CHECKBOX_RADIO_TOKEN = '__c'
+
+export default function model (
+ el: ASTElement,
+ dir: ASTDirective,
+ _warn: Function
+): ?boolean {
+ warn = _warn
+ const value = dir.value
+ const modifiers = dir.modifiers
+ const tag = el.tag
+ const type = el.attrsMap.type
+
+ if (process.env.NODE_ENV !== 'production') {
+ // inputs with type="file" are read only and setting the input's
+ // value will throw an error.
+ if (tag === 'input' && type === 'file') {
+ warn(
+ `<${el.tag} v-model="${value}" type="file">:\n` +
+ `File inputs are read only. Use a v-on:change listener instead.`
+ )
+ }
+ }
+
+ if (el.component) {
+ genComponentModel(el, value, modifiers)
+ // component v-model doesn't need extra runtime
+ return false
+ } else if (tag === 'select') {
+ genSelect(el, value, modifiers)
+ } else if (tag === 'input' && type === 'checkbox') {
+ genCheckboxModel(el, value, modifiers)
+ } else if (tag === 'input' && type === 'radio') {
+ genRadioModel(el, value, modifiers)
+ } else if (tag === 'input' || tag === 'textarea') {
+ genDefaultModel(el, value, modifiers)
+ } else if (!config.isReservedTag(tag)) {
+ genComponentModel(el, value, modifiers)
+ // component v-model doesn't need extra runtime
+ return false
+ } else if (process.env.NODE_ENV !== 'production') {
+ warn(
+ `<${el.tag} v-model="${value}">: ` +
+ `v-model is not supported on this element type. ` +
+ 'If you are working with contenteditable, it\'s recommended to ' +
+ 'wrap a library dedicated for that purpose inside a custom component.'
+ )
+ }
+
+ // ensure runtime directive metadata
+ return true
+}
+
+function genCheckboxModel (
+ el: ASTElement,
+ value: string,
+ modifiers: ?ASTModifiers
+) {
+ const number = modifiers && modifiers.number
+ const valueBinding = getBindingAttr(el, 'value') || 'null'
+ const trueValueBinding = getBindingAttr(el, 'true-value') || 'true'
+ const falseValueBinding = getBindingAttr(el, 'false-value') || 'false'
+ addProp(el, 'checked',
+ `Array.isArray(${value})` +
+ `?_i(${value},${valueBinding})>-1` + (
+ trueValueBinding === 'true'
+ ? `:(${value})`
+ : `:_q(${value},${trueValueBinding})`
+ )
+ )
+ addHandler(el, 'change',
+ `var $$a=${value},` +
+ '$$el=$event.target,' +
+ `$$c=$$el.checked?(${trueValueBinding}):(${falseValueBinding});` +
+ 'if(Array.isArray($$a)){' +
+ `var $$v=${number ? '_n(' + valueBinding + ')' : valueBinding},` +
+ '$$i=_i($$a,$$v);' +
+ `if($$el.checked){$$i<0&&(${genAssignmentCode(value, '$$a.concat([$$v])')})}` +
+ `else{$$i>-1&&(${genAssignmentCode(value, '$$a.slice(0,$$i).concat($$a.slice($$i+1))')})}` +
+ `}else{${genAssignmentCode(value, '$$c')}}`,
+ null, true
+ )
+}
+
+function genRadioModel (
+ el: ASTElement,
+ value: string,
+ modifiers: ?ASTModifiers
+) {
+ const number = modifiers && modifiers.number
+ let valueBinding = getBindingAttr(el, 'value') || 'null'
+ valueBinding = number ? `_n(${valueBinding})` : valueBinding
+ addProp(el, 'checked', `_q(${value},${valueBinding})`)
+ addHandler(el, 'change', genAssignmentCode(value, valueBinding), null, true)
+}
+
+function genSelect (
+ el: ASTElement,
+ value: string,
+ modifiers: ?ASTModifiers
+) {
+ const number = modifiers && modifiers.number
+ const selectedVal = `Array.prototype.filter` +
+ `.call($event.target.options,function(o){return o.selected})` +
+ `.map(function(o){var val = "_value" in o ? o._value : o.value;` +
+ `return ${number ? '_n(val)' : 'val'}})`
+
+ const assignment = '$event.target.multiple ? $$selectedVal : $$selectedVal[0]'
+ let code = `var $$selectedVal = ${selectedVal};`
+ code = `${code} ${genAssignmentCode(value, assignment)}`
+ addHandler(el, 'change', code, null, true)
+}
+
+function genDefaultModel (
+ el: ASTElement,
+ value: string,
+ modifiers: ?ASTModifiers
+): ?boolean {
+ const type = el.attrsMap.type
+
+ // warn if v-bind:value conflicts with v-model
+ // except for inputs with v-bind:type
+ if (process.env.NODE_ENV !== 'production') {
+ const value = el.attrsMap['v-bind:value'] || el.attrsMap[':value']
+ const typeBinding = el.attrsMap['v-bind:type'] || el.attrsMap[':type']
+ if (value && !typeBinding) {
+ const binding = el.attrsMap['v-bind:value'] ? 'v-bind:value' : ':value'
+ warn(
+ `${binding}="${value}" conflicts with v-model on the same element ` +
+ 'because the latter already expands to a value binding internally'
+ )
+ }
+ }
+
+ const { lazy, number, trim } = modifiers || {}
+ const needCompositionGuard = !lazy && type !== 'range'
+ const event = lazy
+ ? 'change'
+ : type === 'range'
+ ? RANGE_TOKEN
+ : 'input'
+
+ let valueExpression = '$event.target.value'
+ if (trim) {
+ valueExpression = `$event.target.value.trim()`
+ }
+ if (number) {
+ valueExpression = `_n(${valueExpression})`
+ }
+
+ let code = genAssignmentCode(value, valueExpression)
+ if (needCompositionGuard) {
+ code = `if($event.target.composing)return;${code}`
+ }
+
+ addProp(el, 'value', `(${value})`)
+ addHandler(el, event, code, null, true)
+ if (trim || number) {
+ addHandler(el, 'blur', '$forceUpdate()')
+ }
+}
diff --git a/node_modules/vue/src/platforms/web/compiler/directives/text.js b/node_modules/vue/src/platforms/web/compiler/directives/text.js
new file mode 100644
index 00000000..1af914f8
--- /dev/null
+++ b/node_modules/vue/src/platforms/web/compiler/directives/text.js
@@ -0,0 +1,9 @@
+/* @flow */
+
+import { addProp } from 'compiler/helpers'
+
+export default function text (el: ASTElement, dir: ASTDirective) {
+ if (dir.value) {
+ addProp(el, 'textContent', `_s(${dir.value})`)
+ }
+}
diff --git a/node_modules/vue/src/platforms/web/compiler/index.js b/node_modules/vue/src/platforms/web/compiler/index.js
new file mode 100644
index 00000000..7ace0936
--- /dev/null
+++ b/node_modules/vue/src/platforms/web/compiler/index.js
@@ -0,0 +1,8 @@
+/* @flow */
+
+import { baseOptions } from './options'
+import { createCompiler } from 'compiler/index'
+
+const { compile, compileToFunctions } = createCompiler(baseOptions)
+
+export { compile, compileToFunctions }
diff --git a/node_modules/vue/src/platforms/web/compiler/modules/class.js b/node_modules/vue/src/platforms/web/compiler/modules/class.js
new file mode 100644
index 00000000..ffdca250
--- /dev/null
+++ b/node_modules/vue/src/platforms/web/compiler/modules/class.js
@@ -0,0 +1,48 @@
+/* @flow */
+
+import { parseText } from 'compiler/parser/text-parser'
+import {
+ getAndRemoveAttr,
+ getBindingAttr,
+ baseWarn
+} from 'compiler/helpers'
+
+function transformNode (el: ASTElement, options: CompilerOptions) {
+ const warn = options.warn || baseWarn
+ const staticClass = getAndRemoveAttr(el, 'class')
+ if (process.env.NODE_ENV !== 'production' && staticClass) {
+ const res = parseText(staticClass, options.delimiters)
+ if (res) {
+ warn(
+ `class="${staticClass}": ` +
+ 'Interpolation inside attributes has been removed. ' +
+ 'Use v-bind or the colon shorthand instead. For example, ' +
+ 'instead of <div class="{{ val }}">, use <div :class="val">.'
+ )
+ }
+ }
+ if (staticClass) {
+ el.staticClass = JSON.stringify(staticClass)
+ }
+ const classBinding = getBindingAttr(el, 'class', false /* getStatic */)
+ if (classBinding) {
+ el.classBinding = classBinding
+ }
+}
+
+function genData (el: ASTElement): string {
+ let data = ''
+ if (el.staticClass) {
+ data += `staticClass:${el.staticClass},`
+ }
+ if (el.classBinding) {
+ data += `class:${el.classBinding},`
+ }
+ return data
+}
+
+export default {
+ staticKeys: ['staticClass'],
+ transformNode,
+ genData
+}
diff --git a/node_modules/vue/src/platforms/web/compiler/modules/index.js b/node_modules/vue/src/platforms/web/compiler/modules/index.js
new file mode 100644
index 00000000..29114a53
--- /dev/null
+++ b/node_modules/vue/src/platforms/web/compiler/modules/index.js
@@ -0,0 +1,9 @@
+import klass from './class'
+import style from './style'
+import model from './model'
+
+export default [
+ klass,
+ style,
+ model
+]
diff --git a/node_modules/vue/src/platforms/web/compiler/modules/model.js b/node_modules/vue/src/platforms/web/compiler/modules/model.js
new file mode 100644
index 00000000..8d784fe4
--- /dev/null
+++ b/node_modules/vue/src/platforms/web/compiler/modules/model.js
@@ -0,0 +1,94 @@
+/* @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
+}
diff --git a/node_modules/vue/src/platforms/web/compiler/modules/style.js b/node_modules/vue/src/platforms/web/compiler/modules/style.js
new file mode 100644
index 00000000..2722b92b
--- /dev/null
+++ b/node_modules/vue/src/platforms/web/compiler/modules/style.js
@@ -0,0 +1,51 @@
+/* @flow */
+
+import { parseText } from 'compiler/parser/text-parser'
+import { parseStyleText } from 'web/util/style'
+import {
+ getAndRemoveAttr,
+ getBindingAttr,
+ baseWarn
+} from 'compiler/helpers'
+
+function transformNode (el: ASTElement, options: CompilerOptions) {
+ const warn = options.warn || baseWarn
+ const staticStyle = getAndRemoveAttr(el, 'style')
+ if (staticStyle) {
+ /* istanbul ignore if */
+ if (process.env.NODE_ENV !== 'production') {
+ const res = parseText(staticStyle, options.delimiters)
+ if (res) {
+ warn(
+ `style="${staticStyle}": ` +
+ 'Interpolation inside attributes has been removed. ' +
+ 'Use v-bind or the colon shorthand instead. For example, ' +
+ 'instead of <div style="{{ val }}">, use <div :style="val">.'
+ )
+ }
+ }
+ el.staticStyle = JSON.stringify(parseStyleText(staticStyle))
+ }
+
+ const styleBinding = getBindingAttr(el, 'style', false /* getStatic */)
+ if (styleBinding) {
+ el.styleBinding = styleBinding
+ }
+}
+
+function genData (el: ASTElement): string {
+ let data = ''
+ if (el.staticStyle) {
+ data += `staticStyle:${el.staticStyle},`
+ }
+ if (el.styleBinding) {
+ data += `style:(${el.styleBinding}),`
+ }
+ return data
+}
+
+export default {
+ staticKeys: ['staticStyle'],
+ transformNode,
+ genData
+}
diff --git a/node_modules/vue/src/platforms/web/compiler/options.js b/node_modules/vue/src/platforms/web/compiler/options.js
new file mode 100644
index 00000000..70c0c488
--- /dev/null
+++ b/node_modules/vue/src/platforms/web/compiler/options.js
@@ -0,0 +1,26 @@
+/* @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)
+}
diff --git a/node_modules/vue/src/platforms/web/compiler/util.js b/node_modules/vue/src/platforms/web/compiler/util.js
new file mode 100644
index 00000000..7d9394d3
--- /dev/null
+++ b/node_modules/vue/src/platforms/web/compiler/util.js
@@ -0,0 +1,24 @@
+/* @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'
+)