@dualbox/editor 1.0.1 → 1.0.3
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/js/src/GraphEditor.js +159 -0
- package/js/src/c/GraphController.js +646 -0
- package/js/src/libs/CodeMirror.js +8 -0
- package/js/src/libs/fontawesome.js +1 -0
- package/js/src/libs/jsoneditor.css +2 -0
- package/js/src/libs/jsoneditor.js +4 -0
- package/js/src/m/DualboxUtils.js +35 -0
- package/js/src/m/GraphModel.js +2167 -0
- package/js/src/m/History.js +94 -0
- package/js/src/m/Merger.js +357 -0
- package/js/src/v/AppManager.js +61 -0
- package/js/src/v/CanvasSizeHandler.js +136 -0
- package/js/src/v/ContextMenu.css +45 -0
- package/js/src/v/ContextMenu.js +239 -0
- package/js/src/v/GraphView.js +928 -0
- package/js/src/v/PlumbStyle.js +254 -0
- package/js/src/v/Selector.js +239 -0
- package/js/src/v/TemplateManager.js +79 -0
- package/js/src/v/Translater.js +174 -0
- package/js/src/v/Utils.js +7 -0
- package/js/src/v/Zoomer.js +201 -0
- package/js/src/v/templates/addNode.css +45 -0
- package/js/src/v/templates/addNode.html +62 -0
- package/js/src/v/templates/addNode.js +34 -0
- package/js/src/v/templates/debugNodeInfos.css +5 -0
- package/js/src/v/templates/debugNodeInfos.html +336 -0
- package/js/src/v/templates/debugNodeInfos.js +31 -0
- package/js/src/v/templates/editMainSettings.css +67 -0
- package/js/src/v/templates/editMainSettings.html +265 -0
- package/js/src/v/templates/editMainSettings.js +240 -0
- package/js/src/v/templates/editNodeSettings.css +86 -0
- package/js/src/v/templates/editNodeSettings.html +539 -0
- package/js/src/v/templates/editNodeSettings.js +356 -0
- package/js/src/v/templates/graphNode.css +333 -0
- package/js/src/v/templates/graphNode.html +227 -0
- package/js/src/v/templates/graphNode.js +412 -0
- package/js/src/v/templates/main.css +353 -0
- package/js/src/v/templates/main.html +149 -0
- package/js/src/v/templates/main.js +511 -0
- package/js/src/v/templates/searchResults.css +50 -0
- package/js/src/v/templates/searchResults.html +46 -0
- package/js/src/v/templates/searchResults.js +176 -0
- package/package.json +3 -2
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
require('./ContextMenu.css');
|
|
2
|
+
|
|
3
|
+
const instances = [];
|
|
4
|
+
let mdCoord = null;
|
|
5
|
+
let nextId = 0;
|
|
6
|
+
|
|
7
|
+
// Tiny polyfill for Element.matches() for IE
|
|
8
|
+
if (!Element.prototype.matches) {
|
|
9
|
+
Element.prototype.matches = Element.prototype.msMatchesSelector;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Gets an element's next/previous sibling that matches the given selector
|
|
13
|
+
function getSibling(el, selector, direction = 1) {
|
|
14
|
+
const sibling = direction > 0 ? el.nextElementSibling : el.previousElementSibling;
|
|
15
|
+
if (!sibling || sibling.matches(selector)) {
|
|
16
|
+
return sibling;
|
|
17
|
+
}
|
|
18
|
+
return getSibling(sibling, selector, direction);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Fires custom event on given element
|
|
22
|
+
function emit(el, type, data = {}) {
|
|
23
|
+
const event = document.createEvent('Event');
|
|
24
|
+
|
|
25
|
+
Object.keys(data).forEach((key) => {
|
|
26
|
+
event[key] = data[key];
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
event.initEvent(type, true, true);
|
|
30
|
+
el.dispatchEvent(event);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
class ContextMenu {
|
|
34
|
+
constructor(selector, items, options = {
|
|
35
|
+
className: '',
|
|
36
|
+
minimalStyling: false,
|
|
37
|
+
}) {
|
|
38
|
+
this.selector = selector;
|
|
39
|
+
this.items = items;
|
|
40
|
+
this.options = options;
|
|
41
|
+
this.id = nextId++;
|
|
42
|
+
this.target = null;
|
|
43
|
+
|
|
44
|
+
this.create();
|
|
45
|
+
instances.push(this);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Creates DOM elements, sets up event listeners
|
|
49
|
+
create() {
|
|
50
|
+
// Create root <ul>
|
|
51
|
+
this.menu = document.createElement('ul');
|
|
52
|
+
this.menu.className = 'ContextMenu';
|
|
53
|
+
this.menu.oncontextmenu=function(e) { e.preventDefault(); e.stopPropagation(); return false; }; // don't do anything on right click
|
|
54
|
+
this.menu.setAttribute('data-contextmenu', this.id);
|
|
55
|
+
this.menu.setAttribute('tabindex', -1);
|
|
56
|
+
this.menu.addEventListener('keyup', (e) => {
|
|
57
|
+
switch (e.which) {
|
|
58
|
+
case 38:
|
|
59
|
+
this.moveFocus(-1);
|
|
60
|
+
break;
|
|
61
|
+
case 40:
|
|
62
|
+
this.moveFocus(1);
|
|
63
|
+
break;
|
|
64
|
+
case 27:
|
|
65
|
+
this.hide();
|
|
66
|
+
break;
|
|
67
|
+
default:
|
|
68
|
+
// do nothing
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
if (!this.options.minimalStyling) {
|
|
73
|
+
this.menu.classList.add('ContextMenu--theme-default');
|
|
74
|
+
}
|
|
75
|
+
if (this.options.className) {
|
|
76
|
+
this.options.className.split(' ').forEach(cls => this.menu.classList.add(cls));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Create <li>'s for each menu item
|
|
80
|
+
this.items.forEach((item, index) => {
|
|
81
|
+
const li = document.createElement('li');
|
|
82
|
+
|
|
83
|
+
if (!('name' in item)) {
|
|
84
|
+
// Insert a divider
|
|
85
|
+
li.className = 'ContextMenu-divider';
|
|
86
|
+
} else {
|
|
87
|
+
li.className = 'ContextMenu-item';
|
|
88
|
+
li.textContent = item.name;
|
|
89
|
+
li.setAttribute('data-contextmenuitem', index);
|
|
90
|
+
li.setAttribute('tabindex', 0);
|
|
91
|
+
li.addEventListener('click', this.select.bind(this, li));
|
|
92
|
+
li.addEventListener('keyup', (e) => {
|
|
93
|
+
if (e.which === 13) {
|
|
94
|
+
this.select(li);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
this.menu.appendChild(li);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Add root element to the <body>
|
|
103
|
+
document.body.appendChild(this.menu);
|
|
104
|
+
|
|
105
|
+
emit(this.menu, 'created');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Shows context menu
|
|
109
|
+
show(e) {
|
|
110
|
+
this.menu.style.left = `${e.pageX}px`;
|
|
111
|
+
this.menu.style.top = `${e.pageY}px`;
|
|
112
|
+
this.menu.classList.add('is-open');
|
|
113
|
+
this.target = e.target;
|
|
114
|
+
// Give context menu focus
|
|
115
|
+
this.menu.focus();
|
|
116
|
+
// Disable native context menu
|
|
117
|
+
e.preventDefault();
|
|
118
|
+
|
|
119
|
+
emit(this.menu, 'shown');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Hides context menu
|
|
123
|
+
hide() {
|
|
124
|
+
this.menu.classList.remove('is-open');
|
|
125
|
+
this.target = null;
|
|
126
|
+
emit(this.menu, 'hidden');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Selects the given item and calls its handler
|
|
130
|
+
select(item) {
|
|
131
|
+
const itemId = item.getAttribute('data-contextmenuitem');
|
|
132
|
+
if (this.items[itemId]) {
|
|
133
|
+
// Call item handler with target element as parameter
|
|
134
|
+
this.items[itemId].fn(this.target);
|
|
135
|
+
}
|
|
136
|
+
this.hide();
|
|
137
|
+
emit(this.menu, 'itemselected');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Moves focus to the next/previous menu item
|
|
141
|
+
moveFocus(direction = 1) {
|
|
142
|
+
const focused = this.menu.querySelector('[data-contextmenuitem]:focus');
|
|
143
|
+
let next;
|
|
144
|
+
|
|
145
|
+
if (focused) {
|
|
146
|
+
next = getSibling(focused, '[data-contextmenuitem]', direction);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (!next) {
|
|
150
|
+
next = direction > 0
|
|
151
|
+
? this.menu.querySelector('[data-contextmenuitem]:first-child')
|
|
152
|
+
: this.menu.querySelector('[data-contextmenuitem]:last-child');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (next) next.focus();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Convenience method for adding an event listener
|
|
159
|
+
on(type, fn) {
|
|
160
|
+
this.menu.addEventListener(type, fn);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Convenience method for removing an event listener
|
|
164
|
+
off(type, fn) {
|
|
165
|
+
this.menu.removeEventListener(type, fn);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Removes DOM elements, stop listeners
|
|
169
|
+
destroy() {
|
|
170
|
+
this.menu.parentElement.removeChild(this.menu);
|
|
171
|
+
this.menu = null;
|
|
172
|
+
instances.splice(instances.indexOf(this), 1);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
static initialize() {
|
|
176
|
+
document.addEventListener('contextmenu', (e) => {
|
|
177
|
+
// unbind browser contextmenu
|
|
178
|
+
e.preventDefault();
|
|
179
|
+
e.stopPropagation();
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
document.addEventListener('mousedown', (e) => {
|
|
183
|
+
if( e.which === 3 ) { // right click
|
|
184
|
+
mdCoord = {
|
|
185
|
+
"x": e.pageX,
|
|
186
|
+
"y": e.pageY
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Listen for contextmenu event to show menu
|
|
192
|
+
document.addEventListener('mouseup', (e) => {
|
|
193
|
+
if( e.which === 3 && mdCoord !== null ) {
|
|
194
|
+
// if the mouse didnt move much since the mouse down, we show the context menu
|
|
195
|
+
var diff = Math.abs(e.pageX - mdCoord.x) + Math.abs(e.pageY -mdCoord.y);
|
|
196
|
+
if( diff < 4 ) {
|
|
197
|
+
var target = $(e.target);
|
|
198
|
+
if( $(target).closest('.jsplumb-endpoint-anchor').length !== 0 ) target = $(target).closest('.jsplumb-endpoint-anchor');
|
|
199
|
+
|
|
200
|
+
instances.forEach((menu) => {
|
|
201
|
+
if( target[0].matches(menu.selector) ||
|
|
202
|
+
target[0].closest('.card') &&
|
|
203
|
+
target[0].closest('.card').matches(menu.selector) ) {
|
|
204
|
+
menu.show(e);
|
|
205
|
+
|
|
206
|
+
/*
|
|
207
|
+
e.preventDefault();
|
|
208
|
+
e.stopPropagation();
|
|
209
|
+
e.stopImmediatePropagation();
|
|
210
|
+
*/
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
mdCoord = null; // reset mdCoord
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// Listen for click event to hide menu
|
|
221
|
+
document.addEventListener('click', (e) => {
|
|
222
|
+
instances.forEach((menu) => {
|
|
223
|
+
if (!e.target.matches(`[data-contextmenu="${menu.id}"], [data-contextmenu="${menu.id}"] *`)) {
|
|
224
|
+
menu.hide();
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
static clean() {
|
|
231
|
+
instances.forEach((menu) => {
|
|
232
|
+
menu.destroy();
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
module.exports = ContextMenu;
|