diff options
Diffstat (limited to 'node_modules/vue/src/platforms/web/compiler')
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' +) |
