ol-contextmenu 5.0.1-alpha → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +111 -103
- package/dist/constants.d.ts +14 -0
- package/dist/emitter.d.ts +3 -0
- package/dist/helpers/dom.d.ts +5 -0
- package/dist/main.d.ts +43 -0
- package/dist/ol-contextmenu.d.ts +3 -0
- package/dist/ol-contextmenu.js +31 -32
- package/dist/ol-contextmenu.umd.cjs +1 -1
- package/dist/types.d.ts +52 -0
- package/dist/vite-env.d.ts +1 -0
- package/package.json +18 -13
package/README.md
CHANGED
|
@@ -1,24 +1,18 @@
|
|
|
1
1
|
# OpenLayers Custom Context Menu
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
<img src="https://david-dm.org/jonataswalker/ol-contextmenu/status.svg"
|
|
17
|
-
alt="dependency status">
|
|
18
|
-
</a>
|
|
19
|
-
<a href="https://david-dm.org/jonataswalker/ol-contextmenu">
|
|
20
|
-
<img src="https://david-dm.org/jonataswalker/ol-contextmenu/dev-status.svg" alt="devDependency status">
|
|
21
|
-
</a>
|
|
4
|
+
<a href="https://github.com/jonataswalker/ol-contextmenu/actions/workflows/test.yml">
|
|
5
|
+
<img src="https://github.com/jonataswalker/ol-contextmenu/actions/workflows/test.yml/badge.svg?branch=master" alt="Build Status">
|
|
6
|
+
</a>
|
|
7
|
+
<a href="https://www.npmjs.com/package/ol-contextmenu">
|
|
8
|
+
<img src="https://img.shields.io/npm/v/ol-contextmenu.svg" alt="npm version">
|
|
9
|
+
</a>
|
|
10
|
+
<a href="https://img.shields.io/npm/dm/ol-contextmenu">
|
|
11
|
+
<img alt="npm" src="https://img.shields.io/npm/dm/ol-contextmenu">
|
|
12
|
+
</a>
|
|
13
|
+
<a href="https://github.com/jonataswalker/ol-contextmenu/blob/master/LICENSE">
|
|
14
|
+
<img src="https://img.shields.io/npm/l/ol-contextmenu.svg" alt="license">
|
|
15
|
+
</a>
|
|
22
16
|
</p>
|
|
23
17
|
|
|
24
18
|
A `contextmenu` extension for [OpenLayers](http://openlayers.org/). **Requires** OpenLayers **v3.11.0** or higher.
|
|
@@ -26,48 +20,58 @@ A `contextmenu` extension for [OpenLayers](http://openlayers.org/). **Requires**
|
|
|
26
20
|

|
|
27
21
|
|
|
28
22
|
## Demo
|
|
23
|
+
|
|
29
24
|
You can see [here a demo](http://rawgit.com/jonataswalker/ol-contextmenu/master/examples/contextmenu.html) or [JSFiddle](https://jsfiddle.net/jonataswalker/ooxs1w5d/).
|
|
30
25
|
|
|
31
26
|
## How to use it?
|
|
27
|
+
|
|
32
28
|
##### NPM
|
|
29
|
+
|
|
33
30
|
`npm install ol-contextmenu`
|
|
34
31
|
|
|
35
32
|
##### CDN Hosted - [jsDelivr](https://www.jsdelivr.com/package/npm/ol-contextmenu)
|
|
33
|
+
|
|
36
34
|
Load CSS and Javascript:
|
|
35
|
+
|
|
37
36
|
```HTML
|
|
38
|
-
<link href="https://cdn.jsdelivr.net/npm/ol-contextmenu@latest/dist/ol-contextmenu.
|
|
37
|
+
<link href="https://cdn.jsdelivr.net/npm/ol-contextmenu@latest/dist/ol-contextmenu.css" rel="stylesheet">
|
|
39
38
|
<script src="https://cdn.jsdelivr.net/npm/ol-contextmenu"></script>
|
|
40
39
|
```
|
|
41
40
|
|
|
42
41
|
##### CDN Hosted - UNPKG
|
|
42
|
+
|
|
43
43
|
Load CSS and Javascript:
|
|
44
|
+
|
|
44
45
|
```HTML
|
|
45
|
-
<link href="https://unpkg.com/ol-contextmenu/dist/ol-contextmenu.
|
|
46
|
+
<link href="https://unpkg.com/ol-contextmenu/dist/ol-contextmenu.css" rel="stylesheet">
|
|
46
47
|
<script src="https://unpkg.com/ol-contextmenu"></script>
|
|
47
48
|
```
|
|
49
|
+
|
|
48
50
|
##### Self hosted
|
|
51
|
+
|
|
49
52
|
Download [latest release](https://github.com/jonataswalker/ol-contextmenu/releases/latest) and (obviously) load CSS and Javascript.
|
|
50
53
|
|
|
51
54
|
##### Instantiate with some options and add the Control
|
|
55
|
+
|
|
52
56
|
```javascript
|
|
53
57
|
var contextmenu = new ContextMenu({
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
58
|
+
width: 170,
|
|
59
|
+
defaultItems: true, // defaultItems are (for now) Zoom In/Zoom Out
|
|
60
|
+
items: [
|
|
61
|
+
{
|
|
62
|
+
text: 'Center map here',
|
|
63
|
+
classname: 'some-style-class', // add some CSS rules
|
|
64
|
+
callback: center, // `center` is your callback function
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
text: 'Add a Marker',
|
|
68
|
+
classname: 'some-style-class', // you can add this icon with a CSS class
|
|
69
|
+
// instead of `icon` property (see next line)
|
|
70
|
+
icon: 'img/marker.png', // this can be relative or absolute
|
|
71
|
+
callback: marker,
|
|
72
|
+
},
|
|
73
|
+
'-', // this is a separator
|
|
74
|
+
],
|
|
71
75
|
});
|
|
72
76
|
map.addControl(contextmenu);
|
|
73
77
|
```
|
|
@@ -78,55 +82,57 @@ If you provide `items {Array}` a submenu will be created as a child of the curre
|
|
|
78
82
|
|
|
79
83
|
```javascript
|
|
80
84
|
var all_items = [
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
85
|
+
{
|
|
86
|
+
text: 'Some Actions',
|
|
87
|
+
items: [
|
|
88
|
+
// <== this is a submenu
|
|
89
|
+
{
|
|
90
|
+
text: 'Action 1',
|
|
91
|
+
callback: action,
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
text: 'Other action',
|
|
95
|
+
callback: action2,
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
text: 'Add a Marker',
|
|
101
|
+
icon: 'img/marker.png',
|
|
102
|
+
callback: marker,
|
|
103
|
+
},
|
|
104
|
+
'-', // this is a separator
|
|
100
105
|
];
|
|
101
106
|
```
|
|
102
107
|
|
|
103
108
|
##### Would you like to propagate custom data to the callback handler?
|
|
109
|
+
|
|
104
110
|
```javascript
|
|
105
111
|
var removeMarker = function (obj) {
|
|
106
|
-
|
|
112
|
+
vectorLayer.getSource().removeFeature(obj.data.marker);
|
|
107
113
|
};
|
|
108
114
|
var removeMarkerItem = {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
115
|
+
text: 'Remove this Marker',
|
|
116
|
+
icon: 'img/marker.png',
|
|
117
|
+
callback: removeMarker,
|
|
112
118
|
};
|
|
113
119
|
|
|
114
120
|
var restore = false;
|
|
115
121
|
contextmenu.on('open', function (evt) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
122
|
+
var feature = map.forEachFeatureAtPixel(evt.pixel, function (ft, l) {
|
|
123
|
+
return ft;
|
|
124
|
+
});
|
|
125
|
+
if (feature) {
|
|
126
|
+
contextmenu.clear();
|
|
127
|
+
removeMarkerItem.data = { marker: feature };
|
|
128
|
+
contextmenu.push(removeMarkerItem);
|
|
129
|
+
restore = true;
|
|
130
|
+
} else if (restore) {
|
|
131
|
+
contextmenu.clear();
|
|
132
|
+
contextmenu.extend(contextmenu_items);
|
|
133
|
+
contextmenu.extend(contextmenu.getDefaultItems());
|
|
134
|
+
restore = false;
|
|
135
|
+
}
|
|
130
136
|
});
|
|
131
137
|
```
|
|
132
138
|
|
|
@@ -137,10 +143,11 @@ contextmenu.on('open', function (evt) {
|
|
|
137
143
|
#### `new ContextMenu(options)`
|
|
138
144
|
|
|
139
145
|
###### `options` is an object with the following possible properties:
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
146
|
+
|
|
147
|
+
- `eventType`: `contextmenu`; The listening event type (You could use `'click'`, `'dblclick'`)
|
|
148
|
+
- `defaultItems`: `true`; Whether the default items (which are: Zoom In/Out) are enabled
|
|
149
|
+
- `width`: `150`; The menu's width
|
|
150
|
+
- `items`: `[]`; An array of object|string
|
|
144
151
|
|
|
145
152
|
## Methods
|
|
146
153
|
|
|
@@ -159,17 +166,18 @@ Close the menu programmatically.
|
|
|
159
166
|
Add items to the menu. This pushes each item in the provided array to the end of the menu.
|
|
160
167
|
|
|
161
168
|
Example:
|
|
169
|
+
|
|
162
170
|
```js
|
|
163
171
|
var contextmenu = new ContextMenu();
|
|
164
172
|
map.addControl(contextmenu);
|
|
165
173
|
|
|
166
174
|
var add_later = [
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
175
|
+
'-', // this is a separator
|
|
176
|
+
{
|
|
177
|
+
text: 'Add a Marker',
|
|
178
|
+
icon: 'img/marker.png',
|
|
179
|
+
callback: marker,
|
|
180
|
+
},
|
|
173
181
|
];
|
|
174
182
|
contextmenu.extend(add_later);
|
|
175
183
|
```
|
|
@@ -202,36 +210,36 @@ Whether the menu is open.
|
|
|
202
210
|
|
|
203
211
|
Update menu's position.
|
|
204
212
|
|
|
205
|
-
|
|
206
213
|
## Events
|
|
207
214
|
|
|
208
215
|
#### If you want to disable this plugin under certain circumstances, listen to `beforeopen`
|
|
209
216
|
|
|
210
217
|
```javascript
|
|
211
218
|
contextmenu.on('beforeopen', function (evt) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
219
|
+
var feature = map.forEachFeatureAtPixel(evt.pixel, function (ft, l) {
|
|
220
|
+
return ft;
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
if (feature) {
|
|
224
|
+
// open only on features
|
|
225
|
+
contextmenu.enable();
|
|
226
|
+
} else {
|
|
227
|
+
contextmenu.disable();
|
|
228
|
+
}
|
|
221
229
|
});
|
|
222
230
|
```
|
|
223
231
|
|
|
224
232
|
#### Listen and make some changes when context menu opens
|
|
225
233
|
|
|
226
234
|
```javascript
|
|
227
|
-
contextmenu.on('open', function(evt){
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
+
contextmenu.on('open', function (evt) {
|
|
236
|
+
var feature = map.forEachFeatureAtPixel(evt.pixel, function (ft, l) {
|
|
237
|
+
return ft;
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
if (feature) {
|
|
241
|
+
// add some other items to the menu
|
|
242
|
+
}
|
|
235
243
|
});
|
|
236
244
|
```
|
|
237
245
|
|
|
@@ -239,6 +247,6 @@ contextmenu.on('open', function(evt){
|
|
|
239
247
|
|
|
240
248
|
```javascript
|
|
241
249
|
contextmenu.on('close', function (evt) {
|
|
242
|
-
|
|
250
|
+
// it's upon you
|
|
243
251
|
});
|
|
244
252
|
```
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { SingleItem, Options } from './types';
|
|
2
|
+
export declare const DEFAULT_OPTIONS: Options;
|
|
3
|
+
export declare const CSS_CLASSES: {
|
|
4
|
+
namespace: string;
|
|
5
|
+
container: string;
|
|
6
|
+
separator: string;
|
|
7
|
+
submenu: string;
|
|
8
|
+
hidden: string;
|
|
9
|
+
icon: string;
|
|
10
|
+
zoomIn: string;
|
|
11
|
+
zoomOut: string;
|
|
12
|
+
unselectable: string;
|
|
13
|
+
};
|
|
14
|
+
export declare const DEFAULT_ITEMS: SingleItem[];
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Item } from '../types';
|
|
2
|
+
export declare function createFragment(html: string): DocumentFragment;
|
|
3
|
+
export declare function getLineHeight(container: HTMLDivElement): number;
|
|
4
|
+
export declare function addMenuEntry(parentNode: HTMLUListElement, item: Item, isSubmenu?: boolean): HTMLLIElement;
|
|
5
|
+
export declare function addMenuEntries(container: HTMLUListElement, items: Item[], menuWidth: number): void;
|
package/dist/main.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Pixel } from 'ol/pixel';
|
|
2
|
+
import type { Coordinate } from 'ol/coordinate';
|
|
3
|
+
import OlMap from 'ol/Map';
|
|
4
|
+
import Control from 'ol/control/Control';
|
|
5
|
+
import { Item, MenuEntry, Options } from './types';
|
|
6
|
+
export default class ContextMenu extends Control {
|
|
7
|
+
protected map: OlMap;
|
|
8
|
+
protected container: HTMLDivElement;
|
|
9
|
+
protected coordinate: Coordinate;
|
|
10
|
+
protected pixel: Pixel;
|
|
11
|
+
protected contextMenuEventListener: (evt: MouseEvent) => void;
|
|
12
|
+
protected entryCallbackEventListener: (evt: MouseEvent) => void;
|
|
13
|
+
protected mapMoveListener: () => void;
|
|
14
|
+
protected lineHeight: number;
|
|
15
|
+
protected disabled: boolean;
|
|
16
|
+
protected opened: boolean;
|
|
17
|
+
protected items: Item[];
|
|
18
|
+
protected menuEntries: Map<string, MenuEntry>;
|
|
19
|
+
options: Options;
|
|
20
|
+
constructor(opts?: Partial<Options>);
|
|
21
|
+
clear(): void;
|
|
22
|
+
enable(): void;
|
|
23
|
+
disable(): void;
|
|
24
|
+
getDefaultItems(): import("./types").SingleItem[];
|
|
25
|
+
countItems(): number;
|
|
26
|
+
extend(items: Item[]): void;
|
|
27
|
+
closeMenu(): void;
|
|
28
|
+
isOpen(): boolean;
|
|
29
|
+
updatePosition(pixel: Pixel): void;
|
|
30
|
+
pop(): void;
|
|
31
|
+
shift(): void;
|
|
32
|
+
push(item: Item): void;
|
|
33
|
+
setMap(map: OlMap): void;
|
|
34
|
+
protected removeListeners(): void;
|
|
35
|
+
protected removeMenuEntry(id: string): void;
|
|
36
|
+
protected handleContextMenu(evt: MouseEvent): void;
|
|
37
|
+
protected openMenu(): void;
|
|
38
|
+
protected getMenuEntriesLength(): number;
|
|
39
|
+
protected positionContainer(): void;
|
|
40
|
+
protected handleMapMove(): void;
|
|
41
|
+
protected handleEntryCallback(evt: MouseEvent): void;
|
|
42
|
+
protected handleAddMenuEntry(item: MenuEntry, element: HTMLLIElement): void;
|
|
43
|
+
}
|
package/dist/ol-contextmenu.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
var S = Object.defineProperty;
|
|
2
2
|
var k = (s, t, e) => t in s ? S(s, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : s[t] = e;
|
|
3
|
-
var
|
|
3
|
+
var r = (s, t, e) => (k(s, typeof t != "symbol" ? t + "" : t, e), e);
|
|
4
4
|
import T from "ol/control/Control";
|
|
5
5
|
var M = /* @__PURE__ */ ((s) => (s.CONTEXTMENU = "contextmenu", s.CLICK = "click", s.DBLCLICK = "dblclick", s))(M || {}), p = /* @__PURE__ */ ((s) => (s.BEFOREOPEN = "beforeopen", s.OPEN = "open", s.CLOSE = "close", s.ADD_MENU_ENTRY = "add-menu-entry", s))(p || {});
|
|
6
6
|
const O = {
|
|
@@ -9,7 +9,7 @@ const O = {
|
|
|
9
9
|
eventType: M.CONTEXTMENU,
|
|
10
10
|
defaultItems: !0,
|
|
11
11
|
items: []
|
|
12
|
-
}, d = "ol-ctx-menu",
|
|
12
|
+
}, d = "ol-ctx-menu", a = {
|
|
13
13
|
namespace: d,
|
|
14
14
|
container: `${d}-container`,
|
|
15
15
|
separator: `${d}-separator`,
|
|
@@ -22,7 +22,7 @@ const O = {
|
|
|
22
22
|
}, x = [
|
|
23
23
|
{
|
|
24
24
|
text: "Zoom In",
|
|
25
|
-
classname: `${
|
|
25
|
+
classname: `${a.zoomIn} ${a.icon}`,
|
|
26
26
|
callback: (s, t) => {
|
|
27
27
|
const e = t.getView();
|
|
28
28
|
e.animate({
|
|
@@ -34,7 +34,7 @@ const O = {
|
|
|
34
34
|
},
|
|
35
35
|
{
|
|
36
36
|
text: "Zoom Out",
|
|
37
|
-
classname: `${
|
|
37
|
+
classname: `${a.zoomOut} ${a.icon}`,
|
|
38
38
|
callback: (s, t) => {
|
|
39
39
|
const e = t.getView();
|
|
40
40
|
e.animate({
|
|
@@ -98,7 +98,7 @@ function L(s, t, e = !1) {
|
|
|
98
98
|
const n = `_${Math.random().toString(36).slice(2, 11)}`;
|
|
99
99
|
if (typeof t != "string" && "text" in t) {
|
|
100
100
|
const u = `<span>${t.text}</span>`, f = E(u), c = document.createElement("li");
|
|
101
|
-
return t.classname = t.classname || "", t.icon && (t.classname === "" ? t.classname =
|
|
101
|
+
return t.classname = t.classname || "", t.icon && (t.classname === "" ? t.classname = a.icon : t.classname.includes(a.icon) === !1 && (t.classname += ` ${a.icon}`), c.setAttribute("style", `background-image:url(${t.icon})`)), c.id = n, c.className = t.classname, c.append(f), s.append(c), y.emit(
|
|
102
102
|
p.ADD_MENU_ENTRY,
|
|
103
103
|
{
|
|
104
104
|
id: n,
|
|
@@ -110,7 +110,7 @@ function L(s, t, e = !1) {
|
|
|
110
110
|
c
|
|
111
111
|
), c;
|
|
112
112
|
}
|
|
113
|
-
const i = `<li id="${n}" class="${
|
|
113
|
+
const i = `<li id="${n}" class="${a.separator}"><hr></li>`, o = E(i);
|
|
114
114
|
s.append(o);
|
|
115
115
|
const l = s.lastChild;
|
|
116
116
|
return y.emit(
|
|
@@ -129,9 +129,9 @@ function v(s, t, e) {
|
|
|
129
129
|
t.forEach((n) => {
|
|
130
130
|
if (typeof n != "string" && "items" in n && Array.isArray(n.items)) {
|
|
131
131
|
const i = L(s, n, !0);
|
|
132
|
-
i.classList.add(
|
|
132
|
+
i.classList.add(a.submenu);
|
|
133
133
|
const o = document.createElement("ul");
|
|
134
|
-
o.classList.add(
|
|
134
|
+
o.classList.add(a.container), o.style.width = `${e}px`, i.append(o), v(o, n.items, e);
|
|
135
135
|
} else
|
|
136
136
|
L(s, n);
|
|
137
137
|
});
|
|
@@ -140,30 +140,30 @@ function g(s, t) {
|
|
|
140
140
|
if (!s)
|
|
141
141
|
throw new Error(t);
|
|
142
142
|
}
|
|
143
|
-
class
|
|
143
|
+
class P extends T {
|
|
144
144
|
constructor(e = {}) {
|
|
145
145
|
g(typeof e == "object", "@param `opts` should be object type!");
|
|
146
146
|
const n = document.createElement("div");
|
|
147
147
|
super({ element: n });
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
148
|
+
r(this, "map");
|
|
149
|
+
r(this, "container");
|
|
150
|
+
r(this, "coordinate", []);
|
|
151
|
+
r(this, "pixel", []);
|
|
152
|
+
r(this, "contextMenuEventListener");
|
|
153
|
+
r(this, "entryCallbackEventListener");
|
|
154
|
+
r(this, "mapMoveListener");
|
|
155
|
+
r(this, "lineHeight", 0);
|
|
156
|
+
r(this, "disabled");
|
|
157
|
+
r(this, "opened");
|
|
158
|
+
r(this, "items", []);
|
|
159
|
+
r(this, "menuEntries", /* @__PURE__ */ new Map());
|
|
160
|
+
r(this, "options");
|
|
161
161
|
this.options = { ...O, ...e };
|
|
162
162
|
const i = document.createElement("ul");
|
|
163
163
|
n.append(i), n.style.width = `${this.options.width}px`, n.classList.add(
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
164
|
+
a.container,
|
|
165
|
+
a.unselectable,
|
|
166
|
+
a.hidden
|
|
167
167
|
), this.container = n, this.contextMenuEventListener = (o) => {
|
|
168
168
|
this.handleContextMenu(o);
|
|
169
169
|
}, this.entryCallbackEventListener = (o) => {
|
|
@@ -181,7 +181,7 @@ class z extends T {
|
|
|
181
181
|
clear() {
|
|
182
182
|
for (const e of this.menuEntries.keys())
|
|
183
183
|
this.removeMenuEntry(e);
|
|
184
|
-
this.container.replaceChildren();
|
|
184
|
+
this.container.replaceChildren(), this.container.append(document.createElement("ul"));
|
|
185
185
|
}
|
|
186
186
|
enable() {
|
|
187
187
|
this.disabled = !1;
|
|
@@ -203,7 +203,7 @@ class z extends T {
|
|
|
203
203
|
);
|
|
204
204
|
}
|
|
205
205
|
closeMenu() {
|
|
206
|
-
this.opened = !1, this.container.classList.add(
|
|
206
|
+
this.opened = !1, this.container.classList.add(a.hidden), this.dispatchEvent(p.CLOSE);
|
|
207
207
|
}
|
|
208
208
|
isOpen() {
|
|
209
209
|
return this.opened;
|
|
@@ -257,7 +257,7 @@ class z extends T {
|
|
|
257
257
|
));
|
|
258
258
|
}
|
|
259
259
|
openMenu() {
|
|
260
|
-
this.menuEntries.size !== 0 && (this.opened = !0, this.positionContainer(), this.container.classList.remove(
|
|
260
|
+
this.menuEntries.size !== 0 && (this.opened = !0, this.positionContainer(), this.container.classList.remove(a.hidden));
|
|
261
261
|
}
|
|
262
262
|
getMenuEntriesLength() {
|
|
263
263
|
return Array.from(this.menuEntries).filter(
|
|
@@ -274,13 +274,13 @@ class z extends T {
|
|
|
274
274
|
}, o = n.w >= i.w ? this.pixel[0] + 5 : this.pixel[0] - i.w;
|
|
275
275
|
this.container.style.left = `${o}px`, this.container.style.top = n.h >= i.h ? `${this.pixel[1] - 10}px` : `${this.pixel[1] - i.h}px`, this.container.style.right = "auto", this.container.style.bottom = "auto", n.w -= i.w;
|
|
276
276
|
const l = (c) => Array.from(c.children).filter(
|
|
277
|
-
(m) => m.tagName === "LI" && m.classList.contains(
|
|
277
|
+
(m) => m.tagName === "LI" && m.classList.contains(a.submenu)
|
|
278
278
|
);
|
|
279
279
|
let u = 0;
|
|
280
280
|
const f = (c, m) => {
|
|
281
281
|
u += 1, l(c).forEach((C) => {
|
|
282
282
|
const A = m >= i.w ? i.w - 8 : (i.w + 8) * -1, h = C.querySelector(
|
|
283
|
-
`ul.${
|
|
283
|
+
`ul.${a.container}`
|
|
284
284
|
), $ = Math.round(
|
|
285
285
|
this.lineHeight * Array.from(h.children).filter((N) => N.tagName === "LI").length
|
|
286
286
|
);
|
|
@@ -307,7 +307,6 @@ class z extends T {
|
|
|
307
307
|
this.menuEntries.set(e.id, e), "callback" in e && typeof e.callback == "function" && n.addEventListener("click", this.entryCallbackEventListener, !1);
|
|
308
308
|
}
|
|
309
309
|
}
|
|
310
|
-
window.ol?.control && (window.ol.control.ContextMenu = z);
|
|
311
310
|
export {
|
|
312
|
-
|
|
311
|
+
P as default
|
|
313
312
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(l,c){typeof exports=="object"&&typeof module<"u"?module.exports=c(require("ol/control/Control")):typeof define=="function"&&define.amd?define(["ol/control/Control"],c):(l=typeof globalThis<"u"?globalThis:l||self,l.ContextMenu=c(l.ol.control.Control))})(this,function(l){"use strict";var z=Object.defineProperty;var H=(l,c,f)=>c in l?z(l,c,{enumerable:!0,configurable:!0,writable:!0,value:f}):l[c]=f;var a=(l,c,f)=>(H(l,typeof c!="symbol"?c+"":c,f),f);const f=(n=>n&&typeof n=="object"&&"default"in n?n:{default:n})(l);var M=(n=>(n.CONTEXTMENU="contextmenu",n.CLICK="click",n.DBLCLICK="dblclick",n))(M||{}),m=(n=>(n.BEFOREOPEN="beforeopen",n.OPEN="open",n.CLOSE="close",n.ADD_MENU_ENTRY="add-menu-entry",n))(m||{});const
|
|
1
|
+
(function(l,c){typeof exports=="object"&&typeof module<"u"?module.exports=c(require("ol/control/Control")):typeof define=="function"&&define.amd?define(["ol/control/Control"],c):(l=typeof globalThis<"u"?globalThis:l||self,l.ContextMenu=c(l.ol.control.Control))})(this,function(l){"use strict";var z=Object.defineProperty;var H=(l,c,f)=>c in l?z(l,c,{enumerable:!0,configurable:!0,writable:!0,value:f}):l[c]=f;var a=(l,c,f)=>(H(l,typeof c!="symbol"?c+"":c,f),f);const f=(n=>n&&typeof n=="object"&&"default"in n?n:{default:n})(l);var M=(n=>(n.CONTEXTMENU="contextmenu",n.CLICK="click",n.DBLCLICK="dblclick",n))(M||{}),m=(n=>(n.BEFOREOPEN="beforeopen",n.OPEN="open",n.CLOSE="close",n.ADD_MENU_ENTRY="add-menu-entry",n))(m||{});const N={width:150,scrollAt:4,eventType:M.CONTEXTMENU,defaultItems:!0,items:[]},p="ol-ctx-menu",r={namespace:p,container:`${p}-container`,separator:`${p}-separator`,submenu:`${p}-submenu`,hidden:`${p}-hidden`,icon:`${p}-icon`,zoomIn:`${p}-zoom-in`,zoomOut:`${p}-zoom-out`,unselectable:"ol-unselectable"},w=[{text:"Zoom In",classname:`${r.zoomIn} ${r.icon}`,callback:(n,i)=>{const e=i.getView();e.animate({zoom:Number(e.getZoom())+1,duration:700,center:n.coordinate})}},{text:"Zoom Out",classname:`${r.zoomOut} ${r.icon}`,callback:(n,i)=>{const e=i.getView();e.animate({zoom:Number(e.getZoom())-1,duration:700,center:n.coordinate})}}];var A={exports:{}};function b(){}b.prototype={on:function(n,i,e){var t=this.e||(this.e={});return(t[n]||(t[n]=[])).push({fn:i,ctx:e}),this},once:function(n,i,e){var t=this;function s(){t.off(n,s),i.apply(e,arguments)}return s._=i,this.on(n,s,e)},emit:function(n){var i=[].slice.call(arguments,1),e=((this.e||(this.e={}))[n]||[]).slice(),t=0,s=e.length;for(t;t<s;t++)e[t].fn.apply(e[t].ctx,i);return this},off:function(n,i){var e=this.e||(this.e={}),t=e[n],s=[];if(t&&i)for(var o=0,h=t.length;o<h;o++)t[o].fn!==i&&t[o].fn._!==i&&s.push(t[o]);return s.length?e[n]=s:delete e[n],this}},A.exports=b;var S=A.exports.TinyEmitter=b;const x=new S;function y(n){const i=document.createDocumentFragment(),e=document.createElement("div");for(e.innerHTML=n;e.firstChild;)i.append(e.firstChild);return i}function k(n){const i=document.importNode(n),e=n.offsetWidth;i.style.cssText=`position: fixed; top: 0; left: 0; overflow: auto; visibility: hidden; pointer-events: none; height: unset; max-height: unset; width: ${e}px`;const t=y("<span>Foo</span>"),s=y("<span>Foo</span>"),o=document.createElement("li"),h=document.createElement("li");o.append(t),h.append(s),i.append(o),i.append(h),n.parentNode?.append(i);const E=i.offsetHeight/2;return n.parentNode?.removeChild(i),E}function $(n,i,e=!1){const t=`_${Math.random().toString(36).slice(2,11)}`;if(typeof i!="string"&&"text"in i){const E=`<span>${i.text}</span>`,v=y(E),u=document.createElement("li");return i.classname=i.classname||"",i.icon&&(i.classname===""?i.classname=r.icon:i.classname.includes(r.icon)===!1&&(i.classname+=` ${r.icon}`),u.setAttribute("style",`background-image:url(${i.icon})`)),u.id=t,u.className=i.classname,u.append(v),n.append(u),x.emit(m.ADD_MENU_ENTRY,{id:t,isSubmenu:e,isSeparator:!1,callback:"callback"in i?i.callback:null,data:"data"in i?i.data:null},u),u}const s=`<li id="${t}" class="${r.separator}"><hr></li>`,o=y(s);n.append(o);const h=n.lastChild;return x.emit(m.ADD_MENU_ENTRY,{id:t,isSubmenu:e,isSeparator:!0,callback:null,data:null},h),h}function L(n,i,e){i.forEach(t=>{if(typeof t!="string"&&"items"in t&&Array.isArray(t.items)){const s=$(n,t,!0);s.classList.add(r.submenu);const o=document.createElement("ul");o.classList.add(r.container),o.style.width=`${e}px`,s.append(o),L(o,t.items,e)}else $(n,t)})}const P="";function C(n,i){if(!n)throw new Error(i)}class T extends f.default{constructor(e={}){C(typeof e=="object","@param `opts` should be object type!");const t=document.createElement("div");super({element:t});a(this,"map");a(this,"container");a(this,"coordinate",[]);a(this,"pixel",[]);a(this,"contextMenuEventListener");a(this,"entryCallbackEventListener");a(this,"mapMoveListener");a(this,"lineHeight",0);a(this,"disabled");a(this,"opened");a(this,"items",[]);a(this,"menuEntries",new Map);a(this,"options");this.options={...N,...e};const s=document.createElement("ul");t.append(s),t.style.width=`${this.options.width}px`,t.classList.add(r.container,r.unselectable,r.hidden),this.container=t,this.contextMenuEventListener=o=>{this.handleContextMenu(o)},this.entryCallbackEventListener=o=>{this.handleEntryCallback(o)},this.mapMoveListener=()=>{this.handleMapMove()},this.disabled=!1,this.opened=!1,x.on(m.ADD_MENU_ENTRY,(o,h)=>{this.handleAddMenuEntry(o,h)},this)}clear(){for(const e of this.menuEntries.keys())this.removeMenuEntry(e);this.container.replaceChildren(),this.container.append(document.createElement("ul"))}enable(){this.disabled=!1}disable(){this.disabled=!0}getDefaultItems(){return w}countItems(){return this.menuEntries.size}extend(e){C(Array.isArray(e),"@param `items` should be an Array."),L(this.container.firstElementChild,e,this.options.width)}closeMenu(){this.opened=!1,this.container.classList.add(r.hidden),this.dispatchEvent(m.CLOSE)}isOpen(){return this.opened}updatePosition(e){C(Array.isArray(e),"@param `pixel` should be an Array."),this.isOpen()&&(this.pixel=e,this.positionContainer())}pop(){const e=Array.from(this.menuEntries.keys()).pop();e&&this.removeMenuEntry(e)}shift(){const e=Array.from(this.menuEntries.keys()).shift();e&&this.removeMenuEntry(e)}push(e){e&&this.extend([e])}setMap(e){if(super.setMap(e),e){this.map=e,this.map.getViewport().addEventListener(this.options.eventType,this.contextMenuEventListener,!1),this.map.on("movestart",()=>{this.handleMapMove()}),this.items=this.options.defaultItems?this.options.items.concat(w):this.options.items,L(this.container.firstElementChild,this.items,this.options.width);const t=this.getMenuEntriesLength();this.lineHeight=t>0?this.container.offsetHeight/t:k(this.container)}else this.removeListeners(),this.clear()}removeListeners(){this.map.getViewport().removeEventListener(this.options.eventType,this.contextMenuEventListener,!1)}removeMenuEntry(e){const t=document.getElementById(e);t?.remove(),t?.removeEventListener("click",this.entryCallbackEventListener),this.menuEntries.delete(e)}handleContextMenu(e){this.coordinate=this.map.getEventCoordinate(e),this.pixel=this.map.getEventPixel(e),this.dispatchEvent({type:m.BEFOREOPEN,pixel:this.pixel,coordinate:this.coordinate}),!this.disabled&&(this.options.eventType===M.CONTEXTMENU&&(e.stopPropagation(),e.preventDefault()),this.openMenu(),e.target?.addEventListener("pointerdown",t=>{this.opened&&(t.stopPropagation(),this.closeMenu())},{once:!0}))}openMenu(){this.menuEntries.size!==0&&(this.opened=!0,this.positionContainer(),this.container.classList.remove(r.hidden))}getMenuEntriesLength(){return Array.from(this.menuEntries).filter(([,e])=>e.isSeparator===!1||e.isSubmenu===!1).length}positionContainer(){const e=this.map.getSize()||[0,0],t={w:e[0]-this.pixel[0],h:e[1]-this.pixel[1]},s={w:this.container.offsetWidth,h:Math.round(this.lineHeight*this.getMenuEntriesLength())},o=t.w>=s.w?this.pixel[0]+5:this.pixel[0]-s.w;this.container.style.left=`${o}px`,this.container.style.top=t.h>=s.h?`${this.pixel[1]-10}px`:`${this.pixel[1]-s.h}px`,this.container.style.right="auto",this.container.style.bottom="auto",t.w-=s.w;const h=u=>Array.from(u.children).filter(g=>g.tagName==="LI"&&g.classList.contains(r.submenu));let E=0;const v=(u,g)=>{E+=1,h(u).forEach(_=>{const D=g>=s.w?s.w-8:(s.w+8)*-1,d=_.querySelector(`ul.${r.container}`),O=Math.round(this.lineHeight*Array.from(d.children).filter(I=>I.tagName==="LI").length);d.style.left=`${D}px`,d.style.right="auto",d.style.top=t.h>=O+s.h?"0":`-${d.offsetHeight-25}px`,d.style.bottom="auto",d.style.zIndex=String(E),h(d).length>0&&v(d,g-s.w)})};v(this.container.firstElementChild,t.w)}handleMapMove(){this.closeMenu()}handleEntryCallback(e){e.preventDefault(),e.stopPropagation();const t=e.currentTarget,s=this.menuEntries.get(t.id);if(!s)return;const o={coordinate:this.coordinate,data:s.data};this.closeMenu(),s.callback?.(o,this.map)}handleAddMenuEntry(e,t){this.menuEntries.set(e.id,e),"callback"in e&&typeof e.callback=="function"&&t.addEventListener("click",this.entryCallbackEventListener,!1)}}return T});
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { Coordinate } from 'ol/coordinate';
|
|
2
|
+
import type { Pixel } from 'ol/pixel';
|
|
3
|
+
import { Map as OlMap } from 'ol';
|
|
4
|
+
import BaseEvent from 'ol/events/Event';
|
|
5
|
+
export declare enum EventTypes {
|
|
6
|
+
CONTEXTMENU = "contextmenu",
|
|
7
|
+
CLICK = "click",
|
|
8
|
+
DBLCLICK = "dblclick"
|
|
9
|
+
}
|
|
10
|
+
export declare enum CustomEventTypes {
|
|
11
|
+
BEFOREOPEN = "beforeopen",
|
|
12
|
+
OPEN = "open",
|
|
13
|
+
CLOSE = "close",
|
|
14
|
+
ADD_MENU_ENTRY = "add-menu-entry"
|
|
15
|
+
}
|
|
16
|
+
export interface ContextMenuEvent extends BaseEvent {
|
|
17
|
+
coordinate: Coordinate;
|
|
18
|
+
pixel: Pixel;
|
|
19
|
+
}
|
|
20
|
+
export declare type CallbackObject = {
|
|
21
|
+
coordinate: Coordinate;
|
|
22
|
+
data: unknown;
|
|
23
|
+
};
|
|
24
|
+
export declare type ItemSeparator = '-';
|
|
25
|
+
export declare type SingleItem = {
|
|
26
|
+
text: string;
|
|
27
|
+
classname?: string;
|
|
28
|
+
icon?: string;
|
|
29
|
+
callback: (object: CallbackObject, map: OlMap) => void;
|
|
30
|
+
data?: unknown;
|
|
31
|
+
};
|
|
32
|
+
export declare type MenuEntry = {
|
|
33
|
+
id: string;
|
|
34
|
+
isSubmenu: boolean;
|
|
35
|
+
isSeparator: boolean;
|
|
36
|
+
callback: SingleItem['callback'] | null;
|
|
37
|
+
data: unknown;
|
|
38
|
+
};
|
|
39
|
+
export declare type ItemWithNested = {
|
|
40
|
+
text: string;
|
|
41
|
+
classname?: string;
|
|
42
|
+
icon?: string;
|
|
43
|
+
items: Item[];
|
|
44
|
+
};
|
|
45
|
+
export declare type Item = SingleItem | ItemSeparator | ItemWithNested;
|
|
46
|
+
export declare type Options = {
|
|
47
|
+
width: number;
|
|
48
|
+
scrollAt: number;
|
|
49
|
+
eventType: `${EventTypes}`;
|
|
50
|
+
defaultItems: boolean;
|
|
51
|
+
items: Item[];
|
|
52
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ol-contextmenu",
|
|
3
|
-
"version": "5.0.1
|
|
3
|
+
"version": "5.0.1",
|
|
4
4
|
"description": "Custom Context Menu for Openlayers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/ol-contextmenu.umd.cjs",
|
|
@@ -8,9 +8,17 @@
|
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
10
|
"import": "./dist/ol-contextmenu.js",
|
|
11
|
-
"require": "./dist/ol-contextmenu.umd.cjs"
|
|
11
|
+
"require": "./dist/ol-contextmenu.umd.cjs",
|
|
12
|
+
"types": "./dist/ol-contextmenu.d.ts"
|
|
13
|
+
},
|
|
14
|
+
"./ol-contextmenu.css": {
|
|
15
|
+
"import": "./dist/ol-contextmenu.css",
|
|
16
|
+
"require": "./dist/ol-contextmenu.css"
|
|
12
17
|
}
|
|
13
18
|
},
|
|
19
|
+
"files": [
|
|
20
|
+
"./dist"
|
|
21
|
+
],
|
|
14
22
|
"types": "./dist/ol-contextmenu.d.ts",
|
|
15
23
|
"author": "Jonatas Walker",
|
|
16
24
|
"homepage": "https://github.com/jonataswalker/ol-contextmenu",
|
|
@@ -26,24 +34,19 @@
|
|
|
26
34
|
"node": "^16 || ^18",
|
|
27
35
|
"npm": ">=8"
|
|
28
36
|
},
|
|
29
|
-
"files": [
|
|
30
|
-
"dist/"
|
|
31
|
-
],
|
|
32
37
|
"scripts": {
|
|
33
38
|
"dev": "vite",
|
|
34
|
-
"build": "
|
|
39
|
+
"build": "rimraf ./dist && vite build",
|
|
35
40
|
"preview": "vite preview",
|
|
36
41
|
"lint": "eslint --cache --ext .js .",
|
|
37
42
|
"lint:fix": "npm run lint -- --fix",
|
|
38
|
-
"
|
|
39
|
-
"
|
|
43
|
+
"test": "jest",
|
|
44
|
+
"prepublishOnly": "npm run lint && npm test && npm run build"
|
|
40
45
|
},
|
|
41
46
|
"devDependencies": {
|
|
42
|
-
"@swc/core": "^1.3.
|
|
47
|
+
"@swc/core": "^1.3.2",
|
|
43
48
|
"@swc/jest": "^0.2.22",
|
|
44
|
-
"@types/jest": "^29.0.
|
|
45
|
-
"@vitejs/plugin-legacy": "^2.1.0",
|
|
46
|
-
"canvas": "^2.10.1",
|
|
49
|
+
"@types/jest": "^29.0.3",
|
|
47
50
|
"eslint": "^8.23.1",
|
|
48
51
|
"eslint-config-jwalker": "^7.9.2",
|
|
49
52
|
"eslint-config-prettier": "^8.5.0",
|
|
@@ -54,8 +57,10 @@
|
|
|
54
57
|
"jest-environment-jsdom": "^29.0.3",
|
|
55
58
|
"ol": "^7.1.0",
|
|
56
59
|
"prettier": "^2.7.1",
|
|
60
|
+
"rimraf": "^3.0.2",
|
|
57
61
|
"typescript": "^4.8.3",
|
|
58
|
-
"vite": "^3.1.
|
|
62
|
+
"vite": "^3.1.3",
|
|
63
|
+
"vite-plugin-dts": "^1.5.0"
|
|
59
64
|
},
|
|
60
65
|
"peerDependencies": {
|
|
61
66
|
"ol": "^7.1.0"
|