diff --git a/index.html b/index.html
index 2e4f46c..db58067 100644
--- a/index.html
+++ b/index.html
@@ -156,6 +156,10 @@
console.log({ evt });
});
+ contextmenu.on('open', function (evt) {
+ console.log({ evt });
+ });
+
map.on('moveend', () => {
console.log('moveend', contextmenu.isOpen());
});
diff --git a/src/main.ts b/src/main.ts
index b727ea6..c36c243 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -3,9 +3,21 @@ import type { Coordinate } from 'ol/coordinate';
import OlMap from 'ol/Map';
import Control from 'ol/control/Control';
import BaseEvent from 'ol/events/Event';
+import { EventsKey } from 'ol/events';
+import { Types as ObjectEventTypes } from 'ol/ObjectEventType';
+import { CombinedOnSignature, EventTypes as OlEventTypes, OnSignature } from 'ol/Observable';
+import { ObjectEvent } from 'ol/Object';
import { CSS_CLASSES, DEFAULT_ITEMS, DEFAULT_OPTIONS } from './constants';
-import { CallbackObject, CustomEventTypes, EventTypes, Item, MenuEntry, Options } from './types';
+import {
+ CallbackObject,
+ ContextMenuEvent,
+ CustomEventTypes,
+ EventTypes,
+ Item,
+ MenuEntry,
+ Options,
+} from './types';
import emitter from './emitter';
import { addMenuEntries, getLineHeight } from './helpers/dom';
@@ -40,6 +52,54 @@ export default class ContextMenu extends Control {
protected menuEntries: Map = new Map();
+ declare on: OnSignature &
+ OnSignature<
+ `${CustomEventTypes.BEFOREOPEN}` | `${CustomEventTypes.OPEN}`,
+ ContextMenuEvent,
+ EventsKey
+ > &
+ OnSignature &
+ CombinedOnSignature<
+ | `${CustomEventTypes.BEFOREOPEN}`
+ | `${CustomEventTypes.OPEN}`
+ | ObjectEventTypes
+ | `${CustomEventTypes.CLOSE}`
+ | OlEventTypes,
+ EventsKey
+ >;
+
+ declare once: OnSignature &
+ OnSignature<
+ `${CustomEventTypes.BEFOREOPEN}` | `${CustomEventTypes.OPEN}`,
+ ContextMenuEvent,
+ EventsKey
+ > &
+ OnSignature &
+ CombinedOnSignature<
+ | `${CustomEventTypes.BEFOREOPEN}`
+ | `${CustomEventTypes.OPEN}`
+ | ObjectEventTypes
+ | `${CustomEventTypes.CLOSE}`
+ | OlEventTypes,
+ EventsKey
+ >;
+
+ declare un: OnSignature &
+ OnSignature<
+ `${CustomEventTypes.BEFOREOPEN}` | `${CustomEventTypes.OPEN}`,
+ ContextMenuEvent,
+ EventsKey
+ > &
+ OnSignature &
+ CombinedOnSignature<
+ | `${CustomEventTypes.BEFOREOPEN}`
+ | `${CustomEventTypes.OPEN}`
+ | ObjectEventTypes
+ | `${CustomEventTypes.CLOSE}`
+ | OlEventTypes,
+ void
+ >;
+
options: Options;
constructor(opts: Partial = {}) {
@@ -72,14 +132,6 @@ export default class ContextMenu extends Control {
};
this.disabled = false;
this.opened = false;
-
- emitter.on(
- CustomEventTypes.ADD_MENU_ENTRY,
- (item: MenuEntry, element: HTMLLIElement) => {
- this.handleAddMenuEntry(item, element);
- },
- this
- );
}
clear() {
@@ -164,6 +216,14 @@ export default class ContextMenu extends Control {
this.handleMapMove();
});
+ emitter.on(
+ CustomEventTypes.ADD_MENU_ENTRY,
+ (item: MenuEntry, element: HTMLLIElement) => {
+ this.handleAddMenuEntry(item, element);
+ },
+ this
+ );
+
this.items = this.options.defaultItems
? this.options.items.concat(DEFAULT_ITEMS)
: this.options.items;
@@ -190,6 +250,8 @@ export default class ContextMenu extends Control {
this.map
.getViewport()
.removeEventListener(this.options.eventType, this.contextMenuEventListener, false);
+
+ emitter.off(CustomEventTypes.ADD_MENU_ENTRY);
}
protected removeMenuEntry(id: string) {
@@ -203,11 +265,13 @@ export default class ContextMenu extends Control {
protected handleContextMenu(evt: MouseEvent) {
this.coordinate = this.map.getEventCoordinate(evt);
this.pixel = this.map.getEventPixel(evt);
- this.dispatchEvent({
- type: CustomEventTypes.BEFOREOPEN,
- pixel: this.pixel,
- coordinate: this.coordinate,
- } as unknown as BaseEvent);
+ this.dispatchEvent(
+ new ContextMenuEvent({
+ type: CustomEventTypes.BEFOREOPEN,
+ pixel: this.pixel,
+ coordinate: this.coordinate,
+ })
+ );
if (this.disabled) return;
@@ -238,6 +302,14 @@ export default class ContextMenu extends Control {
this.opened = true;
this.positionContainer();
this.container.classList.remove(CSS_CLASSES.hidden);
+
+ this.dispatchEvent(
+ new ContextMenuEvent({
+ type: CustomEventTypes.OPEN,
+ pixel: this.pixel,
+ coordinate: this.coordinate,
+ })
+ );
}
protected getMenuEntriesLength(): number {
diff --git a/src/types.ts b/src/types.ts
index 69b318e..1bb016c 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -1,7 +1,7 @@
import type { Coordinate } from 'ol/coordinate';
import type { Pixel } from 'ol/pixel';
import { Map as OlMap } from 'ol';
-import BaseEvent from 'ol/events/Event';
+import BaseEvent from 'ol/events/Event.js';
export enum EventTypes {
CONTEXTMENU = 'contextmenu',
@@ -16,9 +16,19 @@ export enum CustomEventTypes {
ADD_MENU_ENTRY = 'add-menu-entry',
}
-export interface ContextMenuEvent extends BaseEvent {
- coordinate: Coordinate;
- pixel: Pixel;
+export class ContextMenuEvent extends BaseEvent {
+ public coordinate: Coordinate;
+ public pixel: Pixel;
+
+ constructor(options: {
+ type: `${CustomEventTypes.BEFOREOPEN}` | `${CustomEventTypes.OPEN}`;
+ coordinate: Coordinate;
+ pixel: Pixel;
+ }) {
+ super(options.type);
+ this.pixel = options.pixel;
+ this.coordinate = options.coordinate;
+ }
}
export type CallbackObject = {
diff --git a/test/instance.spec.ts b/test/instance.spec.ts
index f1440bf..a20d307 100644
--- a/test/instance.spec.ts
+++ b/test/instance.spec.ts
@@ -1,6 +1,9 @@
+import OlMap from 'ol/Map';
+import BaseEvent from 'ol/events/Event';
+
import { DEFAULT_ITEMS, DEFAULT_OPTIONS } from '../src/constants';
import ContextMenu from '../src/main';
-import { Item } from '../src/types';
+import { ContextMenuEvent, Item } from '../src/types';
const items: Item[] = [
'-',
@@ -46,6 +49,11 @@ describe('Instance options', () => {
describe('Instance methods', () => {
const menu = new ContextMenu();
+ // Add map to initialize the emitter
+ new OlMap({
+ controls: [menu],
+ });
+
test('getDefaultItems()', () => {
expect(toJSON(menu.getDefaultItems())).toEqual(toJSON(DEFAULT_ITEMS));
});
@@ -103,3 +111,21 @@ describe('Throw errors', () => {
}).toThrow();
});
});
+
+// EVENTS
+// The lines below are not a test per se, but as an ESLint indicator if the events are not correctly declared
+const context = new ContextMenu();
+
+context.on('beforeopen', (evt: ContextMenuEvent) => {
+ evt.pixel;
+ evt.coordinate;
+});
+
+context.on('open', (evt: ContextMenuEvent) => {
+ evt.pixel;
+ evt.coordinate;
+});
+
+context.on('close', (evt: BaseEvent) => {
+ evt.target;
+});
diff --git a/vite.config.ts b/vite.config.ts
index e199010..4dd404f 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -9,9 +9,10 @@ import { CSS_CLASSES } from './src/constants';
const pkg = JSON.parse(readFileSync('./package.json', 'utf8'));
// eslint-disable-next-line @typescript-eslint/no-shadow
-const external = ['ol/control/Control', 'ol/PluggableMap', 'ol'];
+const external = ['ol/control/Control', 'ol/events/Event', 'ol/PluggableMap', 'ol'];
const globals = {
'ol/control/Control': 'ol.control.Control',
+ 'ol/events/Event': 'ol.events.Event',
ol: 'ol',
};