modal.js
4.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import { NAME_MODAL } from '../../constants/components';
import { EVENT_NAME_SHOW, EVENT_OPTIONS_PASSIVE } from '../../constants/events';
import { CODE_ENTER, CODE_SPACE } from '../../constants/key-codes';
import { getAttr, hasAttr, isDisabled, matches, select, setAttr } from '../../utils/dom';
import { getRootActionEventName, eventOn, eventOff } from '../../utils/events';
import { isString } from '../../utils/inspect';
import { keys } from '../../utils/object';
import { getEventRoot } from '../../utils/get-event-root';
import { getInstanceFromDirective } from '../../utils/get-instance-from-directive'; // Emitted show event for modal
var ROOT_ACTION_EVENT_NAME_SHOW = getRootActionEventName(NAME_MODAL, EVENT_NAME_SHOW); // Prop name we use to store info on root element
var PROPERTY = '__bv_modal_directive__';
var getTarget = function getTarget(_ref) {
var _ref$modifiers = _ref.modifiers,
modifiers = _ref$modifiers === void 0 ? {} : _ref$modifiers,
arg = _ref.arg,
value = _ref.value;
// Try value, then arg, otherwise pick last modifier
return isString(value) ? value : isString(arg) ? arg : keys(modifiers).reverse()[0];
};
var getTriggerElement = function getTriggerElement(el) {
// If root element is a dropdown-item or nav-item, we
// need to target the inner link or button instead
return el && matches(el, '.dropdown-menu > li, li.nav-item') ? select('a, button', el) || el : el;
};
var setRole = function setRole(trigger) {
// Ensure accessibility on non button elements
if (trigger && trigger.tagName !== 'BUTTON') {
// Only set a role if the trigger element doesn't have one
if (!hasAttr(trigger, 'role')) {
setAttr(trigger, 'role', 'button');
} // Add a tabindex is not a button or link, and tabindex is not provided
if (trigger.tagName !== 'A' && !hasAttr(trigger, 'tabindex')) {
setAttr(trigger, 'tabindex', '0');
}
}
};
var bind = function bind(el, binding, vnode) {
var target = getTarget(binding);
var trigger = getTriggerElement(el);
if (target && trigger) {
var handler = function handler(event) {
// `currentTarget` is the element with the listener on it
var currentTarget = event.currentTarget;
if (!isDisabled(currentTarget)) {
var type = event.type;
var key = event.keyCode; // Open modal only if trigger is not disabled
if (type === 'click' || type === 'keydown' && (key === CODE_ENTER || key === CODE_SPACE)) {
getEventRoot(getInstanceFromDirective(vnode, binding)).$emit(ROOT_ACTION_EVENT_NAME_SHOW, target, currentTarget);
}
}
};
el[PROPERTY] = {
handler: handler,
target: target,
trigger: trigger
}; // If element is not a button, we add `role="button"` for accessibility
setRole(trigger); // Listen for click events
eventOn(trigger, 'click', handler, EVENT_OPTIONS_PASSIVE);
if (trigger.tagName !== 'BUTTON' && getAttr(trigger, 'role') === 'button') {
// If trigger isn't a button but has role button,
// we also listen for `keydown.space` && `keydown.enter`
eventOn(trigger, 'keydown', handler, EVENT_OPTIONS_PASSIVE);
}
}
};
var unbind = function unbind(el) {
var oldProp = el[PROPERTY] || {};
var trigger = oldProp.trigger;
var handler = oldProp.handler;
if (trigger && handler) {
eventOff(trigger, 'click', handler, EVENT_OPTIONS_PASSIVE);
eventOff(trigger, 'keydown', handler, EVENT_OPTIONS_PASSIVE);
eventOff(el, 'click', handler, EVENT_OPTIONS_PASSIVE);
eventOff(el, 'keydown', handler, EVENT_OPTIONS_PASSIVE);
}
delete el[PROPERTY];
};
var componentUpdated = function componentUpdated(el, binding, vnode) {
var oldProp = el[PROPERTY] || {};
var target = getTarget(binding);
var trigger = getTriggerElement(el);
if (target !== oldProp.target || trigger !== oldProp.trigger) {
// We bind and rebind if the target or trigger changes
unbind(el, binding, vnode);
bind(el, binding, vnode);
} // If trigger element is not a button, ensure `role="button"`
// is still set for accessibility
setRole(trigger);
};
var updated = function updated() {};
/*
* Export our directive
*/
export var VBModal = {
inserted: componentUpdated,
updated: updated,
componentUpdated: componentUpdated,
unbind: unbind
};