@lemonadejs/contextmenu 1.0.3 → 1.0.6
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/dist/index.d.ts +32 -0
- package/dist/index.js +140 -37
- package/dist/style.css +0 -1
- package/package.json +3 -2
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Official Type definitions for LemonadeJS plugins
|
|
3
|
+
* https://lemonadejs.net
|
|
4
|
+
* Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
interface Contextmenu {
|
|
8
|
+
(): any
|
|
9
|
+
[key: string]: any
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface Items {
|
|
13
|
+
type: 'line' | undefined;
|
|
14
|
+
title?: string;
|
|
15
|
+
icon?: string;
|
|
16
|
+
submenu?: Items[];
|
|
17
|
+
render?: (e: MouseEvent, element: HTMLElement) => void;
|
|
18
|
+
onclick?: (e: MouseEvent, element: HTMLElement) => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface Options {
|
|
22
|
+
/** Modal is closed */
|
|
23
|
+
options?: Items[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface instance {
|
|
27
|
+
options: boolean;
|
|
28
|
+
open: (options: Options, x: number, y: number, e: MouseEvent) => void;
|
|
29
|
+
close: () => void;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export declare function Modal(el: HTMLElement, options?: Options): instance;
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ if (!lemonade && typeof (require) === 'function') {
|
|
|
3
3
|
}
|
|
4
4
|
|
|
5
5
|
if (! Modal && typeof (require) === 'function') {
|
|
6
|
-
var Modal = require('@lemonadejs/modal
|
|
6
|
+
var Modal = require('@lemonadejs/modal');
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
; (function (global, factory) {
|
|
@@ -30,12 +30,19 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
30
30
|
|
|
31
31
|
const Item = function() {
|
|
32
32
|
let self = this;
|
|
33
|
-
|
|
33
|
+
|
|
34
|
+
self.onload = function() {
|
|
35
|
+
if (typeof(self.render) === 'function') {
|
|
36
|
+
self.render.call(self, self.el);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (self.type === 'line') {
|
|
34
41
|
return `<hr />`;
|
|
35
|
-
} else if (
|
|
36
|
-
return
|
|
42
|
+
} else if (self.type === 'inline') {
|
|
43
|
+
return `<div></div>`;
|
|
37
44
|
} else {
|
|
38
|
-
return `<div class="lm-menu-item" data-cursor="{{self.cursor}}" data-icon="{{self.icon}}" data-submenu="{{
|
|
45
|
+
return `<div class="lm-menu-item" data-cursor="{{self.cursor}}" data-icon="{{self.icon}}" data-submenu="{{self.submenu?true:''}}" onmouseup="self.parent.parent.mouseUp(self, e)" onmouseenter="self.parent.parent.mouseEnter(self)" onmouseleave="self.parent.parent.mouseLeave(self)">
|
|
39
46
|
<a>{{self.title}}</a> <div>{{self.shortcut}}</div>
|
|
40
47
|
</div>`;
|
|
41
48
|
}
|
|
@@ -44,20 +51,29 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
44
51
|
const Create = function() {
|
|
45
52
|
let self = this;
|
|
46
53
|
|
|
54
|
+
// Delay on open
|
|
55
|
+
let delayTimer;
|
|
47
56
|
// Save the position of this modal
|
|
48
57
|
let index = self.parent.modals.length;
|
|
49
58
|
|
|
50
59
|
// Close handler
|
|
51
60
|
self.onclose = function() {
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
// }
|
|
61
|
+
// Reset any cursor
|
|
62
|
+
resetCursor.call(self.modal);
|
|
63
|
+
}
|
|
56
64
|
|
|
57
|
-
|
|
65
|
+
/**
|
|
66
|
+
* Close the modal
|
|
67
|
+
*/
|
|
68
|
+
self.close = function() {
|
|
69
|
+
// Close modals with higher level
|
|
70
|
+
self.parent.close(index);
|
|
58
71
|
}
|
|
59
72
|
|
|
60
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Open submenu handler
|
|
75
|
+
* @param s
|
|
76
|
+
*/
|
|
61
77
|
self.open = function(s) {
|
|
62
78
|
if (s.submenu) {
|
|
63
79
|
// Get the modal in the container of modals
|
|
@@ -70,18 +86,13 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
70
86
|
let parent = self.parent.modals[index].modal;
|
|
71
87
|
// Get the self of the modal
|
|
72
88
|
let modal = item.modal;
|
|
73
|
-
|
|
89
|
+
// Update modal content
|
|
74
90
|
if (modal.options !== s.submenu) {
|
|
75
91
|
// Close modals with higher level
|
|
76
92
|
modal.options = s.submenu;
|
|
77
|
-
// Remove cursor
|
|
78
|
-
if (modal.cursor) {
|
|
79
|
-
delete modal.cursor;
|
|
80
|
-
}
|
|
81
93
|
// Close other modals
|
|
82
94
|
self.parent.close(index+1);
|
|
83
95
|
}
|
|
84
|
-
|
|
85
96
|
// Open modal
|
|
86
97
|
modal.closed = false;
|
|
87
98
|
// Update selected modal
|
|
@@ -89,13 +100,42 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
89
100
|
// Define the position
|
|
90
101
|
modal.top = parent.top + s.el.offsetTop + 2;
|
|
91
102
|
modal.left = parent.left + 248;
|
|
103
|
+
// Place cursor in the first position
|
|
104
|
+
modal.options[0].cursor = true;
|
|
105
|
+
// Position cursor
|
|
106
|
+
modal.cursor = 0;
|
|
92
107
|
} else {
|
|
93
108
|
// Close modals with higher level
|
|
94
109
|
self.parent.close(index+1);
|
|
95
110
|
}
|
|
96
111
|
}
|
|
97
112
|
|
|
98
|
-
|
|
113
|
+
// Mouse open
|
|
114
|
+
self.mouseUp = function(s, e) {
|
|
115
|
+
if (typeof(s.onclick) === 'function') {
|
|
116
|
+
s.onclick.call(s, e, s.el);
|
|
117
|
+
}
|
|
118
|
+
if (! s.submenu) {
|
|
119
|
+
self.close();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
self.mouseEnter = function(s) {
|
|
124
|
+
if (delayTimer) {
|
|
125
|
+
clearTimeout(delayTimer);
|
|
126
|
+
}
|
|
127
|
+
delayTimer = setTimeout(function() {
|
|
128
|
+
self.open(s);
|
|
129
|
+
}, 200);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
self.mouseLeave = function() {
|
|
133
|
+
if (delayTimer) {
|
|
134
|
+
clearTimeout(delayTimer);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
let template = `<Modal :closed="true" :ref="self.modal" :responsive="false" :auto-adjust="true" :onclose="self.onclose" :focus="false" :layers="false">
|
|
99
139
|
<div class="lm-menu-submenu">
|
|
100
140
|
<Item :loop="self.options" />
|
|
101
141
|
</div>
|
|
@@ -137,21 +177,59 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
137
177
|
this.options[cursor].cursor = true;
|
|
138
178
|
// Cursor
|
|
139
179
|
this.cursor = cursor;
|
|
180
|
+
// If is line move to the next one
|
|
181
|
+
if (this.options[cursor].type === 'line') {
|
|
182
|
+
setCursor.call(this, direction);
|
|
183
|
+
}
|
|
140
184
|
}
|
|
141
185
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
186
|
+
/**
|
|
187
|
+
* Reset the cursor for a contextmenu
|
|
188
|
+
*/
|
|
189
|
+
const resetCursor = function() {
|
|
190
|
+
// Contextmenu modal
|
|
191
|
+
let item = this.options[this.cursor];
|
|
192
|
+
// Cursor is found so reset it
|
|
193
|
+
if (typeof(item) !== 'undefined') {
|
|
194
|
+
// Remove the cursor style
|
|
195
|
+
item.cursor = false;
|
|
196
|
+
// Delete reference index
|
|
197
|
+
delete this.cursor;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const actionCursor = function(e) {
|
|
202
|
+
// Contextmenu modal
|
|
203
|
+
let item = this.options[this.cursor];
|
|
204
|
+
// Cursor is found so reset it
|
|
205
|
+
if (typeof(item) !== 'undefined') {
|
|
206
|
+
// Execute action
|
|
207
|
+
if (typeof(item.onclick) === 'function') {
|
|
208
|
+
item.onclick.call(item, e, item.el);
|
|
209
|
+
}
|
|
210
|
+
// Open sub menu in case exists
|
|
147
211
|
if (item.submenu) {
|
|
148
212
|
this.parent.open(item);
|
|
213
|
+
return true;
|
|
149
214
|
}
|
|
150
215
|
}
|
|
151
216
|
}
|
|
152
217
|
|
|
153
|
-
|
|
154
|
-
|
|
218
|
+
/**
|
|
219
|
+
* Open a sub option of the contextmenu by a user action
|
|
220
|
+
* @returns {boolean}
|
|
221
|
+
*/
|
|
222
|
+
const openSubmenu = function() {
|
|
223
|
+
// Get the selected cursor
|
|
224
|
+
let item = this.options[this.cursor];
|
|
225
|
+
// Open submenu
|
|
226
|
+
if (typeof(item) !== 'undefined') {
|
|
227
|
+
// Open submenu in case that exists
|
|
228
|
+
if (item.submenu) {
|
|
229
|
+
this.parent.open(item);
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
155
233
|
}
|
|
156
234
|
|
|
157
235
|
const Contextmenu = function() {
|
|
@@ -174,16 +252,19 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
174
252
|
return s;
|
|
175
253
|
}
|
|
176
254
|
|
|
177
|
-
self.open = function(
|
|
255
|
+
self.open = function(options, x, y, e) {
|
|
178
256
|
// Get the main modal
|
|
179
257
|
let modal = self.modals[0].modal;
|
|
180
|
-
//
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
258
|
+
// Reset cursor
|
|
259
|
+
resetCursor.call(modal);
|
|
260
|
+
|
|
261
|
+
// Current state
|
|
262
|
+
if (! e || e.type === 'contextmenu') {
|
|
184
263
|
modal.closed = false;
|
|
264
|
+
} else if (e.type === 'click') {
|
|
265
|
+
modal.closed = ! modal.closed;
|
|
185
266
|
}
|
|
186
|
-
|
|
267
|
+
|
|
187
268
|
// If the modal is open and the content is different from what is shown
|
|
188
269
|
if (modal.closed === false) {
|
|
189
270
|
// Close modals with higher level
|
|
@@ -191,6 +272,7 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
191
272
|
// Define new position
|
|
192
273
|
modal.top = y;
|
|
193
274
|
modal.left = x;
|
|
275
|
+
// Update the data
|
|
194
276
|
if (modal.options !== options) {
|
|
195
277
|
// Refresh content
|
|
196
278
|
modal.options = options;
|
|
@@ -199,50 +281,71 @@ if (! Modal && typeof (require) === 'function') {
|
|
|
199
281
|
}
|
|
200
282
|
|
|
201
283
|
self.close = function(level) {
|
|
284
|
+
// Close all modals from the level specified
|
|
202
285
|
self.modals.forEach(function(value, k) {
|
|
203
286
|
if (k >= level) {
|
|
204
287
|
// Close the modal
|
|
205
288
|
value.modal.closed = true;
|
|
206
289
|
}
|
|
207
290
|
});
|
|
208
|
-
|
|
209
|
-
self.modalIndex = level ? level-1 : 0;
|
|
291
|
+
// Keep the index of the modal that is opened
|
|
292
|
+
self.modalIndex = level ? level - 1 : 0;
|
|
210
293
|
}
|
|
211
294
|
|
|
212
295
|
self.onload = function() {
|
|
213
296
|
if (! self.root) {
|
|
214
297
|
self.root = self.el.parentNode;
|
|
215
298
|
}
|
|
299
|
+
|
|
216
300
|
// Keyboard event
|
|
217
301
|
self.root.addEventListener("keydown", function(e) {
|
|
218
302
|
// Modal object
|
|
219
303
|
let m = self.modals[self.modalIndex].modal;
|
|
304
|
+
// Something happens
|
|
305
|
+
let ret = false;
|
|
306
|
+
// Control
|
|
220
307
|
if (e.key === 'ArrowLeft') {
|
|
221
|
-
|
|
308
|
+
if (self.modalIndex > 0) {
|
|
309
|
+
// Close modal
|
|
310
|
+
m.parent.close();
|
|
311
|
+
// Action happened
|
|
312
|
+
ret = true;
|
|
313
|
+
}
|
|
222
314
|
} else if (e.key === 'ArrowRight') {
|
|
223
|
-
openSubmenu.call(m);
|
|
315
|
+
ret = openSubmenu.call(m);
|
|
224
316
|
} else if (e.key === 'ArrowUp') {
|
|
225
317
|
setCursor.call(m, 0);
|
|
226
318
|
} else if (e.key === 'ArrowDown') {
|
|
227
319
|
setCursor.call(m, 1);
|
|
320
|
+
} else if (e.key === 'Enter') {
|
|
321
|
+
ret = actionCursor.call(m, e);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Something important happen so block any progression
|
|
325
|
+
if (ret === true) {
|
|
326
|
+
e.preventDefault();
|
|
327
|
+
e.stopImmediatePropagation();
|
|
228
328
|
}
|
|
229
329
|
});
|
|
230
330
|
|
|
231
331
|
// Create event for focus out
|
|
232
332
|
self.root.addEventListener("focusout", (e) => {
|
|
233
|
-
if (! self.
|
|
333
|
+
if (! self.root.contains(e.relatedTarget)) {
|
|
234
334
|
self.close(0);
|
|
235
335
|
}
|
|
236
336
|
});
|
|
337
|
+
|
|
237
338
|
// Parent
|
|
238
339
|
self.root.addEventListener("contextmenu", function(e) {
|
|
239
340
|
let [x,y] = getCoords(e);
|
|
240
341
|
// Open the context menu
|
|
241
|
-
self.open(
|
|
342
|
+
self.open(self.options, x, y, e);
|
|
242
343
|
e.preventDefault();
|
|
243
344
|
e.stopImmediatePropagation();
|
|
244
345
|
});
|
|
346
|
+
|
|
245
347
|
self.root.setAttribute('tabindex', -1);
|
|
348
|
+
|
|
246
349
|
// Create first menu
|
|
247
350
|
self.create();
|
|
248
351
|
}
|
package/dist/style.css
CHANGED
package/package.json
CHANGED
|
@@ -14,9 +14,10 @@
|
|
|
14
14
|
"build": "webpack --config webpack.config.js"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@lemonadejs/modal": "^2.3.
|
|
17
|
+
"@lemonadejs/modal": "^2.3.3",
|
|
18
18
|
"lemonadejs": "^3.4.0"
|
|
19
19
|
},
|
|
20
20
|
"main": "dist/index.js",
|
|
21
|
-
"
|
|
21
|
+
"types": "dist/index.d.ts",
|
|
22
|
+
"version": "1.0.6"
|
|
22
23
|
}
|