diff options
Diffstat (limited to 'node_modules/vue/src/platforms/web/server')
10 files changed, 292 insertions, 0 deletions
diff --git a/node_modules/vue/src/platforms/web/server/compiler.js b/node_modules/vue/src/platforms/web/server/compiler.js new file mode 100644 index 00000000..20e57367 --- /dev/null +++ b/node_modules/vue/src/platforms/web/server/compiler.js @@ -0,0 +1,11 @@ +/* @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 +} diff --git a/node_modules/vue/src/platforms/web/server/directives/index.js b/node_modules/vue/src/platforms/web/server/directives/index.js new file mode 100644 index 00000000..fd7fce0a --- /dev/null +++ b/node_modules/vue/src/platforms/web/server/directives/index.js @@ -0,0 +1,7 @@ +import show from './show' +import model from './model' + +export default { + show, + model +} diff --git a/node_modules/vue/src/platforms/web/server/directives/model.js b/node_modules/vue/src/platforms/web/server/directives/model.js new file mode 100644 index 00000000..7962d6c8 --- /dev/null +++ b/node_modules/vue/src/platforms/web/server/directives/model.js @@ -0,0 +1,44 @@ +/* @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 = '' +} diff --git a/node_modules/vue/src/platforms/web/server/directives/show.js b/node_modules/vue/src/platforms/web/server/directives/show.js new file mode 100644 index 00000000..7493b27e --- /dev/null +++ b/node_modules/vue/src/platforms/web/server/directives/show.js @@ -0,0 +1,12 @@ +/* @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' + } + } +} diff --git a/node_modules/vue/src/platforms/web/server/modules/attrs.js b/node_modules/vue/src/platforms/web/server/modules/attrs.js new file mode 100644 index 00000000..c3f73013 --- /dev/null +++ b/node_modules/vue/src/platforms/web/server/modules/attrs.js @@ -0,0 +1,62 @@ +/* @flow */ + +import { escape } from '../util' + +import { + isDef, + isUndef, + extend +} from 'shared/util' + +import { + isBooleanAttr, + isEnumeratedAttr, + isFalsyAttrValue +} from 'web/util/attrs' + +import { isSSRUnsafeAttr } from 'web/server/util' + +export default function renderAttrs (node: VNodeWithData): string { + let attrs = node.data.attrs + let res = '' + + const opts = node.parent && node.parent.componentOptions + if (isUndef(opts) || opts.Ctor.options.inheritAttrs !== false) { + let parent = node.parent + while (isDef(parent)) { + if (isDef(parent.data) && isDef(parent.data.attrs)) { + attrs = extend(extend({}, attrs), parent.data.attrs) + } + parent = parent.parent + } + } + + if (isUndef(attrs)) { + return res + } + + for (const key in attrs) { + if (isSSRUnsafeAttr(key)) { + continue + } + if (key === 'style') { + // leave it to the style module + continue + } + res += renderAttr(key, attrs[key]) + } + return res +} + +export function renderAttr (key: string, value: string): string { + if (isBooleanAttr(key)) { + if (!isFalsyAttrValue(value)) { + return ` ${key}="${key}"` + } + } else if (isEnumeratedAttr(key)) { + return ` ${key}="${isFalsyAttrValue(value) || value === 'false' ? 'false' : 'true'}"` + } else if (!isFalsyAttrValue(value)) { + return ` ${key}="${escape(String(value))}"` + } + return '' +} diff --git a/node_modules/vue/src/platforms/web/server/modules/class.js b/node_modules/vue/src/platforms/web/server/modules/class.js new file mode 100644 index 00000000..c19040ed --- /dev/null +++ b/node_modules/vue/src/platforms/web/server/modules/class.js @@ -0,0 +1,11 @@ +/* @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)}"` + } +} diff --git a/node_modules/vue/src/platforms/web/server/modules/dom-props.js b/node_modules/vue/src/platforms/web/server/modules/dom-props.js new file mode 100644 index 00000000..57c18eef --- /dev/null +++ b/node_modules/vue/src/platforms/web/server/modules/dom-props.js @@ -0,0 +1,50 @@ +/* @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] +} diff --git a/node_modules/vue/src/platforms/web/server/modules/index.js b/node_modules/vue/src/platforms/web/server/modules/index.js new file mode 100644 index 00000000..3d15bc50 --- /dev/null +++ b/node_modules/vue/src/platforms/web/server/modules/index.js @@ -0,0 +1,11 @@ +import attrs from './attrs' +import domProps from './dom-props' +import klass from './class' +import style from './style' + +export default [ + attrs, + domProps, + klass, + style +] diff --git a/node_modules/vue/src/platforms/web/server/modules/style.js b/node_modules/vue/src/platforms/web/server/modules/style.js new file mode 100644 index 00000000..fc043ef3 --- /dev/null +++ b/node_modules/vue/src/platforms/web/server/modules/style.js @@ -0,0 +1,28 @@ +/* @flow */ + +import { escape } from '../util' +import { hyphenate } from 'shared/util' +import { getStyle } from 'web/util/style' + +export function genStyle (style: Object): string { + let styleText = '' + for (const key in style) { + const value = style[key] + const hyphenatedKey = hyphenate(key) + if (Array.isArray(value)) { + for (let i = 0, len = value.length; i < len; i++) { + styleText += `${hyphenatedKey}:${value[i]};` + } + } else { + styleText += `${hyphenatedKey}:${value};` + } + } + return styleText +} + +export default function renderStyle (vnode: VNodeWithData): ?string { + const styleText = genStyle(getStyle(vnode, false)) + if (styleText !== '') { + return ` style=${JSON.stringify(escape(styleText))}` + } +} diff --git a/node_modules/vue/src/platforms/web/server/util.js b/node_modules/vue/src/platforms/web/server/util.js new file mode 100644 index 00000000..27489705 --- /dev/null +++ b/node_modules/vue/src/platforms/web/server/util.js @@ -0,0 +1,56 @@ +/* @flow */ + +import { makeMap } from 'shared/util' + +const isAttr = makeMap( + 'accept,accept-charset,accesskey,action,align,alt,async,autocomplete,' + + 'autofocus,autoplay,autosave,bgcolor,border,buffered,challenge,charset,' + + 'checked,cite,class,code,codebase,color,cols,colspan,content,http-equiv,' + + 'name,contenteditable,contextmenu,controls,coords,data,datetime,default,' + + 'defer,dir,dirname,disabled,download,draggable,dropzone,enctype,method,for,' + + 'form,formaction,headers,height,hidden,high,href,hreflang,http-equiv,' + + 'icon,id,ismap,itemprop,keytype,kind,label,lang,language,list,loop,low,' + + 'manifest,max,maxlength,media,method,GET,POST,min,multiple,email,file,' + + 'muted,name,novalidate,open,optimum,pattern,ping,placeholder,poster,' + + 'preload,radiogroup,readonly,rel,required,reversed,rows,rowspan,sandbox,' + + 'scope,scoped,seamless,selected,shape,size,type,text,password,sizes,span,' + + 'spellcheck,src,srcdoc,srclang,srcset,start,step,style,summary,tabindex,' + + 'target,title,type,usemap,value,width,wrap' +) + +const unsafeAttrCharRE = /[>/="'\u0009\u000a\u000c\u0020]/ +export const isSSRUnsafeAttr = (name: string): boolean => { + return unsafeAttrCharRE.test(name) +} + +/* istanbul ignore next */ +const isRenderableAttr = (name: string): boolean => { + return ( + isAttr(name) || + name.indexOf('data-') === 0 || + name.indexOf('aria-') === 0 + ) +} +export { isRenderableAttr } + +export const propsToAttrMap = { + acceptCharset: 'accept-charset', + className: 'class', + htmlFor: 'for', + httpEquiv: 'http-equiv' +} + +const ESC = { + '<': '<', + '>': '>', + '"': '"', + '&': '&' +} + +export function escape (s: string) { + return s.replace(/[<>"&]/g, escapeChar) +} + +function escapeChar (a) { + return ESC[a] || a +} |
