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.
Files changed (62) hide show
  1. package/LICENSE +45 -0
  2. package/README.md +129 -0
  3. package/datavis.js +101 -0
  4. package/dist/wcdatavis.css +1957 -0
  5. package/dist/wcdatavis.min.js +1 -0
  6. package/global-jquery.js +4 -0
  7. package/ie-fixes.js +13 -0
  8. package/index.js +70 -0
  9. package/meteor.js +1 -0
  10. package/package.json +102 -0
  11. package/src/flags.js +6 -0
  12. package/src/graph.js +1079 -0
  13. package/src/graph_renderer.js +85 -0
  14. package/src/grid.js +2777 -0
  15. package/src/grid_control.js +1957 -0
  16. package/src/grid_filter.js +1073 -0
  17. package/src/grid_renderer.js +276 -0
  18. package/src/group_fun_win.js +121 -0
  19. package/src/lang/en-US.js +188 -0
  20. package/src/lang/es-MX.js +188 -0
  21. package/src/lang/fr-FR.js +188 -0
  22. package/src/lang/id-ID.js +188 -0
  23. package/src/lang/nl-NL.js +188 -0
  24. package/src/lang/pt-BR.js +188 -0
  25. package/src/lang/ru-RU.js +188 -0
  26. package/src/lang/th-TH.js +188 -0
  27. package/src/lang/vi-VN.js +188 -0
  28. package/src/lang/zh-Hans-CN.js +188 -0
  29. package/src/operations_palette.js +176 -0
  30. package/src/prefs_modules.js +132 -0
  31. package/src/reg/graph_renderer.js +17 -0
  32. package/src/renderers/graph/chartjs.js +457 -0
  33. package/src/renderers/graph/google.js +584 -0
  34. package/src/renderers/graph/jit.js +61 -0
  35. package/src/renderers/graph/svelte-gantt.js +168 -0
  36. package/src/renderers/grid/dummy.js +79 -0
  37. package/src/renderers/grid/handlebars.js +217 -0
  38. package/src/renderers/grid/squirrelly.js +215 -0
  39. package/src/renderers/grid/table/group_detail.js +1404 -0
  40. package/src/renderers/grid/table/group_summary.js +380 -0
  41. package/src/renderers/grid/table/pivot.js +915 -0
  42. package/src/renderers/grid/table/plain.js +1592 -0
  43. package/src/renderers/grid/table.js +2510 -0
  44. package/src/trans.js +101 -0
  45. package/src/ui/collapsible.js +234 -0
  46. package/src/ui/filters/date.js +283 -0
  47. package/src/ui/grid_filter.js +398 -0
  48. package/src/ui/popup_menu.js +224 -0
  49. package/src/ui/popup_window.js +572 -0
  50. package/src/ui/slider.js +156 -0
  51. package/src/ui/tabs.js +202 -0
  52. package/src/ui/templates.js +131 -0
  53. package/src/ui/toolbar.js +63 -0
  54. package/src/ui/toolbars/grid.js +873 -0
  55. package/src/ui/windows/col_config.js +341 -0
  56. package/src/ui/windows/debug.js +164 -0
  57. package/src/ui/windows/grid_table_opts.js +139 -0
  58. package/src/util/handlebars.js +158 -0
  59. package/src/util/jquery.js +630 -0
  60. package/src/util/misc.js +1058 -0
  61. package/src/util/squirrelly.js +155 -0
  62. 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
+ });