model/context-menu

There is no license information available for the latest version (v0.1.0) of this package.

A nice context menu you can append wherever you like

Maintainers

Package info

github.com/model-composer/context-menu

pkg:composer/model/context-menu

Transparency log

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.0 2026-08-26 14:47 UTC

This package is auto-updated.

Last update: 2026-08-26 14:49:20 UTC


README

A nice context menu you can append wherever you like.

This is the ModEl 4 port of the legacy ContextMenu module. It ships the menu's CSS/JS as an asset library declared through an AssetsProvider, so model/assets discovers and serves them automatically — no manual file inclusion needed.

Unlike the v3 module, it has no hard dependency on the legacy FrontEnd module: the helpers it used to borrow from it (_, getMouseCoords, addClass, removeClass) are now implemented internally or replaced by their native equivalents. onHtmlChange is still used to re-scan dynamically loaded HTML, but only if FrontEnd happens to be loaded.

Installation

composer require model/context-menu

Enabling the assets

The library is registered under the name context-menu but is not auto-enabled. Enable it (typically from a controller's init) wherever a page uses the context menu:

use Model\Assets\Assets;

Assets::enable('context-menu');

This adds style.css (in the head) and js.js (in the foot) to the asset render list.

Usage

A menu is a plain object mapping the label of each voice (HTML is allowed) to the callback to run when it is picked. Attach it to any element with ctxMenu:

document.getElementById('my-element').ctxMenu({
	'Edit': function () {
		zkPopup({url: 'edit', get: {id: this.getAttribute('data-id')}});
	},
	'Delete': function () {
		if (confirm('Are you sure?'))
			this.remove();
	},
});

Inside the callbacks, this is the element the menu is attached to.

Right-clicking the element then opens the menu at the cursor; it flips itself back over the cursor if it would otherwise overflow the bottom or the right edge of the window.

Since the voices are the keys of an object, two voices cannot share the same label.

Declarative usage

Instead of calling ctxMenu by hand, the menu can be declared directly in the markup, via the data-context-menu attribute:

<div data-context-menu="{'Edit': function(){ edit(this); }, 'Delete': function(){ del(this); }}">
	Right-click me
</div>

The attribute is a JavaScript object literal (it contains functions, so it is eval'd rather than parsed as JSON). It is scanned at DOMContentLoaded and, if the legacy FrontEnd module is present, on every onHtmlChange — so elements loaded later via ajax get their menu too. Already processed elements are flagged with data-set-context-menu and skipped. Call checkZkMenu() yourself if you inject markup without FrontEnd.

Closing the menu

The menu closes on its own when a voice is picked, when Esc is pressed, when the page is scrolled, and when the mouse is pressed anywhere outside of it. To close it programmatically:

removeContextMenu();

Keyboard

While the menu is open, / move the selection (wrapping from nothing to the last/first voice), Enter runs the selected voice, and Esc closes the menu.