canvas-datagrid 0.25.3 → 0.26.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/CHANGELOG.md +328 -1
- package/README.md +85 -67
- package/dist/canvas-datagrid.debug.js +7606 -3099
- package/dist/canvas-datagrid.debug.map +1 -1
- package/dist/canvas-datagrid.js +1 -1
- package/dist/canvas-datagrid.module.js +1 -1
- package/dist/canvas-datagrid.module.js.map +1 -1
- package/dist/types.d.ts +2508 -0
- package/lib/button.js +326 -0
- package/lib/component.js +51 -13
- package/lib/contextMenu.js +408 -30
- package/lib/defaults.js +100 -7
- package/lib/docs.js +121 -11
- package/lib/dom.js +239 -18
- package/lib/draw.js +1446 -206
- package/lib/events/index.js +2640 -0
- package/lib/events/util.js +165 -0
- package/lib/groups/util.js +42 -0
- package/lib/intf.js +908 -87
- package/lib/main.js +8 -1
- package/lib/publicMethods.js +773 -377
- package/lib/selections/index.js +989 -0
- package/lib/selections/type.d.ts +38 -0
- package/lib/selections/util.js +1320 -0
- package/lib/touch.js +20 -47
- package/package.json +32 -21
- package/lib/events.js +0 -1741
package/lib/button.js
ADDED
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
/*jslint browser: true, unparam: true, todo: true*/
|
|
2
|
+
/*globals define: true, MutationObserver: false, requestAnimationFrame: false, performance: false, btoa: false, Event: false*/
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
export default function (self) {
|
|
6
|
+
let zIndexTop;
|
|
7
|
+
|
|
8
|
+
function applyButtonMenuItemStyle(buttonMenuItemContainer) {
|
|
9
|
+
self.createInlineStyle(
|
|
10
|
+
buttonMenuItemContainer,
|
|
11
|
+
'canvas-datagrid-button-menu-item' + (self.mobile ? '-mobile' : ''),
|
|
12
|
+
);
|
|
13
|
+
buttonMenuItemContainer.addEventListener('mouseover', function () {
|
|
14
|
+
self.createInlineStyle(
|
|
15
|
+
buttonMenuItemContainer,
|
|
16
|
+
'canvas-datagrid-button-menu-item:hover',
|
|
17
|
+
);
|
|
18
|
+
});
|
|
19
|
+
buttonMenuItemContainer.addEventListener('mouseout', function () {
|
|
20
|
+
self.createInlineStyle(
|
|
21
|
+
buttonMenuItemContainer,
|
|
22
|
+
'canvas-datagrid-button-menu-item',
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function applyButtonStyle(button) {
|
|
28
|
+
self.createInlineStyle(button, 'canvas-datagrid-button-wrapper');
|
|
29
|
+
button.addEventListener('mouseover', function () {
|
|
30
|
+
if (!self.buttonMenu) {
|
|
31
|
+
self.createInlineStyle(button, 'canvas-datagrid-button-wrapper:hover');
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
button.addEventListener('mouseout', function () {
|
|
35
|
+
if (!self.buttonMenu) {
|
|
36
|
+
self.createInlineStyle(button, 'canvas-datagrid-button-wrapper');
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function createButton(pos, items, imgSrc) {
|
|
42
|
+
var wrapper = document.createElement('div'),
|
|
43
|
+
buttonArrow = document.createElement('div'),
|
|
44
|
+
buttonIcon = document.createElement('div'),
|
|
45
|
+
intf = {};
|
|
46
|
+
|
|
47
|
+
if (!Array.isArray(items)) {
|
|
48
|
+
throw new Error('createButton expects an array.');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function init() {
|
|
52
|
+
var loc = {},
|
|
53
|
+
s = self.scrollOffset(self.canvas);
|
|
54
|
+
|
|
55
|
+
if (zIndexTop === undefined) {
|
|
56
|
+
zIndexTop = self.style.buttonZIndex;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
applyButtonStyle(wrapper);
|
|
60
|
+
self.createInlineStyle(buttonIcon, 'canvas-datagrid-button-icon');
|
|
61
|
+
self.createInlineStyle(buttonArrow, 'canvas-datagrid-button-arrow');
|
|
62
|
+
|
|
63
|
+
loc.x = pos.left - s.left;
|
|
64
|
+
loc.y = pos.top - s.top;
|
|
65
|
+
loc.height = 0;
|
|
66
|
+
zIndexTop += 1;
|
|
67
|
+
wrapper.style.position = 'absolute';
|
|
68
|
+
wrapper.style.zIndex = zIndexTop;
|
|
69
|
+
wrapper.style.left = loc.x + 'px';
|
|
70
|
+
wrapper.style.top = loc.y + 'px';
|
|
71
|
+
wrapper.left = pos.left + self.scrollBox.scrollLeft;
|
|
72
|
+
wrapper.top = pos.top + self.scrollBox.scrollTop;
|
|
73
|
+
buttonArrow.innerHTML = self.style.buttonArrowDownHTML;
|
|
74
|
+
if (imgSrc) {
|
|
75
|
+
let img = document.createElement('img');
|
|
76
|
+
img.setAttribute('src', imgSrc);
|
|
77
|
+
img.style.maxWidth = '100%';
|
|
78
|
+
img.style.height = '100%';
|
|
79
|
+
buttonIcon.appendChild(img);
|
|
80
|
+
}
|
|
81
|
+
wrapper.appendChild(buttonIcon);
|
|
82
|
+
wrapper.appendChild(buttonArrow);
|
|
83
|
+
document.body.appendChild(wrapper);
|
|
84
|
+
wrapper.addEventListener('click', toggleButtonMenu);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
intf.wrapper = wrapper;
|
|
88
|
+
intf.items = items;
|
|
89
|
+
init();
|
|
90
|
+
|
|
91
|
+
intf.dispose = function () {
|
|
92
|
+
if (wrapper.parentNode) {
|
|
93
|
+
wrapper.parentNode.removeChild(wrapper);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
return intf;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function toggleButtonMenu() {
|
|
100
|
+
function createDisposeEvent() {
|
|
101
|
+
requestAnimationFrame(function () {
|
|
102
|
+
document.addEventListener('click', self.disposeButtonMenu);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
if (self.buttonMenu) {
|
|
106
|
+
self.disposeButtonMenu();
|
|
107
|
+
} else {
|
|
108
|
+
let pos = {
|
|
109
|
+
left: self.button.wrapper.left - self.scrollBox.scrollLeft,
|
|
110
|
+
top:
|
|
111
|
+
self.button.wrapper.top +
|
|
112
|
+
self.button.wrapper.offsetHeight -
|
|
113
|
+
self.scrollBox.scrollTop,
|
|
114
|
+
};
|
|
115
|
+
self.buttonMenu = createButtonMenu(pos, self.button.items);
|
|
116
|
+
self.createInlineStyle(
|
|
117
|
+
self.button.wrapper,
|
|
118
|
+
'canvas-datagrid-button-wrapper:active',
|
|
119
|
+
);
|
|
120
|
+
createDisposeEvent();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function createButtonMenu(pos, items) {
|
|
125
|
+
var buttonMenu = document.createElement('div'),
|
|
126
|
+
selectedIndex = -1,
|
|
127
|
+
intf = {},
|
|
128
|
+
rect;
|
|
129
|
+
|
|
130
|
+
function createItems() {
|
|
131
|
+
function addItem(item, menuItemContainer) {
|
|
132
|
+
function addContent(content) {
|
|
133
|
+
if (content === null) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (typeof content === 'object') {
|
|
138
|
+
menuItemContainer.appendChild(content);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
applyButtonMenuItemStyle(menuItemContainer);
|
|
143
|
+
menuItemContainer.innerHTML = content;
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
addContent(item.title);
|
|
148
|
+
item.buttonMenuItemContainer = menuItemContainer;
|
|
149
|
+
|
|
150
|
+
if (item.click) {
|
|
151
|
+
menuItemContainer.addEventListener('click', function (ev) {
|
|
152
|
+
item.click.apply(self, [ev]);
|
|
153
|
+
self.disposeButton();
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
for (let item of items) {
|
|
159
|
+
var buttonMenuItemContainer = document.createElement('div');
|
|
160
|
+
addItem(item, buttonMenuItemContainer);
|
|
161
|
+
buttonMenu.appendChild(buttonMenuItemContainer);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function clickIndex(idx) {
|
|
166
|
+
items[idx].buttonMenuItemContainer.dispatchEvent(new Event('click'));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function init() {
|
|
170
|
+
var loc = {},
|
|
171
|
+
s = self.scrollOffset(self.canvas);
|
|
172
|
+
|
|
173
|
+
if (zIndexTop === undefined) {
|
|
174
|
+
zIndexTop = self.style.buttonZIndex;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
createItems();
|
|
178
|
+
self.createInlineStyle(
|
|
179
|
+
buttonMenu,
|
|
180
|
+
'canvas-datagrid-button-menu' + (self.mobile ? '-mobile' : ''),
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
loc.x = pos.left - s.left;
|
|
184
|
+
loc.y = pos.top - s.top;
|
|
185
|
+
loc.height = 0;
|
|
186
|
+
zIndexTop += 1;
|
|
187
|
+
buttonMenu.style.position = 'absolute';
|
|
188
|
+
buttonMenu.style.zIndex = zIndexTop;
|
|
189
|
+
buttonMenu.style.left = loc.x + 'px';
|
|
190
|
+
buttonMenu.style.top = loc.y + 'px';
|
|
191
|
+
document.body.appendChild(buttonMenu);
|
|
192
|
+
rect = buttonMenu.getBoundingClientRect();
|
|
193
|
+
|
|
194
|
+
if (rect.bottom > window.innerHeight) {
|
|
195
|
+
loc.y =
|
|
196
|
+
self.button.wrapper.top -
|
|
197
|
+
buttonMenu.offsetHeight -
|
|
198
|
+
self.scrollBox.scrollTop;
|
|
199
|
+
if (loc.y < 0) {
|
|
200
|
+
loc.y = self.style.buttonMenuWindowMargin;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (
|
|
204
|
+
buttonMenu.offsetHeight >
|
|
205
|
+
window.innerHeight - self.style.buttonMenuWindowMargin
|
|
206
|
+
) {
|
|
207
|
+
buttonMenu.style.height =
|
|
208
|
+
window.innerHeight - self.style.buttonMenuWindowMargin * 2 + 'px';
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (rect.right > window.innerWidth) {
|
|
213
|
+
loc.x -=
|
|
214
|
+
rect.right - window.innerWidth + self.style.buttonMenuWindowMargin;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (loc.x < 0) {
|
|
218
|
+
loc.x = self.style.buttonMenuWindowMargin;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (loc.y < 0) {
|
|
222
|
+
loc.y = self.style.buttonMenuWindowMargin;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
buttonMenu.style.left = loc.x + 'px';
|
|
226
|
+
buttonMenu.style.top = loc.y + 'px';
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
intf.buttonMenu = buttonMenu;
|
|
230
|
+
init();
|
|
231
|
+
intf.clickIndex = clickIndex;
|
|
232
|
+
intf.rect = rect;
|
|
233
|
+
intf.items = items;
|
|
234
|
+
|
|
235
|
+
intf.dispose = function () {
|
|
236
|
+
if (buttonMenu.parentNode) {
|
|
237
|
+
buttonMenu.parentNode.removeChild(buttonMenu);
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
Object.defineProperty(intf, 'selectedIndex', {
|
|
242
|
+
get: function get() {
|
|
243
|
+
return selectedIndex;
|
|
244
|
+
},
|
|
245
|
+
set: function set(value) {
|
|
246
|
+
if (typeof value !== 'number' || isNaN(value) || !isFinite(value)) {
|
|
247
|
+
throw new Error('Button menu selected index must be a sane number.');
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
selectedIndex = value;
|
|
251
|
+
|
|
252
|
+
if (selectedIndex > items.length - 1) {
|
|
253
|
+
selectedIndex = items.length - 1;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (selectedIndex < 0) {
|
|
257
|
+
selectedIndex = 0;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
items.forEach(function (item, index) {
|
|
261
|
+
if (index === selectedIndex) {
|
|
262
|
+
return self.createInlineStyle(
|
|
263
|
+
item.buttonMenuItemContainer,
|
|
264
|
+
'canvas-datagrid-button-menu-item:hover',
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
self.createInlineStyle(
|
|
269
|
+
item.buttonMenuItemContainer,
|
|
270
|
+
'canvas-datagrid-button-menu-item',
|
|
271
|
+
);
|
|
272
|
+
});
|
|
273
|
+
},
|
|
274
|
+
});
|
|
275
|
+
return intf;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
self.disposeButtonMenu = function () {
|
|
279
|
+
if (self.buttonMenu) {
|
|
280
|
+
document.removeEventListener('click', self.disposeButtonMenu);
|
|
281
|
+
self.buttonMenu.dispose();
|
|
282
|
+
self.buttonMenu = undefined;
|
|
283
|
+
self.createInlineStyle(
|
|
284
|
+
self.button.wrapper,
|
|
285
|
+
'canvas-datagrid-button-wrapper:hover',
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
self.disposeButton = function (e) {
|
|
291
|
+
if (e && e.keyCode !== 27) return;
|
|
292
|
+
document.removeEventListener('keydown', self.disposeButton);
|
|
293
|
+
zIndexTop = self.style.buttonZIndex;
|
|
294
|
+
self.disposeButtonMenu();
|
|
295
|
+
|
|
296
|
+
if (self.button) {
|
|
297
|
+
self.button.dispose();
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
self.button = undefined;
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
self.moveButtonPos = function () {
|
|
304
|
+
self.button.wrapper.style.left =
|
|
305
|
+
self.button.wrapper.left - self.scrollBox.scrollLeft + 'px';
|
|
306
|
+
self.button.wrapper.style.top =
|
|
307
|
+
self.button.wrapper.top - self.scrollBox.scrollTop + 'px';
|
|
308
|
+
self.disposeButtonMenu();
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
self.attachButton = function (pos, items, imgSrc) {
|
|
312
|
+
function createDisposeEvent() {
|
|
313
|
+
requestAnimationFrame(function () {
|
|
314
|
+
document.addEventListener('keydown', self.disposeButton);
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (self.button) {
|
|
319
|
+
self.disposeButton();
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
self.button = createButton(pos, items, imgSrc);
|
|
323
|
+
createDisposeEvent();
|
|
324
|
+
};
|
|
325
|
+
return;
|
|
326
|
+
}
|
package/lib/component.js
CHANGED
|
@@ -60,8 +60,7 @@ export default function () {
|
|
|
60
60
|
defs = {};
|
|
61
61
|
intf.computedStyle = cStyle;
|
|
62
62
|
defaults(defs);
|
|
63
|
-
defs
|
|
64
|
-
defs.forEach(function (def) {
|
|
63
|
+
defs.defaults.styles.forEach(function (def) {
|
|
65
64
|
var val;
|
|
66
65
|
val = cStyle.getPropertyValue(component.hyphenateProperty(def[0], true));
|
|
67
66
|
if (val === '') {
|
|
@@ -69,6 +68,16 @@ export default function () {
|
|
|
69
68
|
component.hyphenateProperty(def[0], false),
|
|
70
69
|
);
|
|
71
70
|
}
|
|
71
|
+
if (
|
|
72
|
+
/^overflow[XY]$/.test(def[0]) &&
|
|
73
|
+
typeof val === 'string' &&
|
|
74
|
+
val.trim() === 'visible'
|
|
75
|
+
) {
|
|
76
|
+
// 'visible' is the CSS default, not something the page asked for,
|
|
77
|
+
// and not a grid value: keep the overflow set through grid.style
|
|
78
|
+
// instead of overwriting it on every style pass (#248)
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
72
81
|
if (val !== '' && typeof val === 'string') {
|
|
73
82
|
intf.setStyleProperty(
|
|
74
83
|
def[0],
|
|
@@ -126,6 +135,14 @@ export default function () {
|
|
|
126
135
|
};
|
|
127
136
|
component.disconnectedCallback = function () {
|
|
128
137
|
this.connected = false;
|
|
138
|
+
// stop observing while detached so a removed grid can be collected (#338)
|
|
139
|
+
if (this.observer && this.observer.disconnect) {
|
|
140
|
+
this.observer.disconnect();
|
|
141
|
+
this.observer = undefined;
|
|
142
|
+
}
|
|
143
|
+
if (typeof this.unobserveResizeTargets === 'function') {
|
|
144
|
+
this.unobserveResizeTargets();
|
|
145
|
+
}
|
|
129
146
|
};
|
|
130
147
|
component.connectedCallback = function () {
|
|
131
148
|
var intf = this;
|
|
@@ -133,6 +150,9 @@ export default function () {
|
|
|
133
150
|
intf.parentDOMNode.appendChild(intf.canvas);
|
|
134
151
|
intf.connected = true;
|
|
135
152
|
component.observe(intf);
|
|
153
|
+
if (typeof intf.observeResizeTargets === 'function') {
|
|
154
|
+
intf.observeResizeTargets();
|
|
155
|
+
}
|
|
136
156
|
component.applyComponentStyle(true, intf);
|
|
137
157
|
intf.resize(true);
|
|
138
158
|
};
|
|
@@ -172,7 +192,19 @@ export default function () {
|
|
|
172
192
|
return;
|
|
173
193
|
}
|
|
174
194
|
if (/^on/.test(attrName)) {
|
|
175
|
-
|
|
195
|
+
// inline handler attributes need the Function constructor, which a
|
|
196
|
+
// strict Content Security Policy forbids; degrade with a warning (#311)
|
|
197
|
+
var handler;
|
|
198
|
+
try {
|
|
199
|
+
handler = new Function('e', newVal);
|
|
200
|
+
} catch (err) {
|
|
201
|
+
console.warn(
|
|
202
|
+
'canvas-datagrid: cannot bind the %s attribute under the current Content Security Policy; use addEventListener instead.',
|
|
203
|
+
attrName,
|
|
204
|
+
);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
intf.addEventListener('on' + attrName, handler);
|
|
176
208
|
}
|
|
177
209
|
return;
|
|
178
210
|
};
|
|
@@ -181,6 +213,10 @@ export default function () {
|
|
|
181
213
|
if (!window.MutationObserver) {
|
|
182
214
|
return;
|
|
183
215
|
}
|
|
216
|
+
// connectedCallback runs on every (re)attach: never stack observers (#338)
|
|
217
|
+
if (intf.observer && intf.observer.disconnect) {
|
|
218
|
+
intf.observer.disconnect();
|
|
219
|
+
}
|
|
184
220
|
intf.applyComponentStyle = function () {
|
|
185
221
|
component.applyComponentStyle(false, intf);
|
|
186
222
|
intf.resize();
|
|
@@ -229,22 +265,24 @@ export default function () {
|
|
|
229
265
|
intf.data = intf.innerHTML;
|
|
230
266
|
}
|
|
231
267
|
});
|
|
268
|
+
intf.observer = observer;
|
|
232
269
|
observer.observe(intf, {
|
|
233
270
|
characterData: true,
|
|
234
271
|
childList: true,
|
|
235
272
|
attributes: true,
|
|
236
273
|
subtree: true,
|
|
237
274
|
});
|
|
238
|
-
Array.prototype.forEach.call(
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
275
|
+
Array.prototype.forEach.call(
|
|
276
|
+
document.querySelectorAll('style'),
|
|
277
|
+
function (el) {
|
|
278
|
+
observer.observe(el, {
|
|
279
|
+
characterData: true,
|
|
280
|
+
childList: true,
|
|
281
|
+
attributes: true,
|
|
282
|
+
subtree: true,
|
|
283
|
+
});
|
|
284
|
+
},
|
|
285
|
+
);
|
|
248
286
|
};
|
|
249
287
|
return component;
|
|
250
288
|
}
|