Example #1
0
strats.computed = function (
  parentVal: ?Object,
  childVal: ?Object,
  vm?: Component,
  key: string
): ?Object {
  if (childVal && process.env.NODE_ENV !== 'production') {
    assertObjectType(key, childVal, vm)
  }
  if (!parentVal) return childVal
  const ret = Object.create(null)
  extend(ret, parentVal)
  if (childVal) extend(ret, childVal)
  return ret
}
Example #2
0
strats.watch = function (
  parentVal: ?Object,
  childVal: ?Object,
  vm?: Component,
  key: string
): ?Object {
  // work around Firefox's Object.prototype.watch...
  if (parentVal === nativeWatch) parentVal = undefined
  if (childVal === nativeWatch) childVal = undefined
  /* istanbul ignore if */
  if (!childVal) return Object.create(parentVal || null)
  if (process.env.NODE_ENV !== 'production') {
    assertObjectType(key, childVal, vm)
  }
  if (!parentVal) return childVal
  const ret = {}
  extend(ret, parentVal)
  for (const key in childVal) {
    let parent = ret[key]
    const child = childVal[key]
    if (parent && !Array.isArray(parent)) {
      parent = [parent]
    }
    ret[key] = parent
      ? parent.concat(child)
      : Array.isArray(child) ? child : [child]
  }
  return ret
}
Example #3
0
function updateStyle(oldVnode, vnode) {
    if (!oldVnode.data.style && !vnode.data.style) {
        return
    }
    let cur, name
    const elm = vnode.elm
    const oldStyle = oldVnode.data.style || {}
    let style = vnode.data.style || {}

    const needClone = style.__ob__

    // handle array syntax
    if (Array.isArray(style)) {
        style = vnode.data.style = toObject(style)
    }

    // clone the style for future updates,
    // in case the user mutates the style object in-place.
    if (needClone) {
        style = vnode.data.style = extend({}, style)
    }

    for (name in oldStyle) {
        if (!style[name]) {
            elm.setStyle(normalize(name), '')
        }
    }
    for (name in style) {
        cur = style[name]
        elm.setStyle(normalize(name), cur)
    }
}
Example #4
0
/**
 * Normalize all injections into Object-based format
 * 将所有注入规范化为基于对象的格式
 */
function normalizeInject (options: Object, vm: ?Component) {
  const inject = options.inject
  if (!inject) return
  const normalized = options.inject = {}
  if (Array.isArray(inject)) { // 将数组改为形如{from:val} 的对象
    for (let i = 0; i < inject.length; i++) {
      normalized[inject[i]] = { from: inject[i] }
    }
  } else if (isPlainObject(inject)) {
    // 对象就枚举 ==> 改变成2个不同的{}形式
    for (const key in inject) {
      const val = inject[key]
      normalized[key] = isPlainObject(val)
        ? extend({ from: key }, val)
        : { from: val }
    }
  } else if (process.env.NODE_ENV !== 'production') {
    // 不是arr和obj那就错啦
    warn(
      `Invalid value for option "inject": expected an Array or an Object, ` +
      `but got ${toRawType(inject)}.`,
      vm
    )
  }
}
Example #5
0
strats.watch = function (
  parentVal: ?Object,
  childVal: ?Object,
  vm?: Component,
  key: string
): ?Object {
  // work around Firefox's Object.prototype.watch...
  if (parentVal === nativeWatch) parentVal = undefined
  if (childVal === nativeWatch) childVal = undefined
  /* istanbul ignore if */
  // 不存在子直接返回父的复制 (因为create会挂载到__proto__原型链上)
  if (!childVal) return Object.create(parentVal || null)
  if (process.env.NODE_ENV !== 'production') {
    assertObjectType(key, childVal, vm) // 检验真对象[Object Object]
  }
  if (!parentVal) return childVal // 没有父返回子
  const ret = {}
  extend(ret, parentVal) // 浅拷贝一份父的
  for (const key in childVal) {
    let parent = ret[key]
    const child = childVal[key]
    // 父存在 、转数组
    if (parent && !Array.isArray(parent)) {
      parent = [parent]
    }
    // 和mergeHook一样的处理
    ret[key] = parent
      ? parent.concat(child)
      : Array.isArray(child) ? child : [child]
  }
  return ret
}
Example #6
0
 it('not specified getTagNamespace option', () => {
   const options = extend({}, baseOptions)
   delete options.getTagNamespace
   const ast = parse('<svg><text>hello world</text></svg>', options)
   expect(ast.tag).toBe('svg')
   expect(ast.ns).toBeUndefined()
 })
