import { 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 || {}
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]
if (key === 'textContent' || key === 'innerHTML') {
if (vnode.children) vnode.children.length = 0
if (cur === oldProps[key]) continue
if (elm.childNodes.length === 1) {
elm.removeChild(elm.childNodes[0])
}
}
if (key === 'value' && elm.tagName !== 'PROGRESS') {
elm._value = cur
const strCur = isUndef(cur) ? '' : String(cur)
if (shouldUpdateValue(elm, strCur)) {
elm.value = strCur
}
} else if (
key === 'innerHTML' &&
isSVG(elm.tagName) &&
isUndef(elm.innerHTML)
) {
svgContainer = svgContainer || document.createElement('div')
svgContainer.innerHTML = `<svg>${cur}</svg>`
const svg = svgContainer.firstChild
while (elm.firstChild) {
elm.removeChild(elm.firstChild)
}
while (svg.firstChild) {
elm.appendChild(svg.firstChild)
}
} else if (
cur !== oldProps[key]
) {
try {
elm[key] = cur
} catch (e: any) {}
}
}
}
type acceptValueElm = HTMLInputElement | HTMLSelectElement | HTMLOptionElement
function shouldUpdateValue(elm: acceptValueElm, checkVal: string): boolean {
return (
!elm.composing &&
(elm.tagName === 'OPTION' ||
isNotInFocusAndDirty(elm, checkVal) ||
isDirtyWithModifiers(elm, checkVal))
)
}
function isNotInFocusAndDirty(elm: acceptValueElm, checkVal: string): boolean {
let notInFocus = true
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
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
}