Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement #27 - adds an api for more direct usage #29

Merged
merged 3 commits into from
Oct 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,13 @@ This is a divider item which draws a horizontal line.

This library exports a singleton object `ctxmenu`.
In the standalone version the singleton is a global variable (`window.ctxmenu`).
It has the following three APIs:
It has the following five APIs:

[attach](#ctxmenuattach)\
[update](#ctxmenuupdate)\
[delete](#ctxmenudelete)
[delete](#ctxmenudelete)\
[show](#ctxmenushow)\
[hide](#ctxmenuhide)

### `ctxmenu.attach`
```typescript
Expand Down Expand Up @@ -199,6 +201,23 @@ ctxmenu.delete(target: string)
```
The delete method is used to delete a context menu and only takes the `target` selector string.

### `ctxmenu.show`
```typescript
ctxmenu.show(ctxmenu: Array, e: MouseEvent | HTMLElement)
```
The `show` method can be used to show a context menu without using the `attach` method to set up a contextmenu for specific elements first.

This may be useful when integrating with other libraries or frameworks that already provide a contextmenu handler or when trying to show a context menu on a different user interaction (for example showing a context menu when left-clicking a button).

When passing in an element as reference to open the context menu, you still need to stop the propagation of click events
in your custom code, otherwise the context menu may be directly closed.

### `ctxmenu.hide`
```typescript
ctxmenu.hide()
```
The `hide` method can be used to hide any open context menu.

## Customize

ctxmenu.js uses the following css classes which you might want to overwrite:
Expand Down
42 changes: 26 additions & 16 deletions docs/ctxmenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,13 @@
return;
}

_this.closeMenu();
_this.hide();
});
window.addEventListener("resize", function () {
return _this.closeMenu();
return _this.hide();
});
window.addEventListener("scroll", function () {
return _this.closeMenu();
return _this.hide();
});
ContextMenu.addStylesToDom();
}
Expand All @@ -147,14 +147,9 @@
}

var handler = function handler(e) {
e.stopImmediatePropagation();

_this2.closeMenu();

var newMenu = beforeRender(_toConsumableArray(ctxMenu), e);
_this2.menu = _this2.generateDOM(newMenu, e);
document.body.appendChild(_this2.menu);
e.preventDefault();

_this2.show(newMenu, e);
};

this.cache[target] = {
Expand Down Expand Up @@ -194,8 +189,23 @@
delete this.cache[target];
}
}, {
key: "closeMenu",
value: function closeMenu() {
key: "show",
value: function show(ctxMenu, eventOrElement) {
if (eventOrElement instanceof MouseEvent) {
eventOrElement.stopImmediatePropagation();
}

this.hide();
this.menu = this.generateDOM(_toConsumableArray(ctxMenu), eventOrElement);
document.body.appendChild(this.menu);

if (eventOrElement instanceof MouseEvent) {
eventOrElement.preventDefault();
}
}
}, {
key: "hide",
value: function hide() {
var menu = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.menu;

var _a;
Expand Down Expand Up @@ -244,7 +254,7 @@
var subMenu = (_a = li.parentElement) === null || _a === void 0 ? void 0 : _a.querySelector("ul");

if (subMenu && subMenu.parentElement !== li) {
_this3.closeMenu(subMenu);
_this3.hide(subMenu);
}
});

Expand All @@ -269,14 +279,14 @@
li.addEventListener("click", function (e) {
item.action(e);

_this3.closeMenu();
_this3.hide();
});
} else if (ContextMenu.itemIsAnchor(item)) {
var a = document.createElement("a");
elem ? a.append(elem) : a.innerHTML = html ? html : text;

a.onclick = function () {
return _this3.closeMenu();
return _this3.hide();
};

a.href = ContextMenu.getProp(item.href);
Expand Down Expand Up @@ -384,7 +394,7 @@
var subMenu = (_a = listElement.parentElement) === null || _a === void 0 ? void 0 : _a.querySelector("li > ul");

if (subMenu && subMenu.parentElement !== listElement) {
this.closeMenu(subMenu);
this.hide(subMenu);
}

listElement.appendChild(this.generateDOM(ctxMenu, listElement));
Expand Down
2 changes: 1 addition & 1 deletion docs/ctxmenu.min.js

Large diffs are not rendered by default.

28 changes: 28 additions & 0 deletions docs/demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,31 @@ function toggleDarkMode() {
toggle.innerHTML = "Back to normal!";
}
}
var menuExample = [
{
text: "Downloads",
subMenu: [
{
text: "ctxmenu.js",
href: "ctxmenu.js",
download: ""
},
{
text: "ctxmenu.min.js",
href: "ctxmenu.min.js",
download: ""
}
]
},
{
text: "Documentation (github)",
href: "https://www.github.com/nkappler/ctxmenu"
}
];
function showContextMenuForEvent(e) {
ctxmenu.show(menuExample, e);
}
function showContextMenuForElement(element, e) {
e.stopPropagation();
ctxmenu.show(menuExample, element);
}
16 changes: 15 additions & 1 deletion docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@
height: 149px;
}

