nly-adminlte-vue
Version:
nly adminlte3 components
122 lines (111 loc) • 3.85 kB
JavaScript
import KeyCodes from "../../utils/key-codes";
import {
getAttr,
hasAttr,
isDisabled,
matches,
select,
setAttr
} from "../../utils/dom";
import { EVENT_OPTIONS_PASSIVE, eventOn, eventOff } from "../../utils/events";
import { isString } from "../../utils/inspect";
import { keys } from "../../utils/object";
// Emitted show event for modal
const EVENT_SHOW = "nlya::show::modal";
// Prop name we use to store info on root element
const PROPERTY = "__nlya_modal_directive__";
const getTarget = ({ modifiers = {}, arg, value }) => {
// Try value, then arg, otherwise pick last modifier
return isString(value)
? value
: isString(arg)
? arg
: keys(modifiers).reverse()[0];
};
const 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;
};
const 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");
}
}
};
const bind = (el, binding, vnode) => {
const target = getTarget(binding);
const trigger = getTriggerElement(el);
if (target && trigger) {
const handler = evt => {
// `currentTarget` is the element with the listener on it
const currentTarget = evt.currentTarget;
if (!isDisabled(currentTarget)) {
const type = evt.type;
const key = evt.keyCode;
// Open modal only if trigger is not disabled
if (
type === "click" ||
(type === "keydown" &&
(key === KeyCodes.ENTER || key === KeyCodes.SPACE))
) {
vnode.context.$root.$emit(EVENT_SHOW, target, currentTarget);
}
}
};
el[PROPERTY] = { handler, target, 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);
}
}
};
const unbind = el => {
const oldProp = el[PROPERTY] || {};
const trigger = oldProp.trigger;
const 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];
};
const componentUpdated = (el, binding, vnode) => {
const oldProp = el[PROPERTY] || {};
const target = getTarget(binding);
const 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);
};
const updated = () => {};
/*
* Export our directive
*/
export const VNlyModal = {
inserted: componentUpdated,
updated,
componentUpdated,
unbind
};