@lemonadejs/contextmenu 1.0.0

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.js ADDED
@@ -0,0 +1,173 @@
1
+ if (!lemonade && typeof (require) === 'function') {
2
+ var lemonade = require('lemonadejs');
3
+ }
4
+
5
+ if (!Modal && typeof (require) === 'function') {
6
+ var Modal = require('@lemonadejs/modal');
7
+ }
8
+
9
+ ; (function (global, factory) {
10
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
11
+ typeof define === 'function' && define.amd ? define(factory) :
12
+ global.Contextmenu = factory();
13
+ }(this, (function () {
14
+
15
+ // Level
16
+ let index = 0;
17
+
18
+ // Get the coordinates of the action
19
+ const getCoords = function(e) {
20
+ let x;
21
+ let y;
22
+
23
+ if (e.changedTouches && e.changedTouches[0]) {
24
+ x = e.changedTouches[0].clientX;
25
+ y = e.changedTouches[0].clientY;
26
+ } else {
27
+ x = e.clientX;
28
+ y = e.clientY;
29
+ }
30
+
31
+ return [x,y];
32
+ }
33
+
34
+ const Item = function() {
35
+ if (this.type === 'line') {
36
+ return `<hr />`;
37
+ } else {
38
+ return `<div data-icon="{{self.icon}}" data-submenu="{{!!self.submenu}}" onmouseover="self.parent.parent.open(e, self)">
39
+ <a>{{self.title}}</a> <span>{{self.shortcut}}</span>
40
+ </div>`;
41
+ }
42
+ }
43
+
44
+ const Create = function() {
45
+ let self = this;
46
+
47
+ self.open = function(e, s) {
48
+ if (s.submenu) {
49
+ // Get the modal in the container of modals
50
+ let item = self.parent.modals[self.index+1];
51
+ if (! item) {
52
+ // Modal need to be created
53
+ item = self.parent.create();
54
+ }
55
+ // Get the parent from this one
56
+ let parent = self.parent.modals[self.index].modal;
57
+ // Get the self of the modal
58
+ let modal = item.modal;
59
+
60
+ if (modal.options !== s.submenu) {
61
+ // Close modals with higher level
62
+ modal.options = s.submenu;
63
+ // Close other modals
64
+ self.parent.close(self.index+1);
65
+ }
66
+
67
+ // Open modal
68
+ modal.closed = false;
69
+ // Define the position
70
+ modal.top = parent.top + e.target.offsetTop + 2;
71
+ modal.left = parent.left + 248;
72
+ } else {
73
+ // Close modals with higher level
74
+ self.parent.close(self.index+1);
75
+ }
76
+ }
77
+
78
+ let template = `<Modal :closed="true" :ref="self.modal">
79
+ <div class="lm-menu-submenu">
80
+ <Item :loop="self.options" />
81
+ </div>
82
+ </Modal>`;
83
+
84
+ return lemonade.element(template, self, { Item: Item });
85
+ }
86
+
87
+ const Contextmenu = function() {
88
+ let self = this;
89
+
90
+ // Container for all modals
91
+ self.modals = [];
92
+
93
+ self.create = function() {
94
+ // Create a new self for each modal
95
+ let s = {
96
+ index: index++,
97
+ parent: self,
98
+ };
99
+ // Render the modal inside the main container
100
+ lemonade.render(Create, self.el, s);
101
+ // Add the reference of the modal in a container
102
+ self.modals.push(s);
103
+ // Return self
104
+ return s;
105
+ }
106
+
107
+ self.open = function(e, options, x, y) {
108
+ // Get the main modal
109
+ let modal = self.modals[0].modal;
110
+ // Click on the top level menu toggle the state of the menu
111
+ if (e.type == 'click') {
112
+ modal.closed = ! modal.closed;
113
+ } else if (e.type == 'contextmenu') {
114
+ modal.closed = false;
115
+ }
116
+
117
+ // If the modal is open and the content is different from what is shown
118
+ if (modal.closed === false) {
119
+ // Close modals with higher level
120
+ self.close(1);
121
+ // Define new position
122
+ modal.top = y;
123
+ modal.left = x;
124
+ if (modal.options !== options) {
125
+ // Refresh content
126
+ modal.options = options;
127
+ }
128
+ }
129
+ }
130
+
131
+ self.close = function(level) {
132
+ self.modals.forEach(function(value, k) {
133
+ if (k >= level) {
134
+ value.modal.closed = true;
135
+ }
136
+ })
137
+ }
138
+
139
+ self.onload = function() {
140
+ if (! self.root) {
141
+ self.root = self.el.parentNode;
142
+ }
143
+ // Create event for focus out
144
+ self.root.addEventListener("focusout", (e) => {
145
+ self.close(0);
146
+ });
147
+ // Parent
148
+ self.root.addEventListener("contextmenu", function(e) {
149
+ let [x,y] = getCoords(e);
150
+ // Open the context menu
151
+ self.open(e, self.options, x, y);
152
+ e.preventDefault();
153
+ e.stopImmediatePropagation();
154
+ });
155
+ self.root.setAttribute('tabindex', -1);
156
+ // Create first menu
157
+ self.create();
158
+ }
159
+
160
+ return `<div class="lm-menu"></div>`;
161
+ }
162
+
163
+ lemonade.setComponents({ Contextmenu: Contextmenu });
164
+
165
+ return function (root, options) {
166
+ if (typeof (root) === 'object') {
167
+ lemonade.render(Contextmenu, root, options)
168
+ return options;
169
+ } else {
170
+ return Contextmenu.call(this, root)
171
+ }
172
+ }
173
+ })));
package/dist/style.css ADDED
@@ -0,0 +1,72 @@
1
+ .lm-menu .lm-modal {
2
+ color: #555;
3
+ user-select: none;
4
+ border: 1px solid transparent;
5
+ border-radius: 4px;
6
+ box-shadow: 0 2px 6px 2px rgba(60,64,67,.15);
7
+ max-height: calc(100vh - 94px);
8
+ overflow-y: auto;
9
+
10
+ width: initial;
11
+ height: initial;
12
+ min-height: initial;
13
+ }
14
+
15
+ .lm-menu-submenu {
16
+ padding-top: 1px;
17
+ padding-bottom: 1px;
18
+ }
19
+
20
+ .lm-menu-submenu > div {
21
+ box-sizing: border-box;
22
+ display: flex;
23
+ padding: 0 12px 0 32px;
24
+ width: 250px;
25
+ font-size: 11px;
26
+ font-family:sans-serif;
27
+ text-align: left;
28
+ align-items: center;
29
+ }
30
+
31
+ .lm-menu-submenu > div a {
32
+ text-decoration: none;
33
+ flex: 1;
34
+ cursor: pointer;
35
+ line-height: 28px;
36
+ }
37
+
38
+ .lm-menu-submenu > div span {
39
+ margin-right: 10px;
40
+ }
41
+
42
+ .lm-menu-submenu > div[data-submenu="true"]::after {
43
+ content: '\25B6'
44
+ }
45
+
46
+ .lm-menu-submenu > div.disabled {
47
+ color: #ccc;
48
+ }
49
+
50
+ .lm-menu-submenu > div:hover {
51
+ background: #ebebeb;
52
+ }
53
+
54
+ .lm-menu-submenu hr {
55
+ border: 1px solid #e9e9e9;
56
+ border-bottom: 0;
57
+ margin-top:5px;
58
+ margin-bottom:5px;
59
+ }
60
+
61
+ .lm-menu-submenu > div::before {
62
+ content: attr(data-icon);
63
+ font-family: 'Material Icons';
64
+ font-size: 15px;
65
+ position: absolute;
66
+ left: 9px;
67
+ line-height: 24px;
68
+ }
69
+
70
+ .lm-menu-submenu.symbols > div::before {
71
+ font-family: 'Material Symbols Outlined';
72
+ }
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@lemonadejs/contextmenu",
3
+ "title": "LemonadeJS contextmenu",
4
+ "description": "LemonadeJS Contextmenu JavaScript Plugin",
5
+ "author": {
6
+ "name": "Contact <contact@lemonadejs.net>",
7
+ "url": "https://lemonadejs.net"
8
+ },
9
+ "keywords": [
10
+ "javascript contextmenu"
11
+ ],
12
+ "scripts": {
13
+ "start": "webpack serve --history-api-fallback",
14
+ "build": "webpack --config webpack.config.js"
15
+ },
16
+ "dependencies": {
17
+ "@lemonadejs/modal": "^2.0.4",
18
+ "lemonadejs": "^3.3.2"
19
+ },
20
+ "main": "dist/index.js",
21
+ "version": "1.0.0"
22
+ }