Example #7
0
function resolveTransition (def?: string | Object): ?Object {
  if (!def) {
    return
  }
  /* istanbul ignore else */
  if (typeof def === 'object') {
    const res = {}
    if (def.css !== false) {
      extend(res, autoCssTransition(def.name || 'v'))
    }
    extend(res, def)
    return res
  } else if (typeof def === 'string') {
    return autoCssTransition(def)
  }
}
Example #8
0
function updateAttrs (oldVnode: VNodeWithData, vnode: VNodeWithData) {
  if (isUndef(oldVnode.data.attrs) && isUndef(vnode.data.attrs)) {
    return
  }
  let key, cur, old
  const elm = vnode.elm
  const oldAttrs = oldVnode.data.attrs || {}
  let attrs: any = vnode.data.attrs || {}
  // clone observed objects, as the user probably wants to mutate it
  if (isDef(attrs.__ob__)) {
    attrs = vnode.data.attrs = extend({}, attrs)
  }

  for (key in attrs) {
    cur = attrs[key]
    old = oldAttrs[key]
    if (old !== cur) {
      setAttr(elm, key, cur)
    }
  }
  // #4391: in IE9, setting type can reset value for input[type=radio]
  /* istanbul ignore if */
  if (isIE9 && attrs.value !== oldAttrs.value) {
    setAttr(elm, 'value', attrs.value)
  }
  for (key in oldAttrs) {
    if (isUndef(attrs[key])) {
      if (isXlink(key)) {
        elm.removeAttributeNS(xlinkNS, getXlinkProp(key))
      } else if (!isEnumeratedAttr(key)) {
        elm.removeAttribute(key)
      }
    }
  }
}
Example #9
0
// merge static and dynamic style data on the same vnode
function normalizeStyleData (data: VNodeData): ?Object {
  const style = normalizeStyleBinding(data.style)
  // static style is pre-processed into an object during compilation
  // and is always a fresh object, so it's safe to merge into it
  return data.staticStyle
    ? extend(data.staticStyle, style)
    : style
}
Example #10
0
 it('forgivingly handle < in plain text', () => {
   const options = extend({}, baseOptions)
   const ast = parse('<p>1 < 2 < 3</p>', options)
   expect(ast.tag).toBe('p')
   expect(ast.children.length).toBe(1)
   expect(ast.children[0].type).toBe(3)
   expect(ast.children[0].text).toBe('1 < 2 < 3')
 })
Example #11
0
 it('should ignore comments', () => {
   const options = extend({}, baseOptions)
   const ast = parse(`<div>123<!--comment here--></div>`, options)
   expect(ast.tag).toBe('div')
   expect(ast.children.length).toBe(1)
   expect(ast.children[0].type).toBe(3)
   expect(ast.children[0].text).toBe('123')
 })
Example #12
0
function toObject(arr) {
    const res = {}
    for (var i = 0; i < arr.length; i++) {
        if (arr[i]) {
            extend(res, arr[i])
        }
    }
    return res
}
Example #13
0
strats.computed = function ( // 计算属性
  parentVal: ?Object,
  childVal: ?Object,
  vm?: Component,
  key: string
): ?Object {
  if (childVal && process.env.NODE_ENV !== 'production') {
    assertObjectType(key, childVal, vm) // [Object Object]
  }
  /**
   * 1、无父拿子
   * 2、复制父
   * 3、有子合并
   * 4、返回合并/复制结果
   **/
  if (!parentVal) return childVal
  const ret = Object.create(null)
  extend(ret, parentVal)
  if (childVal) extend(ret, childVal)
  return ret
}
Example #14
0
  it('generate component with comment', () => {
    const options = extend({
      comments: true
    }, baseOptions)
    const template = '<div><!--comment--></div>'
    const generatedCode = `with(this){return _c('div',[_e("comment")])}`

    const ast = parse(template, options)
    optimize(ast, options)
    const res = generate(ast, options)
    expect(res.render).toBe(generatedCode)
  })
Example #15
0
  it('generate comments with special characters', () => {
    const options = extend({
      comments: true
    }, baseOptions)
    const template = '<div><!--\n\'comment\'\n--></div>'
    const generatedCode = `with(this){return _c('div',[_e("\\n'comment'\\n")])}`

    const ast = parse(template, options)
    optimize(ast, options)
    const res = generate(ast, options)
    expect(res.render).toBe(generatedCode)
  })
Example #16
0
 it('IE conditional comments', () => {
   const options = extend({}, baseOptions)
   const ast = parse(`
     <div>
       <!--[if lte IE 8]>
         <p>Test 1</p>
       <![endif]-->
     </div>
   `, options)
   expect(ast.tag).toBe('div')
   expect(ast.children.length).toBe(0)
 })
Example #17
0
 it('should kept comments', () => {
   const options = extend({
     comments: true
   }, baseOptions)
   const ast = parse(`<div>123<!--comment here--></div>`, options)
   expect(ast.tag).toBe('div')
   expect(ast.children.length).toBe(2)
   expect(ast.children[0].type).toBe(3)
   expect(ast.children[0].text).toBe('123')
   expect(ast.children[1].type).toBe(3) // parse comment with ASTText
   expect(ast.children[1].isComment).toBe(true) // parse comment with ASTText
   expect(ast.children[1].text).toBe('comment here')
 })
