| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119 |
- /* @flow */
- import { isIE, isIE9, isEdge } from 'core/util/env'
- import {
- extend,
- isDef,
- isUndef
- } from 'shared/util'
- 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__)) {
- 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]
- // #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) {
- if (el.tagName.indexOf('-') > -1) {
- baseSetAttr(el, key, value)
- } else if (isBooleanAttr(key)) {
- // set attribute for blank value
- // e.g. <option disabled>Select one</option>
- if (isFalsyAttrValue(value)) {
- el.removeAttribute(key)
- } else {
- // technically allowfullscreen is a boolean attribute for <iframe>,
- // but Flash expects a value of "true" when used on <embed> tag
- value = key === 'allowfullscreen' && el.tagName === 'EMBED'
- ? 'true'
- : key
- el.setAttribute(key, value)
- }
- } else if (isEnumeratedAttr(key)) {
- el.setAttribute(key, convertEnumeratedValue(key, value))
- } else if (isXlink(key)) {
- if (isFalsyAttrValue(value)) {
- el.removeAttributeNS(xlinkNS, getXlinkProp(key))
- } else {
- el.setAttributeNS(xlinkNS, key, value)
- }
- } else {
- baseSetAttr(el, key, value)
- }
- }
- function baseSetAttr (el, key, value) {
- if (isFalsyAttrValue(value)) {
- el.removeAttribute(key)
- } else {
- // #7138: IE10 & 11 fires input event when setting placeholder on
- // <textarea>... block the first input event and remove the blocker
- // immediately.
- /* istanbul ignore if */
- if (
- isIE && !isIE9 &&
- el.tagName === 'TEXTAREA' &&
- key === 'placeholder' && value !== '' && !el.__ieph
- ) {
- const blocker = e => {
- e.stopImmediatePropagation()
- el.removeEventListener('input', blocker)
- }
- el.addEventListener('input', blocker)
- // $flow-disable-line
- el.__ieph = true /* IE placeholder patched */
- }
- el.setAttribute(key, value)
- }
- }
- export default {
- create: updateAttrs,
- update: updateAttrs
- }
|