8889841centry-runtime-esm.ts000066600000000112150513723770010530 0ustar00import Vue from './runtime/index' export default Vue export * from 'v3' entry-runtime-with-compiler-esm.ts000066600000000122150513723770013312 0ustar00import Vue from './runtime-with-compiler' export default Vue export * from 'v3' util/index.ts000066600000000754150513723770007224 0ustar00import { 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) { __DEV__ && warn('Cannot find element: ' + el) return document.createElement('div') } return selected } else { return el } } util/attrs.ts000066600000003642150513723770007251 0ustar00import { makeMap } from 'shared/util' // these are reserved for web because they are directly compiled away // during template compilation export const isReservedAttr = makeMap('style,class') // attributes that should be using props for binding const acceptValue = makeMap('input,textarea,option,select,progress') export const mustUseProp = ( tag: string, type?: string | null, attr?: string ): boolean => { return ( (attr === 'value' && acceptValue(tag) && type !== 'button') || (attr === 'selected' && tag === 'option') || (attr === 'checked' && tag === 'input') || (attr === 'muted' && tag === 'video') ) } export const isEnumeratedAttr = makeMap('contenteditable,draggable,spellcheck') const isValidContentEditableValue = makeMap( 'events,caret,typing,plaintext-only' ) export const convertEnumeratedValue = (key: string, value: any) => { return isFalsyAttrValue(value) || value === 'false' ? 'false' : // allow arbitrary string value for contenteditable key === 'contenteditable' && isValidContentEditableValue(value) ? value : 'true' } export const isBooleanAttr = makeMap( 'allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,' + 'default,defaultchecked,defaultmuted,defaultselected,defer,disabled,' + 'enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,' + 'muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,' + 'required,reversed,scoped,seamless,selected,sortable,' + 'truespeed,typemustmatch,visible' ) export const xlinkNS = 'http://www.w3.org/1999/xlink' export const isXlink = (name: string): boolean => { return name.charAt(5) === ':' && name.slice(0, 5) === 'xlink' } export const getXlinkProp = (name: string): string => { return isXlink(name) ? name.slice(6, name.length) : '' } export const isFalsyAttrValue = (val: any): boolean => { return val == null || val === false } util/compat.ts000066600000001155150513723770007374 0ustar00import { 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 ? `` : `
` 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 util/class.ts000066600000004245150513723770007221 0ustar00import VNode from 'core/vdom/vnode' import { isDef, isObject } from 'shared/util' import type { VNodeData, VNodeWithData } from 'types/vnode' export function genClassForVnode(vnode: VNodeWithData): string { let data = vnode.data let parentNode: VNode | VNodeWithData | undefined = vnode let childNode: VNode | VNodeWithData = vnode while (isDef(childNode.componentInstance)) { childNode = childNode.componentInstance._vnode! if (childNode && childNode.data) { data = mergeClassData(childNode.data, data) } } // @ts-expect-error parentNode.parent not VNodeWithData 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 | null | undefined, dynamicClass: any ): string { if (isDef(staticClass) || isDef(dynamicClass)) { return concat(staticClass, stringifyClass(dynamicClass)) } /* istanbul ignore next */ return '' } export function concat(a?: string | null, b?: string | null): 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): 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 } util/style.ts000066600000004162150513723770007252 0ustar00import VNode from 'core/vdom/vnode' import { cached, extend, toObject } from 'shared/util' import type { VNodeData, VNodeWithData } from 'types/vnode' export const parseStyleText = cached(function (cssText) { const res = {} const listDelimiter = /;(?![^(]*\))/g const propertyDelimiter = /:(.+)/ cssText.split(listDelimiter).forEach(function (item) { if (item) { const tmp = item.split(propertyDelimiter) tmp.length > 1 && (res[tmp[0].trim()] = tmp[1].trim()) } }) return res }) // merge static and dynamic style data on the same vnode function normalizeStyleData(data: VNodeData): Record { 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 } // normalize possible array / string values into Object export function normalizeStyleBinding(bindingStyle: any): Record { if (Array.isArray(bindingStyle)) { return toObject(bindingStyle) } if (typeof bindingStyle === 'string') { return parseStyleText(bindingStyle) } return bindingStyle } /** * parent component style should be after child's * so that parent component's style could override it */ export function getStyle(vnode: VNodeWithData, checkChild: boolean): Object { const res = {} let styleData if (checkChild) { let childNode: VNodeWithData | VNode = vnode while (childNode.componentInstance) { childNode = childNode.componentInstance._vnode! if ( childNode && childNode.data && (styleData = normalizeStyleData(childNode.data)) ) { extend(res, styleData) } } } if ((styleData = normalizeStyleData(vnode.data))) { extend(res, styleData) } let parentNode: VNodeWithData | VNode | undefined = vnode // @ts-expect-error parentNode.parent not VNodeWithData while ((parentNode = parentNode.parent)) { if (parentNode.data && (styleData = normalizeStyleData(parentNode.data))) { extend(res, styleData) } } return res } util/element.ts000066600000005007150513723770007542 0ustar00import { 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 | undefined => { return isHTMLTag(tag) || isSVG(tag) } export function getTagNamespace(tag: string): string | undefined { 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' ) entry-compiler.ts000066600000000356150513723770010107 0ustar00export { parseComponent } from 'sfc/parseComponent' export { compile, compileToFunctions } from './compiler/index' export { ssrCompile, ssrCompileToFunctions } from 'server/compiler' export { generateCodeFrame } from 'compiler/codeframe' compiler/util.ts000066600000001605150513723770007723 0ustar00import { 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' ) compiler/index.ts000066600000000305150513723770010051 0ustar00import { baseOptions } from './options' import { createCompiler } from 'compiler/index' const { compile, compileToFunctions } = createCompiler(baseOptions) export { compile, compileToFunctions } compiler/modules/index.ts000066600000000172150513723770011523 0ustar00import klass from './class' import style from './style' import model from './model' export default [klass, style, model] compiler/modules/model.ts000066600000005225150513723770011520 0ustar00/** * Expand input[v-model] with dynamic type bindings into v-if-else chains * Turn this: * * into this: * * * */ import { addRawAttr, getBindingAttr, getAndRemoveAttr } from 'compiler/helpers' import { processFor, processElement, addIfCondition, createASTElement } from 'compiler/parser/index' import { ASTElement, CompilerOptions, ModuleOptions } from 'types/compiler' 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 } as ModuleOptions compiler/modules/class.ts000066600000002470150513723770011524 0ustar00import { parseText } from 'compiler/parser/text-parser' import { getAndRemoveAttr, getBindingAttr, baseWarn } from 'compiler/helpers' import { ASTElement, CompilerOptions, ModuleOptions } from 'types/compiler' function transformNode(el: ASTElement, options: CompilerOptions) { const warn = options.warn || baseWarn const staticClass = getAndRemoveAttr(el, 'class') if (__DEV__ && 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
, use
.', el.rawAttrsMap['class'] ) } } if (staticClass) { el.staticClass = JSON.stringify(staticClass.replace(/\s+/g, ' ').trim()) } 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 } as ModuleOptions compiler/modules/style.ts000066600000002605150513723770011557 0ustar00import { parseText } from 'compiler/parser/text-parser' import { parseStyleText } from 'web/util/style' import { getAndRemoveAttr, getBindingAttr, baseWarn } from 'compiler/helpers' import { ASTElement, CompilerOptions, ModuleOptions } from 'types/compiler' function transformNode(el: ASTElement, options: CompilerOptions) { const warn = options.warn || baseWarn const staticStyle = getAndRemoveAttr(el, 'style') if (staticStyle) { /* istanbul ignore if */ if (__DEV__) { 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
, use
.', el.rawAttrsMap['style'] ) } } 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 } as ModuleOptions compiler/directives/index.ts000066600000000174150513723770012216 0ustar00import model from './model' import text from './text' import html from './html' export default { model, text, html } compiler/directives/html.ts000066600000000367150513723770012057 0ustar00import { addProp } from 'compiler/helpers' import { ASTDirective, ASTElement } from 'types/compiler' export default function html(el: ASTElement, dir: ASTDirective) { if (dir.value) { addProp(el, 'innerHTML', `_s(${dir.value})`, dir) } } compiler/directives/model.ts000066600000013102150513723770012202 0ustar00import config from 'core/config' import { addHandler, addProp, getBindingAttr } from 'compiler/helpers' import { genComponentModel, genAssignmentCode } from 'compiler/directives/model' import { ASTDirective, ASTElement, ASTModifiers } from 'types/compiler' 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 | undefined { warn = _warn const value = dir.value const modifiers = dir.modifiers const tag = el.tag const type = el.attrsMap.type if (__DEV__) { // 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.`, el.rawAttrsMap['v-model'] ) } } 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 (__DEV__) { 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.', el.rawAttrsMap['v-model'] ) } // ensure runtime directive metadata return true } function genCheckboxModel( el: ASTElement, value: string, modifiers?: ASTModifiers | null ) { 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 | null ) { 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 | null ) { 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 | null ): boolean | void { const type = el.attrsMap.type // warn if v-bind:value conflicts with v-model // except for inputs with v-bind:type if (__DEV__) { 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', el.rawAttrsMap[binding] ) } } 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()') } } compiler/directives/text.ts000066600000000371150513723770012072 0ustar00import { addProp } from 'compiler/helpers' import { ASTDirective, ASTElement } from 'types/compiler' export default function text(el: ASTElement, dir: ASTDirective) { if (dir.value) { addProp(el, 'textContent', `_s(${dir.value})`, dir) } } compiler/options.ts000066600000001050150513723770010433 0ustar00import { 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' import { CompilerOptions } from 'types/compiler' export const baseOptions: CompilerOptions = { expectHTML: true, modules, directives, isPreTag, isUnaryTag, mustUseProp, canBeLeftOpenTag, isReservedTag, getTagNamespace, staticKeys: genStaticKeys(modules) } runtime-with-compiler.ts000066600000005512150513723770011401 0ustar00import config from 'core/config' import { warn, cached } from 'core/util/index' import { mark, measure } from 'core/util/perf' import Vue from './runtime/index' import { query } from './util/index' import { compileToFunctions } from './compiler/index' import { shouldDecodeNewlines, shouldDecodeNewlinesForHref } from './util/compat' import type { Component } from 'types/component' import type { GlobalAPI } from 'types/global-api' const idToTemplate = cached(id => { const el = query(id) return el && el.innerHTML }) const mount = Vue.prototype.$mount Vue.prototype.$mount = function ( el?: string | Element, hydrating?: boolean ): Component { el = el && query(el) /* istanbul ignore if */ if (el === document.body || el === document.documentElement) { __DEV__ && warn( `Do not mount Vue to or - mount to normal elements instead.` ) return this } const options = this.$options // resolve template/el and convert to render function if (!options.render) { let template = options.template if (template) { if (typeof template === 'string') { if (template.charAt(0) === '#') { template = idToTemplate(template) /* istanbul ignore if */ if (__DEV__ && !template) { warn( `Template element not found or is empty: ${options.template}`, this ) } } } else if (template.nodeType) { template = template.innerHTML } else { if (__DEV__) { warn('invalid template option:' + template, this) } return this } } else if (el) { // @ts-expect-error template = getOuterHTML(el) } if (template) { /* istanbul ignore if */ if (__DEV__ && config.performance && mark) { mark('compile') } const { render, staticRenderFns } = compileToFunctions( template, { outputSourceRange: __DEV__, shouldDecodeNewlines, shouldDecodeNewlinesForHref, delimiters: options.delimiters, comments: options.comments }, this ) options.render = render options.staticRenderFns = staticRenderFns /* istanbul ignore if */ if (__DEV__ && config.performance && mark) { mark('compile end') measure(`vue ${this._name} compile`, 'compile', 'compile end') } } } return mount.call(this, el, hydrating) } /** * Get outerHTML of elements, taking care * of SVG elements in IE as well. */ function getOuterHTML(el: Element): string { if (el.outerHTML) { return el.outerHTML } else { const container = document.createElement('div') container.appendChild(el.cloneNode(true)) return container.innerHTML } } Vue.compile = compileToFunctions export default Vue as GlobalAPI entry-runtime.ts000066600000000207150513723770007753 0ustar00import Vue from './runtime/index' import * as vca from 'v3' import { extend } from 'shared/util' extend(Vue, vca) export default Vue runtime/class-util.ts000066600000002671150513723770010703 0ustar00const whitespaceRE = /\s+/ /** * Add class with compatibility for SVG since classList is not supported on * SVG elements in IE */ export function addClass(el: HTMLElement, cls?: string) { /* istanbul ignore if */ if (!cls || !(cls = cls.trim())) { return } /* istanbul ignore else */ if (el.classList) { if (cls.indexOf(' ') > -1) { cls.split(whitespaceRE).forEach(c => el.classList.add(c)) } else { el.classList.add(cls) } } else { const cur = ` ${el.getAttribute('class') || ''} ` if (cur.indexOf(' ' + cls + ' ') < 0) { el.setAttribute('class', (cur + cls).trim()) } } } /** * Remove class with compatibility for SVG since classList is not supported on * SVG elements in IE */ export function removeClass(el: HTMLElement, cls?: string) { /* istanbul ignore if */ if (!cls || !(cls = cls.trim())) { return } /* istanbul ignore else */ if (el.classList) { if (cls.indexOf(' ') > -1) { cls.split(whitespaceRE).forEach(c => el.classList.remove(c)) } else { el.classList.remove(cls) } if (!el.classList.length) { el.removeAttribute('class') } } else { let cur = ` ${el.getAttribute('class') || ''} ` const tar = ' ' + cls + ' ' while (cur.indexOf(tar) >= 0) { cur = cur.replace(tar, ' ') } cur = cur.trim() if (cur) { el.setAttribute('class', cur) } else { el.removeAttribute('class') } } } runtime/index.ts000066600000004220150513723770007722 0ustar00import Vue from 'core/index' import config from 'core/config' import { extend, noop } from 'shared/util' import { mountComponent } from 'core/instance/lifecycle' import { devtools, inBrowser } from 'core/util/index' import { query, mustUseProp, isReservedTag, isReservedAttr, getTagNamespace, isUnknownElement } from 'web/util/index' import { patch } from './patch' import platformDirectives from './directives/index' import platformComponents from './components/index' import type { Component } from 'types/component' // install platform specific utils Vue.config.mustUseProp = mustUseProp Vue.config.isReservedTag = isReservedTag Vue.config.isReservedAttr = isReservedAttr Vue.config.getTagNamespace = getTagNamespace Vue.config.isUnknownElement = isUnknownElement // install platform runtime directives & components extend(Vue.options.directives, platformDirectives) extend(Vue.options.components, platformComponents) // install platform patch function Vue.prototype.__patch__ = inBrowser ? patch : noop // public mount method Vue.prototype.$mount = function ( el?: string | Element, hydrating?: boolean ): Component { el = el && inBrowser ? query(el) : undefined return mountComponent(this, el, hydrating) } // devtools global hook /* istanbul ignore next */ if (inBrowser) { setTimeout(() => { if (config.devtools) { if (devtools) { devtools.emit('init', Vue) } else if (__DEV__ && process.env.NODE_ENV !== 'test') { // @ts-expect-error console[console.info ? 'info' : 'log']( 'Download the Vue Devtools extension for a better development experience:\n' + 'https://github.com/vuejs/vue-devtools' ) } } if ( __DEV__ && process.env.NODE_ENV !== 'test' && config.productionTip !== false && typeof console !== 'undefined' ) { // @ts-expect-error console[console.info ? 'info' : 'log']( `You are running Vue in development mode.\n` + `Make sure to turn on production mode when deploying for production.\n` + `See more tips at https://vuejs.org/guide/deployment.html` ) } }, 0) } export default Vue runtime/components/index.ts000066600000000213150513723770012105 0ustar00import Transition from './transition' import TransitionGroup from './transition-group' export default { Transition, TransitionGroup } runtime/components/transition.ts000066600000013245150513723770013201 0ustar00// Provides transition support for a single element/component. // supports transition mode (out-in / in-out) import { warn } from 'core/util/index' import { camelize, extend, isPrimitive } from 'shared/util' import { mergeVNodeHook, isAsyncPlaceholder, getFirstComponentChild } from 'core/vdom/helpers/index' import VNode from 'core/vdom/vnode' import type { Component } from 'types/component' export const transitionProps = { name: String, appear: Boolean, css: Boolean, mode: String, type: String, enterClass: String, leaveClass: String, enterToClass: String, leaveToClass: String, enterActiveClass: String, leaveActiveClass: String, appearClass: String, appearActiveClass: String, appearToClass: String, duration: [Number, String, Object] } // in case the child is also an abstract component, e.g. // we want to recursively retrieve the real component to be rendered function getRealChild(vnode?: VNode): VNode | undefined { const compOptions = vnode && vnode.componentOptions if (compOptions && compOptions.Ctor.options.abstract) { return getRealChild(getFirstComponentChild(compOptions.children)) } else { return vnode } } export function extractTransitionData(comp: Component): Record { const data = {} const options = comp.$options // props for (const key in options.propsData) { data[key] = comp[key] } // events. // extract listeners and pass them directly to the transition methods const listeners = options._parentListeners for (const key in listeners) { data[camelize(key)] = listeners[key] } return data } function placeholder(h: Function, rawChild: VNode): VNode | undefined { // @ts-expect-error if (/\d-keep-alive$/.test(rawChild.tag)) { return h('keep-alive', { props: rawChild.componentOptions!.propsData }) } } function hasParentTransition(vnode: VNode): boolean | undefined { while ((vnode = vnode.parent!)) { if (vnode.data!.transition) { return true } } } function isSameChild(child: VNode, oldChild: VNode): boolean { return oldChild.key === child.key && oldChild.tag === child.tag } const isNotTextNode = (c: VNode) => c.tag || isAsyncPlaceholder(c) const isVShowDirective = d => d.name === 'show' export default { name: 'transition', props: transitionProps, abstract: true, render(h: Function) { let children: any = this.$slots.default if (!children) { return } // filter out text nodes (possible whitespaces) children = children.filter(isNotTextNode) /* istanbul ignore if */ if (!children.length) { return } // warn multiple elements if (__DEV__ && children.length > 1) { warn( ' can only be used on a single element. Use ' + ' for lists.', this.$parent ) } const mode: string = this.mode // warn invalid mode if (__DEV__ && mode && mode !== 'in-out' && mode !== 'out-in') { warn('invalid mode: ' + mode, this.$parent) } const rawChild: VNode = children[0] // if this is a component root node and the component's // parent container node also has transition, skip. if (hasParentTransition(this.$vnode)) { return rawChild } // apply transition data to child // use getRealChild() to ignore abstract components e.g. keep-alive const child = getRealChild(rawChild) /* istanbul ignore if */ if (!child) { return rawChild } if (this._leaving) { return placeholder(h, rawChild) } // ensure a key that is unique to the vnode type and to this transition // component instance. This key will be used to remove pending leaving nodes // during entering. const id: string = `__transition-${this._uid}-` child.key = child.key == null ? child.isComment ? id + 'comment' : id + child.tag : isPrimitive(child.key) ? String(child.key).indexOf(id) === 0 ? child.key : id + child.key : child.key const data: Object = ((child.data || (child.data = {})).transition = extractTransitionData(this)) const oldRawChild: VNode = this._vnode const oldChild = getRealChild(oldRawChild) // mark v-show // so that the transition module can hand over the control to the directive if (child.data.directives && child.data.directives.some(isVShowDirective)) { child.data.show = true } if ( oldChild && oldChild.data && !isSameChild(child, oldChild) && !isAsyncPlaceholder(oldChild) && // #6687 component root is a comment node !( oldChild.componentInstance && oldChild.componentInstance._vnode!.isComment ) ) { // replace old child transition data with fresh one // important for dynamic transitions! const oldData: Object = (oldChild.data.transition = extend({}, data)) // handle transition mode if (mode === 'out-in') { // return placeholder node and queue update when leave finishes this._leaving = true mergeVNodeHook(oldData, 'afterLeave', () => { this._leaving = false this.$forceUpdate() }) return placeholder(h, rawChild) } else if (mode === 'in-out') { if (isAsyncPlaceholder(child)) { return oldRawChild } let delayedLeave const performLeave = () => { delayedLeave() } mergeVNodeHook(data, 'afterEnter', performLeave) mergeVNodeHook(data, 'enterCancelled', performLeave) mergeVNodeHook(oldData, 'delayLeave', leave => { delayedLeave = leave }) } } return rawChild } } runtime/components/transition-group.ts000066600000014311150513723770014326 0ustar00// Provides transition support for list items. // supports move transitions using the FLIP technique. // Because the vdom's children update algorithm is "unstable" - i.e. // it doesn't guarantee the relative positioning of removed elements, // we force transition-group to update its children into two passes: // in the first pass, we remove all nodes that need to be removed, // triggering their leaving transition; in the second pass, we insert/move // into the final desired state. This way in the second pass removed // nodes will remain where they should be. import { warn, extend } from 'core/util/index' import { addClass, removeClass } from 'web/runtime/class-util' import { transitionProps, extractTransitionData } from './transition' import { setActiveInstance } from 'core/instance/lifecycle' import { hasTransition, getTransitionInfo, transitionEndEvent, addTransitionClass, removeTransitionClass } from 'web/runtime/transition-util' import VNode from 'core/vdom/vnode' import { VNodeWithData } from 'types/vnode' import { getComponentName } from 'core/vdom/create-component' const props = extend( { tag: String, moveClass: String }, transitionProps ) delete props.mode export default { props, beforeMount() { const update = this._update this._update = (vnode, hydrating) => { const restoreActiveInstance = setActiveInstance(this) // force removing pass this.__patch__( this._vnode, this.kept, false, // hydrating true // removeOnly (!important, avoids unnecessary moves) ) this._vnode = this.kept restoreActiveInstance() update.call(this, vnode, hydrating) } }, render(h: Function) { const tag: string = this.tag || this.$vnode.data.tag || 'span' const map: Record = Object.create(null) const prevChildren: Array = (this.prevChildren = this.children) const rawChildren: Array = this.$slots.default || [] const children: Array = (this.children = []) const transitionData = extractTransitionData(this) for (let i = 0; i < rawChildren.length; i++) { const c: VNode = 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 (__DEV__) { const opts = c.componentOptions const name: string = opts ? getComponentName(opts.Ctor.options as any) || opts.tag || '' : c.tag warn(` children must be keyed: <${name}>`) } } } if (prevChildren) { const kept: Array = [] const removed: Array = [] for (let i = 0; i < prevChildren.length; i++) { const c: VNode = prevChildren[i] c.data!.transition = transitionData // @ts-expect-error .getBoundingClientRect is not typed in Node c.data!.pos = c.elm.getBoundingClientRect() 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) }, updated() { const children: Array = this.prevChildren const moveClass: string = this.moveClass || (this.name || 'v') + '-move' if (!children.length || !this.hasMove(children[0].elm, moveClass)) { return } // we divide the work into three loops to avoid mixing DOM reads and writes // in each iteration - which helps prevent layout thrashing. children.forEach(callPendingCbs) children.forEach(recordPosition) children.forEach(applyTranslation) // force reflow to put everything in position // assign to this to avoid being removed in tree-shaking // $flow-disable-line this._reflow = document.body.offsetHeight children.forEach((c: VNode) => { if (c.data!.moved) { const el: any = c.elm const s: any = el.style addTransitionClass(el, moveClass) s.transform = s.WebkitTransform = s.transitionDuration = '' el.addEventListener( transitionEndEvent, (el._moveCb = function cb(e) { if (e && e.target !== el) { return } if (!e || /transform$/.test(e.propertyName)) { el.removeEventListener(transitionEndEvent, cb) el._moveCb = null removeTransitionClass(el, moveClass) } }) ) } }) }, methods: { hasMove(el: any, moveClass: string): boolean { /* istanbul ignore if */ if (!hasTransition) { return false } /* istanbul ignore if */ if (this._hasMove) { return this._hasMove } // Detect whether an element with the move class applied has // CSS transitions. Since the element may be inside an entering // transition at this very moment, we make a clone of it and remove // all other transition classes applied to ensure only the move class // is applied. const clone: HTMLElement = el.cloneNode() if (el._transitionClasses) { el._transitionClasses.forEach((cls: string) => { removeClass(clone, cls) }) } addClass(clone, moveClass) clone.style.display = 'none' this.$el.appendChild(clone) const info: any = getTransitionInfo(clone) this.$el.removeChild(clone) return (this._hasMove = info.hasTransform) } } } function callPendingCbs( c: VNodeWithData & { elm?: { _moveCb?: Function; _enterCb?: Function } } ) { /* istanbul ignore if */ if (c.elm!._moveCb) { c.elm!._moveCb() } /* istanbul ignore if */ if (c.elm!._enterCb) { c.elm!._enterCb() } } function recordPosition(c: VNodeWithData) { c.data!.newPos = c.elm.getBoundingClientRect() } function applyTranslation(c: VNodeWithData) { 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 const s = c.elm.style s.transform = s.WebkitTransform = `translate(${dx}px,${dy}px)` s.transitionDuration = '0s' } } runtime/node-ops.ts000066600000003002150513723770010334 0ustar00import VNode from 'core/vdom/vnode' 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) { return node.parentNode } export function nextSibling(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, '') } runtime/transition-util.ts000066600000013046150513723770011766 0ustar00import { inBrowser, isIE9 } from 'core/util/index' import { addClass, removeClass } from 'web/runtime/class-util' import { remove, extend, cached } from 'shared/util' export function resolveTransition( def?: string | Record ): Record | undefined { 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) } } const autoCssTransition: (name: string) => Object = cached(name => { return { enterClass: `${name}-enter`, enterToClass: `${name}-enter-to`, enterActiveClass: `${name}-enter-active`, leaveClass: `${name}-leave`, leaveToClass: `${name}-leave-to`, leaveActiveClass: `${name}-leave-active` } }) export const hasTransition = inBrowser && !isIE9 const TRANSITION = 'transition' const ANIMATION = 'animation' // Transition property/event sniffing export let transitionProp = 'transition' export let transitionEndEvent = 'transitionend' export let animationProp = 'animation' export let animationEndEvent = 'animationend' if (hasTransition) { /* istanbul ignore if */ if ( window.ontransitionend === undefined && window.onwebkittransitionend !== undefined ) { transitionProp = 'WebkitTransition' transitionEndEvent = 'webkitTransitionEnd' } if ( window.onanimationend === undefined && window.onwebkitanimationend !== undefined ) { animationProp = 'WebkitAnimation' animationEndEvent = 'webkitAnimationEnd' } } // binding to window is necessary to make hot reload work in IE in strict mode const raf = inBrowser ? window.requestAnimationFrame ? window.requestAnimationFrame.bind(window) : setTimeout : /* istanbul ignore next */ fn => fn() export function nextFrame(fn: Function) { raf(() => { // @ts-expect-error raf(fn) }) } export function addTransitionClass(el: any, cls: string) { const transitionClasses = el._transitionClasses || (el._transitionClasses = []) if (transitionClasses.indexOf(cls) < 0) { transitionClasses.push(cls) addClass(el, cls) } } export function removeTransitionClass(el: any, cls: string) { if (el._transitionClasses) { remove(el._transitionClasses, cls) } removeClass(el, cls) } export function whenTransitionEnds( el: Element, expectedType: string | undefined, cb: Function ) { const { type, timeout, propCount } = getTransitionInfo(el, expectedType) if (!type) return cb() const event: string = type === TRANSITION ? transitionEndEvent : animationEndEvent let ended = 0 const end = () => { el.removeEventListener(event, onEnd) cb() } const onEnd = e => { if (e.target === el) { if (++ended >= propCount) { end() } } } setTimeout(() => { if (ended < propCount) { end() } }, timeout + 1) el.addEventListener(event, onEnd) } const transformRE = /\b(transform|all)(,|$)/ export function getTransitionInfo( el: Element, expectedType?: string ): { type?: string | null propCount: number timeout: number hasTransform: boolean } { const styles: any = window.getComputedStyle(el) // JSDOM may return undefined for transition properties const transitionDelays: Array = ( styles[transitionProp + 'Delay'] || '' ).split(', ') const transitionDurations: Array = ( styles[transitionProp + 'Duration'] || '' ).split(', ') const transitionTimeout: number = getTimeout( transitionDelays, transitionDurations ) const animationDelays: Array = ( styles[animationProp + 'Delay'] || '' ).split(', ') const animationDurations: Array = ( styles[animationProp + 'Duration'] || '' ).split(', ') const animationTimeout: number = getTimeout( animationDelays, animationDurations ) let type: string | undefined | null let timeout = 0 let propCount = 0 /* istanbul ignore if */ if (expectedType === TRANSITION) { if (transitionTimeout > 0) { type = TRANSITION timeout = transitionTimeout propCount = transitionDurations.length } } else if (expectedType === ANIMATION) { if (animationTimeout > 0) { type = ANIMATION timeout = animationTimeout propCount = animationDurations.length } } else { timeout = Math.max(transitionTimeout, animationTimeout) type = timeout > 0 ? transitionTimeout > animationTimeout ? TRANSITION : ANIMATION : null propCount = type ? type === TRANSITION ? transitionDurations.length : animationDurations.length : 0 } const hasTransform: boolean = type === TRANSITION && transformRE.test(styles[transitionProp + 'Property']) return { type, timeout, propCount, hasTransform } } function getTimeout(delays: Array, durations: Array): number { /* istanbul ignore next */ while (delays.length < durations.length) { delays = delays.concat(delays) } return Math.max.apply( null, durations.map((d, i) => { return toMs(d) + toMs(delays[i]) }) ) } // Old versions of Chromium (below 61.0.3163.100) formats floating pointer numbers // in a locale-dependent way, using a comma instead of a dot. // If comma is not replaced with a dot, the input will be rounded down (i.e. acting // as a floor function) causing unexpected behaviors function toMs(s: string): number { return Number(s.slice(0, -1).replace(',', '.')) * 1000 } runtime/modules/dom-props.ts000066600000007633150513723770012216 0ustar00import { isDef, isUndef, extend, toNumber, isTrue } from 'shared/util' import type { VNodeWithData } from 'types/vnode' import { isSVG } from 'web/util/index' let svgContainer 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__) || isTrue(props._v_attr_proxy)) { props = vnode.data.domProps = extend({}, props) } for (key in oldProps) { if (!(key in props)) { 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 // #6601 work around Chrome version <= 55 bug where single textNode // replaced by innerHTML/textContent retains its parentNode property if (elm.childNodes.length === 1) { elm.removeChild(elm.childNodes[0]) } } if (key === 'value' && elm.tagName !== 'PROGRESS') { // 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, strCur)) { elm.value = strCur } } else if ( key === 'innerHTML' && isSVG(elm.tagName) && isUndef(elm.innerHTML) ) { // IE doesn't support innerHTML for SVG elements svgContainer = svgContainer || document.createElement('div') svgContainer.innerHTML = `${cur}` const svg = svgContainer.firstChild while (elm.firstChild) { elm.removeChild(elm.firstChild) } while (svg.firstChild) { elm.appendChild(svg.firstChild) } } else if ( // skip the update if old and new VDOM state is the same. // `value` is handled separately because the DOM value may be temporarily // out of sync with VDOM state due to focus, composition and modifiers. // This #4521 by skipping the unnecessary `checked` update. cur !== oldProps[key] ) { // some property updates can throw // e.g. `value` on w/ non-finite value try { elm[key] = cur } catch (e: any) {} } } } // check platforms/web/util/attrs.js acceptValue type acceptValueElm = HTMLInputElement | HTMLSelectElement | HTMLOptionElement function shouldUpdateValue(elm: acceptValueElm, checkVal: string): boolean { return ( //@ts-expect-error !elm.composing && (elm.tagName === 'OPTION' || isNotInFocusAndDirty(elm, checkVal) || isDirtyWithModifiers(elm, checkVal)) ) } function isNotInFocusAndDirty(elm: acceptValueElm, checkVal: string): boolean { // return true when textbox (.number and .trim) loses focus and its value is // not equal to the updated value let notInFocus = true // #6157 // work around IE bug when accessing document.activeElement in an iframe try { notInFocus = document.activeElement !== elm } catch (e: any) {} return notInFocus && elm.value !== checkVal } function isDirtyWithModifiers(elm: any, newVal: string): boolean { const value = elm.value const modifiers = elm._vModifiers // injected by v-model runtime if (isDef(modifiers)) { if (modifiers.number) { return toNumber(value) !== toNumber(newVal) } if (modifiers.trim) { return value.trim() !== newVal.trim() } } return value !== newVal } export default { create: updateDOMProps, update: updateDOMProps } runtime/modules/index.ts000066600000000377150513723770011403 0ustar00import 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] runtime/modules/attrs.ts000066600000006367150513723770011436 0ustar00import { isIE, isIE9, isEdge } from 'core/util/env' import { extend, isDef, isUndef, isTrue } from 'shared/util' import type { VNodeWithData } from 'types/vnode' import { isXlink, xlinkNS, getXlinkProp, isBooleanAttr, isEnumeratedAttr, isFalsyAttrValue, convertEnumeratedValue } from 'web/util/index' function updateAttrs(oldVnode: VNodeWithData, vnode: VNodeWithData) { const opts = vnode.componentOptions if (isDef(opts) && opts.Ctor.options.inheritAttrs === false) { return } 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__) || isTrue(attrs._v_attr_proxy)) { attrs = vnode.data.attrs = extend({}, attrs) } for (key in attrs) { cur = attrs[key] old = oldAttrs[key] if (old !== cur) { setAttr(elm, key, cur, vnode.data.pre) } } // #4391: in IE9, setting type can reset value for input[type=radio] // #6666: IE/Edge forces progress value down to 1 before setting a max /* istanbul ignore if */ if ((isIE || isEdge) && 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) } } } } function setAttr(el: Element, key: string, value: any, isInPre?: any) { if (isInPre || el.tagName.indexOf('-') > -1) { baseSetAttr(el, key, value) } else if (isBooleanAttr(key)) { // set attribute for blank value // e.g. if (isFalsyAttrValue(value)) { el.removeAttribute(key) } else { // technically allowfullscreen is a boolean attribute for