Example #18
0
export function processFor (el: ASTElement) {
  let exp
  if ((exp = getAndRemoveAttr(el, 'v-for'))) {
    const res = parseFor(exp)
    if (res) {
      extend(el, res)
    } else if (process.env.NODE_ENV !== 'production') {
      warn(
        `Invalid v-for expression: ${exp}`
      )
    }
  }
}
Example #19
0
 it('ignore the first newline in <pre> tag', function () {
   const options = extend({}, baseOptions)
   const ast = parse('<div><pre>\nabc</pre>\ndef<pre>\n\nabc</pre></div>', options)
   const pre = ast.children[0]
   expect(pre.children[0].type).toBe(3)
   expect(pre.children[0].text).toBe('abc')
   const text = ast.children[1]
   expect(text.type).toBe(3)
   expect(text.text).toBe('\ndef')
   const pre2 = ast.children[2]
   expect(pre2.children[0].type).toBe(3)
   expect(pre2.children[0].text).toBe('\nabc')
 })
Example #20
0
  it('preserve whitespace in <pre> tag', function () {
    const options = extend({}, baseOptions)
    const ast = parse('<pre><code>  \n<span>hi</span>\n  </code><span> </span></pre>', options)
    const code = ast.children[0]
    expect(code.children[0].type).toBe(3)
    expect(code.children[0].text).toBe('  \n')
    expect(code.children[2].type).toBe(3)
    expect(code.children[2].text).toBe('\n  ')

    const span = ast.children[1]
    expect(span.children[0].type).toBe(3)
    expect(span.children[0].text).toBe(' ')
  })
Example #21
0
/**
 * Assets
 *
 * When a vm is present (instance creation), we need to do
 * a three-way merge between constructor options, instance
 * options and parent options.
 */
function mergeAssets (
  parentVal: ?Object,
  childVal: ?Object,
  vm?: Component,
  key: string
): Object {
  const res = Object.create(parentVal || null)
  if (childVal) {
    process.env.NODE_ENV !== 'production' && assertObjectType(key, childVal, vm)
    return extend(res, childVal)
  } else {
    return res
  }
}
Example #22
0
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
}
Example #23
0
export function compile (
  template: string,
  options?: CompilerOptions
): CompiledResult {
  options = options || {}
  const errors = []
  // allow injecting modules/directives
  const baseModules = baseOptions.modules || []
  const modules = options.modules
    ? baseModules.concat(options.modules)
    : baseModules
  const directives = options.directives
    ? extend(extend({}, baseOptions.directives), options.directives)
    : baseOptions.directives
  const compiled = baseCompile(template, {
    modules,
    directives,
    warn: msg => {
      errors.push(msg)
    }
  })
  compiled.errors = errors.concat(detectErrors(compiled.ast))
  return compiled
}
Example #24
0
 it('pre/post transforms', () => {
   const options = extend({}, baseOptions)
   const spy1 = jasmine.createSpy('preTransform')
   const spy2 = jasmine.createSpy('postTransform')
   options.modules = options.modules.concat([{
     preTransformNode (el) {
       spy1(el.tag)
     },
     postTransformNode (el) {
       expect(el.attrs.length).toBe(1)
       spy2(el.tag)
     }
   }])
   parse('<img v-pre src="hi">', options)
   expect(spy1).toHaveBeenCalledWith('img')
   expect(spy2).toHaveBeenCalledWith('img')
 })
