UNPKG

uiv

Version:

Bootstrap 3 components implemented by Vue 2.

272 lines (260 loc) 8.06 kB
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Polyfill function isBoolean (obj) { return typeof obj === 'boolean' } var EVENTS = { MOUSE_ENTER: 'mouseenter', MOUSE_LEAVE: 'mouseleave', MOUSE_DOWN: 'mousedown', MOUSE_UP: 'mouseup', FOCUS: 'focus', BLUR: 'blur', CLICK: 'click', INPUT: 'input', KEY_DOWN: 'keydown', KEY_UP: 'keyup', KEY_PRESS: 'keypress', RESIZE: 'resize', SCROLL: 'scroll', TOUCH_START: 'touchstart', TOUCH_END: 'touchend' }; function on (element, event, handler) { /* istanbul ignore next */ element.addEventListener(event, handler); } function off (element, event, handler) { /* istanbul ignore next */ element.removeEventListener(event, handler); } function isElement (el) { return el && el.nodeType === Node.ELEMENT_NODE } function setDropdownPosition (dropdown, trigger, options) { if ( options === void 0 ) options = {}; var doc = document.documentElement; var containerScrollLeft = (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0); var containerScrollTop = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0); var rect = trigger.getBoundingClientRect(); var dropdownRect = dropdown.getBoundingClientRect(); dropdown.style.right = 'auto'; dropdown.style.bottom = 'auto'; if (options.menuRight) { dropdown.style.left = containerScrollLeft + rect.left + rect.width - dropdownRect.width + 'px'; } else { dropdown.style.left = containerScrollLeft + rect.left + 'px'; } if (options.dropup) { dropdown.style.top = containerScrollTop + rect.top - dropdownRect.height - 4 + 'px'; } else { dropdown.style.top = containerScrollTop + rect.top + rect.height + 'px'; } } function focus (el) { if (!isElement(el)) { return } el.getAttribute('tabindex') ? null : el.setAttribute('tabindex', '-1'); el.focus(); } var DEFAULT_TAG = 'div'; var Dropdown = { render: function render (h) { return h( this.tag, { class: { 'btn-group': this.tag === DEFAULT_TAG, dropdown: !this.dropup, dropup: this.dropup, open: this.show } }, [ this.$slots.default, h( 'ul', { class: { 'dropdown-menu': true, 'dropdown-menu-right': this.menuRight }, ref: 'dropdown' }, [this.$slots.dropdown] ) ] ) }, props: { tag: { type: String, default: DEFAULT_TAG }, appendToBody: { type: Boolean, default: false }, value: Boolean, dropup: { type: Boolean, default: false }, menuRight: { type: Boolean, default: false }, disabled: { type: Boolean, default: false }, notCloseElements: Array, positionElement: null }, data: function data () { return { show: false, triggerEl: undefined } }, watch: { value: function value (v) { this.toggle(v); } }, mounted: function mounted () { this.initTrigger(); if (this.triggerEl) { on(this.triggerEl, EVENTS.CLICK, this.toggle); on(this.triggerEl, EVENTS.KEY_DOWN, this.onKeyPress); } on(this.$refs.dropdown, EVENTS.KEY_DOWN, this.onKeyPress); on(window, EVENTS.CLICK, this.windowClicked); on(window, EVENTS.TOUCH_END, this.windowClicked); if (this.value) { this.toggle(true); } }, beforeDestroy: function beforeDestroy () { this.removeDropdownFromBody(); if (this.triggerEl) { off(this.triggerEl, EVENTS.CLICK, this.toggle); off(this.triggerEl, EVENTS.KEY_DOWN, this.onKeyPress); } off(this.$refs.dropdown, EVENTS.KEY_DOWN, this.onKeyPress); off(window, EVENTS.CLICK, this.windowClicked); off(window, EVENTS.TOUCH_END, this.windowClicked); }, methods: { getFocusItem: function getFocusItem () { var dropdownEl = this.$refs.dropdown; /* istanbul ignore next */ return dropdownEl.querySelector('li > a:focus') }, onKeyPress: function onKeyPress (event) { if (this.show) { var dropdownEl = this.$refs.dropdown; var keyCode = event.keyCode; if (keyCode === 27) { // esc this.toggle(false); this.triggerEl && this.triggerEl.focus(); } else if (keyCode === 13) { // enter var currentFocus = this.getFocusItem(); currentFocus && currentFocus.click(); } else if (keyCode === 38 || keyCode === 40) { // up || down event.preventDefault(); event.stopPropagation(); var currentFocus$1 = this.getFocusItem(); var items = dropdownEl.querySelectorAll('li:not(.disabled) > a'); if (!currentFocus$1) { focus(items[0]); } else { for (var i = 0; i < items.length; i++) { if (currentFocus$1 === items[i]) { if (keyCode === 38 && i < items.length > 0) { focus(items[i - 1]); } else if (keyCode === 40 && i < items.length - 1) { focus(items[i + 1]); } break } } } } } }, initTrigger: function initTrigger () { var trigger = this.$el.querySelector('[data-role="trigger"]') || this.$el.querySelector('.dropdown-toggle') || this.$el.firstChild; this.triggerEl = trigger && trigger !== this.$refs.dropdown ? trigger : null; }, toggle: function toggle (show) { if (this.disabled) { return } if (isBoolean(show)) { this.show = show; } else { this.show = !this.show; } if (this.appendToBody) { this.show ? this.appendDropdownToBody() : this.removeDropdownFromBody(); } this.$emit('input', this.show); }, windowClicked: function windowClicked (event) { var target = event.target; if (this.show && target) { var targetInNotCloseElements = false; if (this.notCloseElements) { for (var i = 0, l = this.notCloseElements.length; i < l; i++) { var isTargetInElement = this.notCloseElements[i].contains(target); var shouldBreak = isTargetInElement; /* istanbul ignore else */ if (this.appendToBody) { var isTargetInDropdown = this.$refs.dropdown.contains(target); var isElInElements = this.notCloseElements.indexOf(this.$el) >= 0; shouldBreak = isTargetInElement || (isTargetInDropdown && isElInElements); } if (shouldBreak) { targetInNotCloseElements = true; break } } } var targetInDropdownBody = this.$refs.dropdown.contains(target); var targetInTrigger = this.$el.contains(target) && !targetInDropdownBody; // normally, a dropdown select event is handled by @click that trigger after @touchend // then @touchend event have to be ignore in this case var targetInDropdownAndIsTouchEvent = targetInDropdownBody && event.type === 'touchend'; if (!targetInTrigger && !targetInNotCloseElements && !targetInDropdownAndIsTouchEvent) { this.toggle(false); } } }, appendDropdownToBody: function appendDropdownToBody () { try { var el = this.$refs.dropdown; el.style.display = 'block'; document.body.appendChild(el); var positionElement = this.positionElement || this.$el; setDropdownPosition(el, positionElement, this); } catch (e) { // Silent } }, removeDropdownFromBody: function removeDropdownFromBody () { try { var el = this.$refs.dropdown; el.removeAttribute('style'); this.$el.appendChild(el); } catch (e) { // Silent } } } }; export default Dropdown; //# sourceMappingURL=Dropdown.js.map