datavis-glide 4.0.0-PRE.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/LICENSE +45 -0
- package/README.md +129 -0
- package/datavis.js +101 -0
- package/dist/wcdatavis.css +1957 -0
- package/dist/wcdatavis.min.js +1 -0
- package/global-jquery.js +4 -0
- package/ie-fixes.js +13 -0
- package/index.js +70 -0
- package/meteor.js +1 -0
- package/package.json +102 -0
- package/src/flags.js +6 -0
- package/src/graph.js +1079 -0
- package/src/graph_renderer.js +85 -0
- package/src/grid.js +2777 -0
- package/src/grid_control.js +1957 -0
- package/src/grid_filter.js +1073 -0
- package/src/grid_renderer.js +276 -0
- package/src/group_fun_win.js +121 -0
- package/src/lang/en-US.js +188 -0
- package/src/lang/es-MX.js +188 -0
- package/src/lang/fr-FR.js +188 -0
- package/src/lang/id-ID.js +188 -0
- package/src/lang/nl-NL.js +188 -0
- package/src/lang/pt-BR.js +188 -0
- package/src/lang/ru-RU.js +188 -0
- package/src/lang/th-TH.js +188 -0
- package/src/lang/vi-VN.js +188 -0
- package/src/lang/zh-Hans-CN.js +188 -0
- package/src/operations_palette.js +176 -0
- package/src/prefs_modules.js +132 -0
- package/src/reg/graph_renderer.js +17 -0
- package/src/renderers/graph/chartjs.js +457 -0
- package/src/renderers/graph/google.js +584 -0
- package/src/renderers/graph/jit.js +61 -0
- package/src/renderers/graph/svelte-gantt.js +168 -0
- package/src/renderers/grid/dummy.js +79 -0
- package/src/renderers/grid/handlebars.js +217 -0
- package/src/renderers/grid/squirrelly.js +215 -0
- package/src/renderers/grid/table/group_detail.js +1404 -0
- package/src/renderers/grid/table/group_summary.js +380 -0
- package/src/renderers/grid/table/pivot.js +915 -0
- package/src/renderers/grid/table/plain.js +1592 -0
- package/src/renderers/grid/table.js +2510 -0
- package/src/trans.js +101 -0
- package/src/ui/collapsible.js +234 -0
- package/src/ui/filters/date.js +283 -0
- package/src/ui/grid_filter.js +398 -0
- package/src/ui/popup_menu.js +224 -0
- package/src/ui/popup_window.js +572 -0
- package/src/ui/slider.js +156 -0
- package/src/ui/tabs.js +202 -0
- package/src/ui/templates.js +131 -0
- package/src/ui/toolbar.js +63 -0
- package/src/ui/toolbars/grid.js +873 -0
- package/src/ui/windows/col_config.js +341 -0
- package/src/ui/windows/debug.js +164 -0
- package/src/ui/windows/grid_table_opts.js +139 -0
- package/src/util/handlebars.js +158 -0
- package/src/util/jquery.js +630 -0
- package/src/util/misc.js +1058 -0
- package/src/util/squirrelly.js +155 -0
- package/wcdatavis.css +1601 -0
|
@@ -0,0 +1,630 @@
|
|
|
1
|
+
import jQuery from 'jquery';
|
|
2
|
+
import _ from 'underscore';
|
|
3
|
+
|
|
4
|
+
import { trans } from '../trans.js';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
deepDefaults,
|
|
8
|
+
icon,
|
|
9
|
+
getProp,
|
|
10
|
+
} from './misc.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The jQuery plugin namespace.
|
|
14
|
+
* @external "jQuery.fn"
|
|
15
|
+
* @see {@link http://learn.jquery.com/plugins/|jQuery Plugins}
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
jQuery.fn.extend({
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Tells whether the element is checked.
|
|
22
|
+
*
|
|
23
|
+
* @function external:"jQuery.fn"#_isChecked
|
|
24
|
+
*
|
|
25
|
+
* @returns {boolean}
|
|
26
|
+
* True if the element is checked, false if it's not.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
_isChecked: function () {
|
|
30
|
+
return this.prop('checked');
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Checks a checkbox.
|
|
35
|
+
*
|
|
36
|
+
* @function external:"jQuery.fn"#_check
|
|
37
|
+
*
|
|
38
|
+
* @returns {boolean}
|
|
39
|
+
* True if the element is now checked, false if it's not.
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
_check: function () {
|
|
43
|
+
this.prop('checked', true);
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Unchecks a checkbox.
|
|
48
|
+
*
|
|
49
|
+
* @function external:"jQuery.fn"#_uncheck
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
_uncheck: function () {
|
|
53
|
+
this.prop('checked', false);
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Toggles the checkbox.
|
|
58
|
+
*
|
|
59
|
+
* @function external:"jQuery.fn"#_toggleCheck
|
|
60
|
+
*
|
|
61
|
+
* @returns {boolean}
|
|
62
|
+
* True if the element is now checked, false if it's not.
|
|
63
|
+
*/
|
|
64
|
+
|
|
65
|
+
_toggleCheck: function () {
|
|
66
|
+
var newValue = !this.prop('checked');
|
|
67
|
+
this.prop('checked', newValue);
|
|
68
|
+
return newValue;
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Tells whether the element is disabled.
|
|
73
|
+
*
|
|
74
|
+
* @function external:"jQuery.fn"#_isDisabled
|
|
75
|
+
*
|
|
76
|
+
* @returns {boolean}
|
|
77
|
+
* True if the element is disabled, false if it's not.
|
|
78
|
+
*/
|
|
79
|
+
|
|
80
|
+
_isDisabled: function () {
|
|
81
|
+
return this.attr('disabled');
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Tells whether the element is hidden.
|
|
86
|
+
*
|
|
87
|
+
* @function external:"jQuery.fn"#_isHidden
|
|
88
|
+
*
|
|
89
|
+
* @returns {boolean}
|
|
90
|
+
* True if the element is hidden, false if it's visible.
|
|
91
|
+
*/
|
|
92
|
+
|
|
93
|
+
_isHidden: function () {
|
|
94
|
+
return this.css('display') === 'none' || this.css('visibility') !== 'visible';
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Ensures that an element ends with certain text.
|
|
99
|
+
*
|
|
100
|
+
* @function external:"jQuery.fn"#_addTrailing
|
|
101
|
+
*
|
|
102
|
+
* @param {string} chars
|
|
103
|
+
* The text that will be added to the end of this element, if necessary.
|
|
104
|
+
*/
|
|
105
|
+
|
|
106
|
+
_addTrailing: function (chars) {
|
|
107
|
+
var t = this.text();
|
|
108
|
+
if (t.slice(chars.length * -1) !== chars){
|
|
109
|
+
this.text(t + chars);
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Ensures that an element does not end with certain text.
|
|
115
|
+
*
|
|
116
|
+
* @function external:"jQuery.fn"#_stripTrailing
|
|
117
|
+
*
|
|
118
|
+
* @param {string} chars
|
|
119
|
+
* The text that will be removed from this element's text, if necessary.
|
|
120
|
+
*/
|
|
121
|
+
|
|
122
|
+
_stripTrailing: function (chars) {
|
|
123
|
+
var t = this.text();
|
|
124
|
+
if (t.slice(chars.length * -1) === chars) {
|
|
125
|
+
this.text(t.slice(0, chars.length * -1));
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Make a checkbox that is represented by an icon. The icon can change based on whether the
|
|
131
|
+
* checkbox is on/off (e.g. turning from a "check" icon to an "x" icon). Or the icon can be
|
|
132
|
+
* displayed with a different class (e.g. to change the background or color when on/off).
|
|
133
|
+
*
|
|
134
|
+
* @function external:"jQuery.fn"#_makeIconCheckbox
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* _makeIconCheckbox('foo') -->
|
|
138
|
+
* off = icon('foo'), class = 'wcdv_icon_checkbox_off'
|
|
139
|
+
* on = icon('foo'), class = 'wcdv_icon_checkbox_on'
|
|
140
|
+
* _makeIconCheckbox('foo', 'bar') -->
|
|
141
|
+
* off = icon('foo')
|
|
142
|
+
* on = icon('bar')
|
|
143
|
+
* _makeIconCheckbox(obj) -->
|
|
144
|
+
* off = icon(obj.off.icon), class = obj.off.classes
|
|
145
|
+
* on = icon(obj.on.icon), class = obj.on.classes
|
|
146
|
+
*/
|
|
147
|
+
|
|
148
|
+
_makeIconCheckbox: (function () {
|
|
149
|
+
return function () {
|
|
150
|
+
var self = this
|
|
151
|
+
, args = Array.prototype.slice.call(arguments)
|
|
152
|
+
, opts = {};
|
|
153
|
+
|
|
154
|
+
if (args.length === 1) {
|
|
155
|
+
if (typeof args[0] === 'string') {
|
|
156
|
+
opts = {
|
|
157
|
+
on: {
|
|
158
|
+
icon: args[0],
|
|
159
|
+
classes: 'wcdv_icon_checkbox_on'
|
|
160
|
+
},
|
|
161
|
+
off: {
|
|
162
|
+
icon: args[0],
|
|
163
|
+
classes: 'wcdv_icon_checkbox_off'
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
opts = args[0];
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
else if (args.length === 2) {
|
|
172
|
+
opts = {
|
|
173
|
+
on: {
|
|
174
|
+
icon: args[0]
|
|
175
|
+
},
|
|
176
|
+
off: {
|
|
177
|
+
icon: args[1]
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
var button = jQuery('<button>', {
|
|
183
|
+
'type': 'button',
|
|
184
|
+
'disabled': jQuery(self).prop('disabled'),
|
|
185
|
+
'title': self.attr('title')
|
|
186
|
+
})
|
|
187
|
+
.addClass('wcdv_icon_button wcdv_button_left')
|
|
188
|
+
.on('click', function () {
|
|
189
|
+
self._toggleCheck();
|
|
190
|
+
self.trigger('change');
|
|
191
|
+
})
|
|
192
|
+
;
|
|
193
|
+
|
|
194
|
+
var onIcon = icon(opts.on.icon, opts.on.classes)
|
|
195
|
+
.css('display', 'inline-block')
|
|
196
|
+
.hide()
|
|
197
|
+
.appendTo(button);
|
|
198
|
+
var offIcon = icon(opts.off.icon, opts.off.classes)
|
|
199
|
+
.css('display', 'inline-block')
|
|
200
|
+
.hide()
|
|
201
|
+
.appendTo(button);
|
|
202
|
+
|
|
203
|
+
var updateIcon = function () {
|
|
204
|
+
if (self._isChecked()) {
|
|
205
|
+
onIcon.show();
|
|
206
|
+
offIcon.hide();
|
|
207
|
+
if (opts.on.tooltip != null) {
|
|
208
|
+
button.attr('title', opts.on.tooltip);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
onIcon.hide();
|
|
213
|
+
offIcon.show();
|
|
214
|
+
if (opts.off.tooltip != null) {
|
|
215
|
+
button.attr('title', opts.off.tooltip);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
updateIcon();
|
|
221
|
+
self.hide();
|
|
222
|
+
self.before(button);
|
|
223
|
+
self.on('change', updateIcon);
|
|
224
|
+
self._updateIcon = updateIcon;
|
|
225
|
+
|
|
226
|
+
return self;
|
|
227
|
+
};
|
|
228
|
+
})(),
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Adds debugging output for jQuery UI behavior events.
|
|
232
|
+
*
|
|
233
|
+
* @function external:"jQuery.fn"#_addEventDebugging
|
|
234
|
+
*
|
|
235
|
+
* @param {string} what
|
|
236
|
+
* The behavior to output debugging info for. Must be: drag, drop, or sort.
|
|
237
|
+
*
|
|
238
|
+
* @param {string} tag
|
|
239
|
+
* Prefix to output at the beginning of the debug message.
|
|
240
|
+
*/
|
|
241
|
+
|
|
242
|
+
_addEventDebugging: function (what, tag) {
|
|
243
|
+
var elt = this;
|
|
244
|
+
switch (what) {
|
|
245
|
+
case 'drag':
|
|
246
|
+
elt.on('dragstart', function (evt, ui) {
|
|
247
|
+
console.log('### ' + tag + ' > DRAG.START: evt = %O, ui = %O', evt, ui);
|
|
248
|
+
});
|
|
249
|
+
elt.on('dragstop', function (evt, ui) {
|
|
250
|
+
console.log('### ' + tag + ' > DRAG.STOP: evt = %O, ui = %O', evt, ui);
|
|
251
|
+
});
|
|
252
|
+
break;
|
|
253
|
+
case 'drop':
|
|
254
|
+
elt.on('dropactivate', function (evt, ui) {
|
|
255
|
+
console.log('### ' + tag + ' > DROP.ACTIVATE: evt = %O, ui = %O', evt, ui);
|
|
256
|
+
});
|
|
257
|
+
elt.on('dropdeactivate', function (evt, ui) {
|
|
258
|
+
console.log('### ' + tag + ' > DROP.DEACTIVATE: evt = %O, ui = %O', evt, ui);
|
|
259
|
+
});
|
|
260
|
+
elt.on('drop', function (evt, ui) {
|
|
261
|
+
console.log('### ' + tag + ' > DROP.DROP: evt = %O, ui = %O', evt, ui);
|
|
262
|
+
});
|
|
263
|
+
break;
|
|
264
|
+
case 'sort':
|
|
265
|
+
_.each(['activate', 'change', 'deactivate', 'out', 'over', 'receive', 'remove', 'sort', 'start', 'stop', 'update'], function (eventName) {
|
|
266
|
+
elt.on('sort' + eventName, function (evt, ui) {
|
|
267
|
+
console.log('### ' + tag + ' > SORT.' + eventName.toUpperCase() + ': evt = %O, ui = %O', evt, ui);
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
break;
|
|
271
|
+
default:
|
|
272
|
+
throw new Error('Call Error: Event type must be one of: ["drag", "drop", "sort"]');
|
|
273
|
+
}
|
|
274
|
+
return elt;
|
|
275
|
+
},
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Make this element draggable.
|
|
279
|
+
*
|
|
280
|
+
* @function external:"jQuery.fn"#_makeDraggableField
|
|
281
|
+
*
|
|
282
|
+
* @param {object} [opts]
|
|
283
|
+
* Change options passed to `draggable()`.
|
|
284
|
+
*/
|
|
285
|
+
|
|
286
|
+
_makeDraggableField: function (opts) {
|
|
287
|
+
opts = deepDefaults(true, {
|
|
288
|
+
classes: {
|
|
289
|
+
'ui-draggable-handle': 'wcdv_drag_handle'
|
|
290
|
+
},
|
|
291
|
+
distance: 8, // FIXME Deprecated [1.12]: replacement will be in 1.13
|
|
292
|
+
helper: 'clone',
|
|
293
|
+
appendTo: document.body,
|
|
294
|
+
revert: true,
|
|
295
|
+
revertDuration: 0
|
|
296
|
+
});
|
|
297
|
+
var tooltipContent = jQuery('<div>', {
|
|
298
|
+
'data-tooltip': tooltipContent
|
|
299
|
+
})
|
|
300
|
+
.append(icon('info').css('padding-right', '0.25em').addClass('wcdv_text-primary'))
|
|
301
|
+
.append(trans('GRID.TABLE.DRAGGABLE_FIELD_HELP'));
|
|
302
|
+
return this
|
|
303
|
+
.draggable(opts);
|
|
304
|
+
},
|
|
305
|
+
|
|
306
|
+
_makeSortableTable: function (cb) {
|
|
307
|
+
var self = this;
|
|
308
|
+
|
|
309
|
+
var helperClone = function (e, tr) {
|
|
310
|
+
var originals = tr.children(),
|
|
311
|
+
clonedRow = tr.clone(),
|
|
312
|
+
start_idx = tr.index(),
|
|
313
|
+
all_rows = tr.parent().children(),
|
|
314
|
+
all_select = tr.find('select');
|
|
315
|
+
|
|
316
|
+
// first set the size of the row that was cloned (clonedRow).
|
|
317
|
+
// This keeps the table rows shape.
|
|
318
|
+
clonedRow.children().each(function(index, val) {
|
|
319
|
+
jQuery(val).width(originals.eq(index).width());
|
|
320
|
+
//_.each(['box-sizing'], function (cssProp) {
|
|
321
|
+
// jQuery(val).css(cssProp, originals.eq(index).css(cssProp));
|
|
322
|
+
//});
|
|
323
|
+
});
|
|
324
|
+
// second set the 'selected' value of any selects
|
|
325
|
+
// found during the clone. Seems jquery has a
|
|
326
|
+
// bug that will not be fixed.
|
|
327
|
+
clonedRow.find('select').val(function(index) {
|
|
328
|
+
return all_select.eq(index).val();
|
|
329
|
+
});
|
|
330
|
+
// third lets place a temp class on all the rows
|
|
331
|
+
// to keep the zerba striping, during the drag
|
|
332
|
+
for (var i = start_idx+1; i < all_rows.length; i++) {
|
|
333
|
+
if ((i % 2) == 0) {
|
|
334
|
+
// this row should really be even but because
|
|
335
|
+
// the clonedRow is hidden we need to make it
|
|
336
|
+
// odd to avoid the 'shifting of colors in the zebra'
|
|
337
|
+
jQuery(all_rows[i]).addClass('odd');
|
|
338
|
+
} else {
|
|
339
|
+
jQuery(all_rows[i]).addClass('even');
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
// lastly put the correct zebra strip on the cloned row
|
|
343
|
+
// that gets dragged around
|
|
344
|
+
if ((start_idx % 2) == 0) {
|
|
345
|
+
clonedRow.addClass('odd');
|
|
346
|
+
} else {
|
|
347
|
+
clonedRow.addClass('even');
|
|
348
|
+
}
|
|
349
|
+
return clonedRow;
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
self.on('keydown', 'button.drag-handle', function (event) {
|
|
353
|
+
var tr = jQuery(event.currentTarget).closest('tr'),
|
|
354
|
+
oldIndex = tr.index(),
|
|
355
|
+
newIndex = oldIndex;
|
|
356
|
+
|
|
357
|
+
// Reposition if one of the directional keys is pressed
|
|
358
|
+
switch (event.keyCode) {
|
|
359
|
+
case 38: // Up
|
|
360
|
+
event.preventDefault();
|
|
361
|
+
if (tr.prev().length) {
|
|
362
|
+
tr.insertBefore(tr.prev());
|
|
363
|
+
} else {
|
|
364
|
+
// already at the top so exit
|
|
365
|
+
return true;
|
|
366
|
+
}
|
|
367
|
+
break;
|
|
368
|
+
case 40: // Down
|
|
369
|
+
event.preventDefault();
|
|
370
|
+
if (tr.next().length) {
|
|
371
|
+
tr.insertAfter(tr.next());
|
|
372
|
+
} else {
|
|
373
|
+
// already at the bottom so exit
|
|
374
|
+
return true;
|
|
375
|
+
}
|
|
376
|
+
break;
|
|
377
|
+
default:
|
|
378
|
+
return true; // Exit
|
|
379
|
+
}
|
|
380
|
+
newIndex = tr.index();
|
|
381
|
+
if (oldIndex !== newIndex) {
|
|
382
|
+
cb(oldIndex, newIndex);
|
|
383
|
+
}
|
|
384
|
+
// keep focus on the button after move
|
|
385
|
+
jQuery(event.currentTarget).focus();
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
var opts = {
|
|
389
|
+
forcePlaceholderSize: true,
|
|
390
|
+
axis: 'y',
|
|
391
|
+
cancel: 'input,textarea,select,option',
|
|
392
|
+
helper: helperClone,
|
|
393
|
+
handle: '.drag-handle',
|
|
394
|
+
containment: self,
|
|
395
|
+
// This event is triggered when sorting starts.
|
|
396
|
+
start: function(event, ui) {
|
|
397
|
+
// set the height of the placeholder row on start
|
|
398
|
+
ui.placeholder.height(ui.helper.height());
|
|
399
|
+
ui.item.data('originIndex', ui.item.index());
|
|
400
|
+
},
|
|
401
|
+
// This event is triggered when sorting has stopped.
|
|
402
|
+
stop: function(event, ui) {
|
|
403
|
+
var oldIndex = ui.item.data('originIndex'),
|
|
404
|
+
newIndex = ui.item.index();
|
|
405
|
+
// the drag has stopped so remove the classes that 'override'
|
|
406
|
+
// the even/odd strips
|
|
407
|
+
ui.item.parent().children().removeClass('even odd');
|
|
408
|
+
|
|
409
|
+
if ( (typeof oldIndex !== 'undefined') &&
|
|
410
|
+
(typeof newIndex !== 'undefined') &&
|
|
411
|
+
(oldIndex !== newIndex) ) {
|
|
412
|
+
// swap the rows in our internal data structure
|
|
413
|
+
cb(oldIndex, newIndex);
|
|
414
|
+
} else {
|
|
415
|
+
// strange some bad data so just call the 'cancel' method
|
|
416
|
+
jQuery(this).sortable('cancel');
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
self.sortable(opts);
|
|
422
|
+
|
|
423
|
+
return this;
|
|
424
|
+
},
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Specify what to do when a file is dropped onto this element.
|
|
428
|
+
*
|
|
429
|
+
* ```
|
|
430
|
+
* $('#fileDropTarget')._onFileDrop(function (files) {
|
|
431
|
+
* something.addFiles(files);
|
|
432
|
+
* });
|
|
433
|
+
* ```
|
|
434
|
+
*
|
|
435
|
+
* @function external:"jQuery.fn"#_onFileDrop
|
|
436
|
+
*
|
|
437
|
+
* @param {function} cb
|
|
438
|
+
* Function to call when the file is dropped; it is passed a `File` array.
|
|
439
|
+
*/
|
|
440
|
+
|
|
441
|
+
_onFileDrop: function (cb) {
|
|
442
|
+
// https://www.html5rocks.com/en/tutorials/file/dndfiles/
|
|
443
|
+
function handleFileSelect(evt) {
|
|
444
|
+
evt.stopPropagation();
|
|
445
|
+
evt.preventDefault();
|
|
446
|
+
cb(evt.dataTransfer.files);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function handleDragOver(evt) {
|
|
450
|
+
evt.stopPropagation();
|
|
451
|
+
evt.preventDefault();
|
|
452
|
+
|
|
453
|
+
// Things I've tried to determine file type in drag+drop:
|
|
454
|
+
//
|
|
455
|
+
// evt.dataTransfer.items[0].type => MIME Type
|
|
456
|
+
//
|
|
457
|
+
// +---------+--------------------------------------+
|
|
458
|
+
// | Browser | Result |
|
|
459
|
+
// +=========+======================================+
|
|
460
|
+
// | Chrome | ** OK ** |
|
|
461
|
+
// | Firefox | ** OK ** |
|
|
462
|
+
// | IE11 | evt.dataTransfer.items doesn't exist |
|
|
463
|
+
// | Safari | evt.dataTransfer.items doesn't exist |
|
|
464
|
+
// | Edge | evt.dataTransfer.items[0].type = '' |
|
|
465
|
+
// +---------+--------------------------------------+
|
|
466
|
+
//
|
|
467
|
+
// Setting the dropEffect:
|
|
468
|
+
//
|
|
469
|
+
// +---------+-----------------------------+
|
|
470
|
+
// | Browser | Result |
|
|
471
|
+
// +=========+=============================+
|
|
472
|
+
// | Chrome | ** OK ** |
|
|
473
|
+
// | Firefox | ** OK ** |
|
|
474
|
+
// | IE11 | None (performs navigation) |
|
|
475
|
+
// | Safari | ** OK ** |
|
|
476
|
+
// | Edge | None (file always accepted) |
|
|
477
|
+
// +---------+-----------------------------+
|
|
478
|
+
|
|
479
|
+
switch (getProp(evt.dataTransfer, 'items', 0, 'type')) {
|
|
480
|
+
case 'text/csv':
|
|
481
|
+
case 'application/csv':
|
|
482
|
+
case 'application/vnd.ms-excel':
|
|
483
|
+
evt.dataTransfer.dropEffect = 'copy';
|
|
484
|
+
break;
|
|
485
|
+
default:
|
|
486
|
+
evt.dataTransfer.dropEffect = 'none';
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
this.get(0).addEventListener('dragover', handleDragOver, false);
|
|
491
|
+
this.get(0).addEventListener('drop', handleFileSelect, false);
|
|
492
|
+
},
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Sets a delegated event handler for a click event that won't fire when the user clicks and
|
|
496
|
+
* drags.
|
|
497
|
+
*
|
|
498
|
+
* @function external:"jQuery.fn"#_onSingleClick
|
|
499
|
+
*
|
|
500
|
+
* @param {string} sel
|
|
501
|
+
* jQuery selector for the delegated event.
|
|
502
|
+
*
|
|
503
|
+
* @param {function} cb
|
|
504
|
+
* Function to call when the click happens.
|
|
505
|
+
*
|
|
506
|
+
* @param {string[]} mod
|
|
507
|
+
* A list of modifiers that must be present when the click is started. The modifiers are:
|
|
508
|
+
*/
|
|
509
|
+
|
|
510
|
+
_onSingleClick: function (sel, cb, mod) {
|
|
511
|
+
var elt = this;
|
|
512
|
+
var maxDist = 4;
|
|
513
|
+
var evtInfo = {
|
|
514
|
+
state: 'up',
|
|
515
|
+
x0: 0,
|
|
516
|
+
y0: 0
|
|
517
|
+
};
|
|
518
|
+
elt.on('mousedown', sel, function (evt) {
|
|
519
|
+
if (mod != null) {
|
|
520
|
+
if (
|
|
521
|
+
(mod.indexOf('shift') >= 0 && !evt.shiftKey) ||
|
|
522
|
+
(mod.indexOf('ctrl') >= 0 && !evt.ctrlKey) ||
|
|
523
|
+
(mod.indexOf('alt') >= 0 && !evt.altKey)
|
|
524
|
+
) {
|
|
525
|
+
// User failed to hold a required mod key.
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
if (
|
|
529
|
+
(evt.shiftKey && mod.indexOf('shift') < 0) ||
|
|
530
|
+
(evt.ctrlKey && mod.indexOf('ctrl') < 0) ||
|
|
531
|
+
(evt.altKey && mod.indexOf('alt') < 0)
|
|
532
|
+
) {
|
|
533
|
+
// User held a mod key they weren't supposed to.
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
if (evt.shiftKey) {
|
|
538
|
+
// Normally, holding shift selects text. Prevent that from happening.
|
|
539
|
+
// FIXME: This loses any already existing selection. But restoring that is hard.
|
|
540
|
+
document.getSelection().empty();
|
|
541
|
+
}
|
|
542
|
+
evtInfo.state = 'down';
|
|
543
|
+
evtInfo.x0 = evt.clientX;
|
|
544
|
+
evtInfo.y0 = evt.clientY;
|
|
545
|
+
});
|
|
546
|
+
elt.on('mousemove', sel, function () {
|
|
547
|
+
if (evtInfo.state === 'down') {
|
|
548
|
+
evtInfo.state = 'drag';
|
|
549
|
+
}
|
|
550
|
+
});
|
|
551
|
+
elt.on('mouseup', sel, function (evt) {
|
|
552
|
+
var moveDist = 0;
|
|
553
|
+
switch (evtInfo.state) {
|
|
554
|
+
case 'down':
|
|
555
|
+
cb.call(this);
|
|
556
|
+
break;
|
|
557
|
+
case 'drag':
|
|
558
|
+
moveDist = Math.sqrt(Math.pow(evt.clientX - evtInfo.x0, 2) + Math.pow(evt.clientY - evtInfo.y0, 2));
|
|
559
|
+
if (moveDist < maxDist) {
|
|
560
|
+
cb.call(this);
|
|
561
|
+
}
|
|
562
|
+
break;
|
|
563
|
+
}
|
|
564
|
+
evtInfo.state = 'up';
|
|
565
|
+
});
|
|
566
|
+
},
|
|
567
|
+
|
|
568
|
+
findFieldCell: function (field) {
|
|
569
|
+
return this.children().filter(function (i, elt) {
|
|
570
|
+
return jQuery(elt).attr('data-wcdv-field') === field;
|
|
571
|
+
});
|
|
572
|
+
},
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* A shortcut for accessing DataVis-specific attributes on elements.
|
|
576
|
+
*
|
|
577
|
+
* @function external:"jQuery.fn"#dvAttr
|
|
578
|
+
*
|
|
579
|
+
* @param {string|object} name
|
|
580
|
+
* When a string, the partial name of the attribute. When an object, sets the values of a bunch
|
|
581
|
+
* of attributes at once. In both cases, the attribute names are prefixed with `data-wcdv-`.
|
|
582
|
+
*
|
|
583
|
+
* @param {string} [val]
|
|
584
|
+
* Assigns this value to the attribute, if provided.
|
|
585
|
+
*
|
|
586
|
+
* @returns {string|jQuery}
|
|
587
|
+
* When getting, returns the attribute value, which is always a string because HTML. When
|
|
588
|
+
* setting, returns `this` for chaining purposes.
|
|
589
|
+
*/
|
|
590
|
+
|
|
591
|
+
dvAttr: function () {
|
|
592
|
+
var args = Array.prototype.slice.call(arguments);
|
|
593
|
+
|
|
594
|
+
if (args.length === 1) {
|
|
595
|
+
if (typeof args[0] === 'string') {
|
|
596
|
+
return this.attr('data-wcdv-' + args[0]);
|
|
597
|
+
}
|
|
598
|
+
else if (typeof args[0] === 'object') {
|
|
599
|
+
for (var p in args[0]) {
|
|
600
|
+
if (Object.prototype.hasOwnProperty.call(args[0], p)) {
|
|
601
|
+
args[0]['data-wcdv-' + p] = args[0][p];
|
|
602
|
+
delete args[0][p];
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
return this.attr(args[0]);
|
|
606
|
+
}
|
|
607
|
+
else {
|
|
608
|
+
throw new Error('Call Error: Sole argument must be a string (getter) or object (setter)');
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
else if (args.length === 2) {
|
|
612
|
+
if (typeof args[0] !== 'string') {
|
|
613
|
+
throw new Error('Call Error: With two arguments, first argument must be a string');
|
|
614
|
+
}
|
|
615
|
+
if (args[1] != null && typeof args[1] !== 'string' && typeof args[1] !== 'number') {
|
|
616
|
+
if (typeof args[1] === 'boolean') {
|
|
617
|
+
args[1] = args[1] ? '1' : '0';
|
|
618
|
+
}
|
|
619
|
+
else {
|
|
620
|
+
throw new Error('Call Error: With two arguments, second must be a string, number, boolean, or null');
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
return this.attr('data-wcdv-' + args[0], args[1]);
|
|
625
|
+
}
|
|
626
|
+
else {
|
|
627
|
+
throw new Error('Call Error: dvAttr(string|object), dvAttr(string, string|number|boolean)');
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
});
|