.clickable-div {
background-color: #ccc;
display: inline;
cursor: pointer;
}

/* If the screen size is 600px wide or less, set the font-size of <div> to 30px */
@media screen and (max-width: 600px) {
h1 {
Expand Down Expand Up @@ -168,6 +174,14 @@ <h1 style="margin: auto;">ctxmenu.js</h1>
run any arbitrary javascript function</li>
<li>Fully customizable! <span id="switch" style="cursor: pointer;" class="bold"
onclick="toggleDarkMode()">Fancy dark mode?</span></li>
<li>Show a context menu "on demand" for
<ul>
<li>any mouse event
<button type="button" onclick="showContextMenuForEvent(event)">Click me!</button></li>
<li>any element
<div class="clickable-div" onclick="showContextMenuForElement(this, event)">Click me!</div></li>
</ul>

<li>Mobile support</li>
</ul>
</p>
Expand All @@ -176,4 +190,4 @@ <h1 style="margin: auto;">ctxmenu.js</h1>

</body>

</html>
</html>
10 changes: 10 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,16 @@ declare module "ctxmenu" {
* @param target A selector string to define the target node (eg `'body'`, or `'#someID'`)
*/
delete(target: string): void;
/**
* Create & show a context menu without attaching it to a specific element, based on the passed mouse event.
* @param ctxMenu An array of objects defining the menu layout.
* @param e Either a MouseEvent or an HTMLElement, defining where the context menu should be opened.
*/
show(ctxMenu: CTXMenu, e: MouseEvent | HTMLElement): void;
/**
* Close any contextmenu that might be open at the moment
*/
hide(): void;
}
export const ctxmenu: CTXMenuSingleton;
}
42 changes: 26 additions & 16 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ var ContextMenu = /*#__PURE__*/function () {
return;
}

_this.closeMenu();
_this.hide();
});
window.addEventListener("resize", function () {
return _this.closeMenu();
return _this.hide();
});
window.addEventListener("scroll", function () {
return _this.closeMenu();
return _this.hide();
});
ContextMenu.addStylesToDom();
}
Expand All @@ -72,14 +72,9 @@ var ContextMenu = /*#__PURE__*/function () {
}

var handler = function handler(e) {
e.stopImmediatePropagation();

_this2.closeMenu();

var newMenu = beforeRender(_toConsumableArray(ctxMenu), e);
_this2.menu = _this2.generateDOM(newMenu, e);
document.body.appendChild(_this2.menu);
e.preventDefault();

_this2.show(newMenu, e);
};

this.cache[target] = {
Expand Down Expand Up @@ -119,8 +114,23 @@ var ContextMenu = /*#__PURE__*/function () {
delete this.cache[target];
}
}, {
key: "closeMenu",
value: function closeMenu() {
key: "show",
value: function show(ctxMenu, eventOrElement) {
if (eventOrElement instanceof MouseEvent) {
eventOrElement.stopImmediatePropagation();
}

this.hide();
this.menu = this.generateDOM(_toConsumableArray(ctxMenu), eventOrElement);
document.body.appendChild(this.menu);

if (eventOrElement instanceof MouseEvent) {
eventOrElement.preventDefault();
}
}
}, {
key: "hide",
value: function hide() {
var menu = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.menu;

var _a;
Expand Down Expand Up @@ -169,7 +179,7 @@ var ContextMenu = /*#__PURE__*/function () {
var subMenu = (_a = li.parentElement) === null || _a === void 0 ? void 0 : _a.querySelector("ul");

if (subMenu && subMenu.parentElement !== li) {
_this3.closeMenu(subMenu);
_this3.hide(subMenu);
}
});

Expand All @@ -194,14 +204,14 @@ var ContextMenu = /*#__PURE__*/function () {
li.addEventListener("click", function (e) {
item.action(e);

_this3.closeMenu();
_this3.hide();
});
} else if (ContextMenu.itemIsAnchor(item)) {
var a = document.createElement("a");
elem ? a.append(elem) : a.innerHTML = html ? html : text;

a.onclick = function () {
return _this3.closeMenu();
return _this3.hide();
};

a.href = ContextMenu.getProp(item.href);
Expand Down Expand Up @@ -309,7 +319,7 @@ var ContextMenu = /*#__PURE__*/function () {
var subMenu = (_a = listElement.parentElement) === null || _a === void 0 ? void 0 : _a.querySelector("li > ul");

if (subMenu && subMenu.parentElement !== listElement) {
this.closeMenu(subMenu);
this.hide(subMenu);
}

listElement.appendChild(this.generateDOM(ctxMenu, listElement));
Expand Down
Loading