/** * Not type checking this file because flow doesn't like attaching * properties to Elements. */ import { isTextInputType } from 'web/util/element' import { looseEqual, looseIndexOf } from 'shared/util' import { mergeVNodeHook } from 'core/vdom/helpers/index' import { warn, isIE9, isIE, isEdge } from 'core/util/index' /* istanbul ignore if */ if (isIE9) { // http://www.matts411.com/post/internet-explorer-9-oninput/ document.addEventListener('selectionchange', () => { const el = document.activeElement // @ts-expect-error if (el && el.vmodel) { trigger(el, 'input') } }) } const directive = { inserted(el, binding, vnode, oldVnode) { if (vnode.tag === 'select') { // #6903 if (oldVnode.elm && !oldVnode.elm._vOptions) { mergeVNodeHook(vnode, 'postpatch', () => { directive.componentUpdated(el, binding, vnode) }) } else { setSelected(el, binding, vnode.context) } el._vOptions = [].map.call(el.options, getValue) } else if (vnode.tag === 'textarea' || isTextInputType(el.type)) { el._vModifiers = binding.modifiers if (!binding.modifiers.lazy) { el.addEventListener('compositionstart', onCompositionStart) el.addEventListener('compositionend', onCompositionEnd) // Safari < 10.2 & UIWebView doesn't fire compositionend when // switching focus before confirming composition choice // this also fixes the issue where some browsers e.g. iOS Chrome // fires "change" instead of "input" on autocomplete. el.addEventListener('change', onCompositionEnd) /* istanbul ignore if */ if (isIE9) { el.vmodel = true } } } }, componentUpdated(el, binding, vnode) { if (vnode.tag === 'select') { setSelected(el, binding, vnode.context) // in case the options rendered by v-for have changed, // it's possible that the value is out-of-sync with the rendered options. // detect such cases and filter out values that no longer has a matching // option in the DOM. const prevOptions = el._vOptions const curOptions = (el._vOptions = [].map.call(el.options, getValue)) if (curOptions.some((o, i) => !looseEqual(o, prevOptions[i]))) { // trigger change event if // no matching option found for at least one value const needReset = el.multiple ? binding.value.some(v => hasNoMatchingOption(v, curOptions)) : binding.value !== binding.oldValue && hasNoMatchingOption(binding.value, curOptions) if (needReset) { trigger(el, 'change') } } } } } function setSelected(el, binding, vm) { actuallySetSelected(el, binding, vm) /* istanbul ignore if */ if (isIE || isEdge) { setTimeout(() => { actuallySetSelected(el, binding, vm) }, 0) } } function actuallySetSelected(el, binding, vm) { const value = binding.value const isMultiple = el.multiple if (isMultiple && !Array.isArray(value)) { __DEV__ && warn( `