mj-context-menu
Version:
A generic context menu
152 lines • 4.86 kB
JavaScript
import { AbstractMenu } from './abstract_menu.js';
import { HtmlClasses } from './html_classes.js';
import { MenuStore } from './menu_store.js';
import { VariablePool } from './variable_pool.js';
export class ContextMenu extends AbstractMenu {
static fromJson(factory, { pool: pool, items: items, id: id = '' }) {
const ctxtMenu = new this(factory);
ctxtMenu.id = id;
const varParser = factory.get('variable');
pool.forEach((x) => varParser(factory, x, ctxtMenu.pool));
const itemList = factory.get('items')(factory, items, ctxtMenu);
ctxtMenu.items = itemList;
return ctxtMenu;
}
constructor(factory) {
super();
this.factory = factory;
this.id = '';
this.moving = false;
this._store = new MenuStore(this);
this.widgets = [];
this.variablePool = new VariablePool();
}
generateHtml() {
if (this.isPosted()) {
this.unpost();
}
super.generateHtml();
this._frame = document.createElement('div');
this._frame.classList.add(HtmlClasses['MENUFRAME']);
const styleString = 'left: 0px; top: 0px; z-index: 200; width: 100%; ' +
'height: 100%; border: 0px; padding: 0px; margin: 0px;';
this._frame.setAttribute('style', 'position: absolute; ' + styleString);
const innerDiv = document.createElement('div');
innerDiv.setAttribute('style', 'position: fixed; ' + styleString);
this._frame.appendChild(innerDiv);
innerDiv.addEventListener('mousedown', function (event) {
this.unpost();
this.unpostWidgets();
this.stop(event);
}.bind(this));
}
display() {
document.body.appendChild(this.frame);
this.frame.appendChild(this.html);
this.focus();
}
escape(_event) {
this.unpost();
this.unpostWidgets();
}
unpost() {
super.unpost();
if (this.widgets.length > 0) {
return;
}
this.frame.parentNode.removeChild(this.frame);
const store = this.store;
if (!this.moving) {
store.insertTaborder();
}
store.active.focus();
}
left(_event) {
this.move_(this.store.previous());
}
right(_event) {
this.move_(this.store.next());
}
get frame() {
return this._frame;
}
get store() {
return this._store;
}
post(numberOrEvent, isY) {
if (typeof isY !== 'undefined') {
if (!this.moving) {
this.store.removeTaborder();
}
super.post(numberOrEvent, isY);
return;
}
const event = numberOrEvent;
let node;
if (event instanceof Event) {
node = event.target;
this.stop(event);
}
else {
node = event;
}
let x;
let y;
if (event instanceof MouseEvent) {
x = event.pageX;
y = event.pageY;
if (!x && !y && event.clientX) {
x =
event.clientX +
document.body.scrollLeft +
document.documentElement.scrollLeft;
y =
event.clientY +
document.body.scrollTop +
document.documentElement.scrollTop;
}
}
if (!x && !y && node) {
const offsetX = window.pageXOffset || document.documentElement.scrollLeft;
const offsetY = window.pageYOffset || document.documentElement.scrollTop;
const rect = node.getBoundingClientRect();
x = (rect.right + rect.left) / 2 + offsetX;
y = (rect.bottom + rect.top) / 2 + offsetY;
}
this.store.active = node;
this.anchor = this.store.active;
const menu = this.html;
const margin = 5;
if (x + menu.offsetWidth > document.body.offsetWidth - margin) {
x = document.body.offsetWidth - menu.offsetWidth - margin;
}
this.post(x, y);
}
registerWidget(widget) {
this.widgets.push(widget);
}
unregisterWidget(widget) {
const index = this.widgets.indexOf(widget);
if (index > -1) {
this.widgets.splice(index, 1);
}
if (this.widgets.length === 0) {
this.unpost();
}
}
unpostWidgets() {
this.widgets.forEach((x) => x.unpost());
}
toJson() {
return { type: '' };
}
move_(next) {
if (this.anchor && next !== this.anchor) {
this.moving = true;
this.unpost();
this.post(next);
this.moving = false;
}
}
}
//# sourceMappingURL=context_menu.js.map