diff options
Diffstat (limited to 'node_modules/vue/src/platforms/web/runtime/directives')
3 files changed, 214 insertions, 0 deletions
diff --git a/node_modules/vue/src/platforms/web/runtime/directives/index.js b/node_modules/vue/src/platforms/web/runtime/directives/index.js new file mode 100644 index 00000000..b673f11a --- /dev/null +++ b/node_modules/vue/src/platforms/web/runtime/directives/index.js @@ -0,0 +1,7 @@ +import model from './model' +import show from './show' + +export default { + model, + show +} diff --git a/node_modules/vue/src/platforms/web/runtime/directives/model.js b/node_modules/vue/src/platforms/web/runtime/directives/model.js new file mode 100644 index 00000000..cba8ded0 --- /dev/null +++ b/node_modules/vue/src/platforms/web/runtime/directives/model.js @@ -0,0 +1,147 @@ +/** + * 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 + 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)) { + process.env.NODE_ENV !== 'production' && warn( + `<select multiple v-model="${binding.expression}"> ` + + `expects an Array value for its binding, but got ${ + Object.prototype.toString.call(value).slice(8, -1) + }`, + vm + ) + return + } + let selected, option + for (let i = 0, l = el.options.length; i < l; i++) { + option = el.options[i] + if (isMultiple) { + selected = looseIndexOf(value, getValue(option)) > -1 + if (option.selected !== selected) { + option.selected = selected + } + } else { + if (looseEqual(getValue(option), value)) { + if (el.selectedIndex !== i) { + el.selectedIndex = i + } + return + } + } + } + if (!isMultiple) { + el.selectedIndex = -1 + } +} + +function hasNoMatchingOption (value, options) { + return options.every(o => !looseEqual(o, value)) +} + +function getValue (option) { + return '_value' in option + ? option._value + : option.value +} + +function onCompositionStart (e) { + e.target.composing = true +} + +function onCompositionEnd (e) { + // prevent triggering an input event for no reason + if (!e.target.composing) return + e.target.composing = false + trigger(e.target, 'input') +} + +function trigger (el, type) { + const e = document.createEvent('HTMLEvents') + e.initEvent(type, true, true) + el.dispatchEvent(e) +} + +export default directive diff --git a/node_modules/vue/src/platforms/web/runtime/directives/show.js b/node_modules/vue/src/platforms/web/runtime/directives/show.js new file mode 100644 index 00000000..17fb5dec --- /dev/null +++ b/node_modules/vue/src/platforms/web/runtime/directives/show.js @@ -0,0 +1,60 @@ +/* @flow */ + +import { enter, leave } from '../modules/transition' + +// recursively search for possible transition defined inside the component root +function locateNode (vnode: VNode): VNodeWithData { + return vnode.componentInstance && (!vnode.data || !vnode.data.transition) + ? locateNode(vnode.componentInstance._vnode) + : vnode +} + +export default { + bind (el: any, { value }: VNodeDirective, vnode: VNodeWithData) { + vnode = locateNode(vnode) + const transition = vnode.data && vnode.data.transition + const originalDisplay = el.__vOriginalDisplay = + el.style.display === 'none' ? '' : el.style.display + if (value && transition) { + vnode.data.show = true + enter(vnode, () => { + el.style.display = originalDisplay + }) + } else { + el.style.display = value ? originalDisplay : 'none' + } + }, + + update (el: any, { value, oldValue }: VNodeDirective, vnode: VNodeWithData) { + /* istanbul ignore if */ + if (!value === !oldValue) return + vnode = locateNode(vnode) + const transition = vnode.data && vnode.data.transition + if (transition) { + vnode.data.show = true + if (value) { + enter(vnode, () => { + el.style.display = el.__vOriginalDisplay + }) + } else { + leave(vnode, () => { + el.style.display = 'none' + }) + } + } else { + el.style.display = value ? el.__vOriginalDisplay : 'none' + } + }, + + unbind ( + el: any, + binding: VNodeDirective, + vnode: VNodeWithData, + oldVnode: VNodeWithData, + isDestroy: boolean + ) { + if (!isDestroy) { + el.style.display = el.__vOriginalDisplay + } + } +} |
