2021-07-03 05:06:05 +08:00
|
|
|
import { getAttributeOrDefault, parseBoolean } from "../lib/attribute";
|
|
|
|
|
2021-04-22 05:02:09 +08:00
|
|
|
/**
|
|
|
|
* A hook controlling a toggleable menu.
|
|
|
|
*
|
2021-07-03 05:06:05 +08:00
|
|
|
* Configuration:
|
|
|
|
*
|
|
|
|
* * `data-primary` - a boolean indicating whether to open on the primary
|
|
|
|
* click or the secondary click (like right mouse button click). Defaults to `true`.
|
|
|
|
*
|
2021-04-22 05:02:09 +08:00
|
|
|
* The element should have two children:
|
|
|
|
*
|
|
|
|
* * one annotated with `data-toggle` being a clickable element
|
|
|
|
*
|
|
|
|
* * one annotated with `data-content` with menu content
|
|
|
|
*/
|
|
|
|
const Menu = {
|
|
|
|
mounted() {
|
2021-07-03 05:06:05 +08:00
|
|
|
this.props = getProps(this);
|
|
|
|
|
2021-04-22 05:02:09 +08:00
|
|
|
const toggleElement = this.el.querySelector("[data-toggle]");
|
|
|
|
|
|
|
|
if (!toggleElement) {
|
|
|
|
throw new Error("Menu must have a child with data-toggle attribute");
|
|
|
|
}
|
|
|
|
|
|
|
|
const contentElement = this.el.querySelector("[data-content]");
|
|
|
|
|
|
|
|
if (!contentElement) {
|
|
|
|
throw new Error("Menu must have a child with data-content attribute");
|
|
|
|
}
|
|
|
|
|
2021-07-03 05:06:05 +08:00
|
|
|
if (this.props.primary) {
|
|
|
|
toggleElement.addEventListener("click", (event) => {
|
|
|
|
if (this.el.hasAttribute("data-js-open")) {
|
|
|
|
this.el.removeAttribute("data-js-open");
|
|
|
|
} else {
|
|
|
|
this.el.setAttribute("data-js-open", "true");
|
|
|
|
// Postpone callback registration until the current click finishes bubbling.
|
|
|
|
setTimeout(() => {
|
|
|
|
document.addEventListener(
|
|
|
|
"click",
|
|
|
|
(event) => {
|
|
|
|
this.el.removeAttribute("data-js-open");
|
|
|
|
},
|
|
|
|
{ once: true }
|
|
|
|
);
|
|
|
|
}, 0);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
toggleElement.addEventListener("contextmenu", (event) => {
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
|
|
if (this.el.hasAttribute("data-js-open")) {
|
|
|
|
this.el.removeAttribute("data-js-open");
|
|
|
|
} else {
|
|
|
|
this.el.setAttribute("data-js-open", "true");
|
|
|
|
// Postpone callback registration until the current click finishes bubbling.
|
|
|
|
setTimeout(() => {
|
|
|
|
const handler = (event) => {
|
2021-04-22 05:02:09 +08:00
|
|
|
this.el.removeAttribute("data-js-open");
|
2021-07-03 05:06:05 +08:00
|
|
|
document.removeEventListener("click", handler);
|
|
|
|
document.removeEventListener("contextmenu", handler);
|
|
|
|
};
|
|
|
|
|
|
|
|
document.addEventListener("click", handler);
|
|
|
|
document.addEventListener("contextmenu", handler);
|
|
|
|
}, 0);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2021-04-22 05:02:09 +08:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2021-07-03 05:06:05 +08:00
|
|
|
function getProps(hook) {
|
|
|
|
return {
|
|
|
|
primary: getAttributeOrDefault(
|
|
|
|
hook.el,
|
|
|
|
"data-primary",
|
|
|
|
"true",
|
|
|
|
parseBoolean
|
|
|
|
),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-04-22 05:02:09 +08:00
|
|
|
export default Menu;
|