Example #25
0
strats.watch = function (parentVal: ?Object, childVal: ?Object): ?Object {
  /* istanbul ignore if */
  if (!childVal) return parentVal
  if (!parentVal) return childVal
  const ret = {}
  extend(ret, parentVal)
  for (const key in childVal) {
    let parent = ret[key]
    const child = childVal[key]
    if (parent && !Array.isArray(parent)) {
      parent = [parent]
    }
    ret[key] = parent
      ? parent.concat(child)
      : [child]
  }
  return ret
}
Example #26
0
function updateDOMProps (oldVnode: VNodeWithData, vnode: VNodeWithData) {
  if (isUndef(oldVnode.data.domProps) && isUndef(vnode.data.domProps)) {
    return
  }
  let key, cur
  const elm: any = vnode.elm
  const oldProps = oldVnode.data.domProps || {}
  let props = vnode.data.domProps || {}
  // clone observed objects, as the user probably wants to mutate it
  if (isDef(props.__ob__)) {
    props = vnode.data.domProps = extend({}, props)
  }

  for (key in oldProps) {
    if (isUndef(props[key])) {
      elm[key] = ''
    }
  }
  for (key in props) {
    cur = props[key]
    // ignore children if the node has textContent or innerHTML,
    // as these will throw away existing DOM nodes and cause removal errors
    // on subsequent patches (#3360)
    if (key === 'textContent' || key === 'innerHTML') {
      if (vnode.children) vnode.children.length = 0
      if (cur === oldProps[key]) continue
    }

    if (key === 'value') {
      // store value as _value as well since
      // non-string values will be stringified
      elm._value = cur
      // avoid resetting cursor position when value is the same
      const strCur = isUndef(cur) ? '' : String(cur)
      if (shouldUpdateValue(elm, vnode, strCur)) {
        elm.value = strCur
      }
    } else {
      elm[key] = cur
    }
  }
}
Example #27
0
function updateStyle (oldVnode: VNodeWithData, vnode: VNodeWithData) {
  if ((!oldVnode.data || !oldVnode.data.style) && !vnode.data.style) {
    return
  }
  let cur, name
  const el: any = vnode.elm
  const oldStyle: any = oldVnode.data.style || {}
  let style: any = vnode.data.style || {}

  // handle string
  if (typeof style === 'string') {
    el.style.cssText = style
    return
  }

  const needClone = style.__ob__

  // handle array syntax
  if (Array.isArray(style)) {
    style = vnode.data.style = toObject(style)
  }

  // clone the style for future updates,
  // in case the user mutates the style object in-place.
  if (needClone) {
    style = vnode.data.style = extend({}, style)
  }

  for (name in oldStyle) {
    if (!style[name]) {
      el.style[normalize(name)] = ''
    }
  }
  for (name in style) {
    cur = style[name]
    if (cur !== oldStyle[name]) {
      // ie9 setting to null has no effect, must use empty string
      el.style[normalize(name)] = cur == null ? '' : cur
    }
  }
}
Example #28
0
strats.watch = function (parentVal: ?Object, childVal: ?Object): ?Object {
  // work around Firefox's Object.prototype.watch...
  if (parentVal === nativeWatch) parentVal = undefined
  if (childVal === nativeWatch) childVal = undefined
  /* istanbul ignore if */
  if (!childVal) return Object.create(parentVal || null)
  if (!parentVal) return childVal
  const ret = {}
  extend(ret, parentVal)
  for (const key in childVal) {
    let parent = ret[key]
    const child = childVal[key]
    if (parent && !Array.isArray(parent)) {
      parent = [parent]
    }
    ret[key] = parent
      ? parent.concat(child)
      : Array.isArray(child) ? child : [child]
  }
  return ret
}
    function compile (
      template: string,
      options?: CompilerOptions
    ): CompiledResult {
      const finalOptions = Object.create(baseOptions)
      const errors = []
      const tips = []
      finalOptions.warn = (msg, tip) => {
        (tip ? tips : errors).push(msg)
      }

      if (options) {
        // merge custom modules
        if (options.modules) {
          finalOptions.modules =
            (baseOptions.modules || []).concat(options.modules)
        }
        // merge custom directives
        if (options.directives) {
          finalOptions.directives = extend(
            Object.create(baseOptions.directives || null),
            options.directives
          )
        }
        // copy other options
        for (const key in options) {
          if (key !== 'modules' && key !== 'directives') {
            finalOptions[key] = options[key]
          }
        }
      }

      const compiled = baseCompile(template, finalOptions)
      if (process.env.NODE_ENV !== 'production') {
        errors.push.apply(errors, detectErrors(compiled.ast))
      }
      compiled.errors = errors
      compiled.tips = tips
      return compiled
    }
Example #30
0
function updateDOMProps (oldVnode: VNodeWithData, vnode: VNodeWithData) {
  if (!oldVnode.data.domProps && !vnode.data.domProps) {
    return
  }
  let key, cur
  const elm: any = vnode.elm
  const oldProps = oldVnode.data.domProps || {}
  let props = vnode.data.domProps || {}
  // clone observed objects, as the user probably wants to mutate it
  if (props.__ob__) {
    props = vnode.data.domProps = extend({}, props)
  }

  for (key in oldProps) {
    if (props[key] == null) {
      elm[key] = undefined
    }
  }
  for (key in props) {
    // ignore children if the node has textContent or innerHTML,
    // as these will throw away existing DOM nodes and cause removal errors
    // on subsequent patches (#3360)
    if ((key === 'textContent' || key === 'innerHTML') && vnode.children) {
      vnode.children.length = 0
    }
    cur = props[key]
    if (key === 'value') {
      // store value as _value as well since
      // non-string values will be stringified
      elm._value = cur
      // avoid resetting cursor position when value is the same
      const strCur = cur == null ? '' : String(cur)
      if (elm.value !== strCur && !elm.composing) {
        elm.value = strCur
      }
    } else {
      elm[key] = cur
    }
  }
}