@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.
@@ -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
- if (this.type === 'line') {
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 (this.type === 'inline') {
36
- return '<div>' + this.component() + '</div>';
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="{{!!self.submenu}}" onmouseover="self.parent.parent.open(self)">
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
- // if (typeof(value.modal.cursor) !== 'undefined') {
53
- // value.modal.options[value.modal.cursor].cursor = false;
54
- // delete value.modal.cursor;
55
- // }
61
+ // Reset any cursor
62
+ resetCursor.call(self.modal);
63
+ }
56
64
 
57
- console.log(self.cursor,self.options);
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
- // Open handler
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
- let template = `<Modal :closed="true" :ref="self.modal" :responsive="false" :autoadjust="true" :onclose="self.onclose">
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
- const openSubmenu = function() {
143
- if (typeof(this.options[this.cursor]) !== 'undefined') {
144
- // Get the selected cursor
145
- let item = this.options[this.cursor];
146
- // Open submenu in case that exists
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
- const closeSubmenu = function() {
154
- this.parent.parent.close(this.parent.parent.modalIndex);
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(e, options, x, y) {
255
+ self.open = function(options, x, y, e) {
178
256
  // Get the main modal
179
257
  let modal = self.modals[0].modal;
180
- // Click on the top level menu toggle the state of the menu
181
- if (e.type === 'click') {
182
- modal.closed = ! modal.closed;
183
- } else if (e.type === 'contextmenu') {
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
- closeSubmenu.call(m);
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.el.contains(e.relatedTarget)) {
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(e, self.options, x, y);
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
@@ -11,7 +11,6 @@
11
11
  height: initial;
12
12
  min-width: 250px;
13
13
  min-height: initial;
14
- padding-bottom: 6px;
15
14
  }
16
15
 
17
16
  .lm-menu .lm-modal::-webkit-scrollbar {
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.1",
17
+ "@lemonadejs/modal": "^2.3.3",
18
18
  "lemonadejs": "^3.4.0"
19
19
  },
20
20
  "main": "dist/index.js",
21
- "version": "1.0.3"
21
+ "types": "dist/index.d.ts",
22
+ "version": "1.0.6"
22
23
  }