@datarailsshared/dr_renderer 1.2.110 → 1.2.111-dev

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/src/pivottable.js CHANGED
@@ -1,1874 +1,1874 @@
1
- // from pivottable@2.23.0
2
- let initPivotTable = function($, window, document) {
3
- var indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
4
- slice = [].slice,
5
- bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
6
- hasProp = {}.hasOwnProperty;
7
- /*
8
- Utilities
9
- */
10
- var PivotData, addSeparators, aggregatorTemplates, aggregators, dayNamesEn, derivers, getSort, locales, mthNamesEn, naturalSort, numberFormat, pivotTableRenderer, rd, renderers, rx, rz, sortAs, usFmt, usFmtInt, usFmtPct, zeroPad, errorHandling;
11
- addSeparators = function(nStr, thousandsSep, decimalSep) {
12
- var rgx, x, x1, x2;
13
- nStr += '';
14
- x = nStr.split('.');
15
- x1 = x[0];
16
- x2 = x.length > 1 ? decimalSep + x[1] : '';
17
- rgx = /(\d+)(\d{3})/;
18
- while (rgx.test(x1)) {
19
- x1 = x1.replace(rgx, '$1' + thousandsSep + '$2');
20
- }
21
- return x1 + x2;
22
- };
23
- let useTotalsCalculation = false;
24
- if (document.ReportHippo && document.ReportHippo && document.ReportHippo.user) {
25
- useTotalsCalculation = _.includes(document.ReportHippo.user.features, 'enable_server_totals_calculation');
26
- }
27
- numberFormat = function(opts) {
28
- var defaults;
29
- defaults = {
30
- digitsAfterDecimal: 2,
31
- scaler: 1,
32
- thousandsSep: ",",
33
- decimalSep: ".",
34
- prefix: "",
35
- suffix: ""
36
- };
37
- opts = $.extend({}, defaults, opts);
38
- return function(x) {
39
- var result;
40
- if (isNaN(x) || !isFinite(x)) {
41
- return "";
42
- }
43
- result = addSeparators((opts.scaler * x).toFixed(opts.digitsAfterDecimal), opts.thousandsSep, opts.decimalSep);
44
- return "" + opts.prefix + result + opts.suffix;
45
- };
46
- };
47
- usFmt = numberFormat();
48
- usFmtInt = numberFormat({
49
- digitsAfterDecimal: 0
50
- });
51
- usFmtPct = numberFormat({
52
- digitsAfterDecimal: 1,
53
- scaler: 100,
54
- suffix: "%"
55
- });
56
- aggregatorTemplates = {
57
- count: function(formatter) {
58
- if (formatter == null) {
59
- formatter = usFmtInt;
60
- }
61
- return function() {
62
- return function(data, rowKey, colKey) {
63
- return {
64
- count: 0,
65
- push: function() {
66
- return this.count++;
67
- },
68
- value: function() {
69
- return this.count;
70
- },
71
- format: formatter
72
- };
73
- };
74
- };
75
- },
76
- uniques: function(fn, formatter) {
77
- if (formatter == null) {
78
- formatter = usFmtInt;
79
- }
80
- return function(arg) {
81
- var attr;
82
- attr = arg[0];
83
- return function(data, rowKey, colKey) {
84
- return {
85
- uniq: [],
86
- push: function(record) {
87
- var ref;
88
- if (ref = record[attr], indexOf.call(this.uniq, ref) < 0) {
89
- return this.uniq.push(record[attr]);
90
- }
91
- },
92
- value: function() {
93
- return fn(this.uniq);
94
- },
95
- format: formatter,
96
- numInputs: attr != null ? 0 : 1
97
- };
98
- };
99
- };
100
- },
101
- sum: function(formatter) {
102
- if (formatter == null) {
103
- formatter = usFmt;
104
- }
105
- return function(arg) {
106
- var attr;
107
- attr = arg[0];
108
- return function(data, rowKey, colKey) {
109
- return {
110
- sum: 0,
111
- push: function(record) {
112
- if (!isNaN(parseFloat(record[attr]))) {
113
- return this.sum += parseFloat(record[attr]);
114
- }
115
- },
116
- value: function() {
117
- return this.sum;
118
- },
119
- format: formatter,
120
- numInputs: attr != null ? 0 : 1
121
- };
122
- };
123
- };
124
- },
125
- extremes: function(mode, formatter) {
126
- if (formatter == null) {
127
- formatter = usFmt;
128
- }
129
- return function(arg) {
130
- var attr;
131
- attr = arg[0];
132
- return function(data, rowKey, colKey) {
133
- return {
134
- val: null,
135
- sorter: getSort(data != null ? data.sorters : void 0, attr),
136
- push: function(record) {
137
- var ref, ref1, ref2, x;
138
- x = record[attr];
139
- if (mode === "min" || mode === "max") {
140
- x = parseFloat(x);
141
- if (!isNaN(x)) {
142
- this.val = Math[mode](x, (ref = this.val) != null ? ref : x);
143
- }
144
- }
145
- if (mode === "first") {
146
- if (this.sorter(x, (ref1 = this.val) != null ? ref1 : x) <= 0) {
147
- this.val = x;
148
- }
149
- }
150
- if (mode === "last") {
151
- if (this.sorter(x, (ref2 = this.val) != null ? ref2 : x) >= 0) {
152
- return this.val = x;
153
- }
154
- }
155
- },
156
- value: function() {
157
- return this.val;
158
- },
159
- format: function(x) {
160
- if (isNaN(x)) {
161
- return x;
162
- } else {
163
- return formatter(x);
164
- }
165
- },
166
- numInputs: attr != null ? 0 : 1
167
- };
168
- };
169
- };
170
- },
171
- quantile: function(q, formatter) {
172
- if (formatter == null) {
173
- formatter = usFmt;
174
- }
175
- return function(arg) {
176
- var attr;
177
- attr = arg[0];
178
- return function(data, rowKey, colKey) {
179
- return {
180
- vals: [],
181
- push: function(record) {
182
- var x;
183
- x = parseFloat(record[attr]);
184
- if (!isNaN(x)) {
185
- return this.vals.push(x);
186
- }
187
- },
188
- value: function() {
189
- var i;
190
- if (this.vals.length === 0) {
191
- return null;
192
- }
193
- this.vals.sort(function(a, b) {
194
- return a - b;
195
- });
196
- i = (this.vals.length - 1) * q;
197
- return (this.vals[Math.floor(i)] + this.vals[Math.ceil(i)]) / 2.0;
198
- },
199
- format: formatter,
200
- numInputs: attr != null ? 0 : 1
201
- };
202
- };
203
- };
204
- },
205
- runningStat: function(mode, ddof, formatter) {
206
- if (mode == null) {
207
- mode = "mean";
208
- }
209
- if (ddof == null) {
210
- ddof = 1;
211
- }
212
- if (formatter == null) {
213
- formatter = usFmt;
214
- }
215
- return function(arg) {
216
- var attr;
217
- attr = arg[0];
218
- return function(data, rowKey, colKey) {
219
- return {
220
- n: 0.0,
221
- m: 0.0,
222
- s: 0.0,
223
- push: function(record) {
224
- var m_new, x;
225
- x = parseFloat(record[attr]);
226
- if (isNaN(x)) {
227
- return;
228
- }
229
- this.n += 1.0;
230
- if (this.n === 1.0) {
231
- return this.m = x;
232
- } else {
233
- m_new = this.m + (x - this.m) / this.n;
234
- this.s = this.s + (x - this.m) * (x - m_new);
235
- return this.m = m_new;
236
- }
237
- },
238
- value: function() {
239
- if (mode === "mean") {
240
- if (this.n === 0) {
241
- return 0 / 0;
242
- } else {
243
- return this.m;
244
- }
245
- }
246
- if (this.n <= ddof) {
247
- return 0;
248
- }
249
- switch (mode) {
250
- case "var":
251
- return this.s / (this.n - ddof);
252
- case "stdev":
253
- return Math.sqrt(this.s / (this.n - ddof));
254
- }
255
- },
256
- format: formatter,
257
- numInputs: attr != null ? 0 : 1
258
- };
259
- };
260
- };
261
- },
262
- sumOverSum: function(formatter) {
263
- if (formatter == null) {
264
- formatter = usFmt;
265
- }
266
- return function(arg) {
267
- var denom, num;
268
- num = arg[0], denom = arg[1];
269
- return function(data, rowKey, colKey) {
270
- return {
271
- sumNum: 0,
272
- sumDenom: 0,
273
- push: function(record) {
274
- if (!isNaN(parseFloat(record[num]))) {
275
- this.sumNum += parseFloat(record[num]);
276
- }
277
- if (!isNaN(parseFloat(record[denom]))) {
278
- return this.sumDenom += parseFloat(record[denom]);
279
- }
280
- },
281
- value: function() {
282
- return this.sumNum / this.sumDenom;
283
- },
284
- format: formatter,
285
- numInputs: (num != null) && (denom != null) ? 0 : 2
286
- };
287
- };
288
- };
289
- },
290
- sumOverSumBound80: function(upper, formatter) {
291
- if (upper == null) {
292
- upper = true;
293
- }
294
- if (formatter == null) {
295
- formatter = usFmt;
296
- }
297
- return function(arg) {
298
- var denom, num;
299
- num = arg[0], denom = arg[1];
300
- return function(data, rowKey, colKey) {
301
- return {
302
- sumNum: 0,
303
- sumDenom: 0,
304
- push: function(record) {
305
- if (!isNaN(parseFloat(record[num]))) {
306
- this.sumNum += parseFloat(record[num]);
307
- }
308
- if (!isNaN(parseFloat(record[denom]))) {
309
- return this.sumDenom += parseFloat(record[denom]);
310
- }
311
- },
312
- value: function() {
313
- var sign;
314
- sign = upper ? 1 : -1;
315
- return (0.821187207574908 / this.sumDenom + this.sumNum / this.sumDenom + 1.2815515655446004 * sign * Math.sqrt(0.410593603787454 / (this.sumDenom * this.sumDenom) + (this.sumNum * (1 - this.sumNum / this.sumDenom)) / (this.sumDenom * this.sumDenom))) / (1 + 1.642374415149816 / this.sumDenom);
316
- },
317
- format: formatter,
318
- numInputs: (num != null) && (denom != null) ? 0 : 2
319
- };
320
- };
321
- };
322
- },
323
- fractionOf: function(wrapped, type, formatter) {
324
- if (type == null) {
325
- type = "total";
326
- }
327
- if (formatter == null) {
328
- formatter = usFmtPct;
329
- }
330
- return function() {
331
- var x;
332
- x = 1 <= arguments.length ? slice.call(arguments, 0) : [];
333
- return function(data, rowKey, colKey) {
334
- return {
335
- selector: {
336
- total: [[], []],
337
- row: [rowKey, []],
338
- col: [[], colKey]
339
- }[type],
340
- inner: wrapped.apply(null, x)(data, rowKey, colKey),
341
- push: function(record) {
342
- return this.inner.push(record);
343
- },
344
- format: formatter,
345
- value: function() {
346
- return this.inner.value() / data.getAggregator.apply(data, this.selector).inner.value();
347
- },
348
- numInputs: wrapped.apply(null, x)().numInputs
349
- };
350
- };
351
- };
352
- }
353
- };
354
- aggregatorTemplates.countUnique = function(f) {
355
- return aggregatorTemplates.uniques((function(x) {
356
- return x.length;
357
- }), f);
358
- };
359
- aggregatorTemplates.listUnique = function(s) {
360
- return aggregatorTemplates.uniques((function(x) {
361
- return x.sort(naturalSort).join(s);
362
- }), (function(x) {
363
- return x;
364
- }));
365
- };
366
- aggregatorTemplates.max = function(f) {
367
- return aggregatorTemplates.extremes('max', f);
368
- };
369
- aggregatorTemplates.min = function(f) {
370
- return aggregatorTemplates.extremes('min', f);
371
- };
372
- aggregatorTemplates.first = function(f) {
373
- return aggregatorTemplates.extremes('first', f);
374
- };
375
- aggregatorTemplates.last = function(f) {
376
- return aggregatorTemplates.extremes('last', f);
377
- };
378
- aggregatorTemplates.median = function(f) {
379
- return aggregatorTemplates.quantile(0.5, f);
380
- };
381
- aggregatorTemplates.average = function(f) {
382
- return aggregatorTemplates.runningStat("mean", 1, f);
383
- };
384
- aggregatorTemplates["var"] = function(ddof, f) {
385
- return aggregatorTemplates.runningStat("var", ddof, f);
386
- };
387
- aggregatorTemplates.stdev = function(ddof, f) {
388
- return aggregatorTemplates.runningStat("stdev", ddof, f);
389
- };
390
- aggregators = (function(tpl) {
391
- return {
392
- "Count": tpl.count(usFmtInt),
393
- "Count Unique Values": tpl.countUnique(usFmtInt),
394
- "List Unique Values": tpl.listUnique(", "),
395
- "Sum": tpl.sum(usFmt),
396
- "Integer Sum": tpl.sum(usFmtInt),
397
- "Average": tpl.average(usFmt),
398
- "Median": tpl.median(usFmt),
399
- "Sample Variance": tpl["var"](1, usFmt),
400
- "Sample Standard Deviation": tpl.stdev(1, usFmt),
401
- "Minimum": tpl.min(usFmt),
402
- "Maximum": tpl.max(usFmt),
403
- "First": tpl.first(usFmt),
404
- "Last": tpl.last(usFmt),
405
- "Sum over Sum": tpl.sumOverSum(usFmt),
406
- "80% Upper Bound": tpl.sumOverSumBound80(true, usFmt),
407
- "80% Lower Bound": tpl.sumOverSumBound80(false, usFmt),
408
- "Sum as Fraction of Total": tpl.fractionOf(tpl.sum(), "total", usFmtPct),
409
- "Sum as Fraction of Rows": tpl.fractionOf(tpl.sum(), "row", usFmtPct),
410
- "Sum as Fraction of Columns": tpl.fractionOf(tpl.sum(), "col", usFmtPct),
411
- "Count as Fraction of Total": tpl.fractionOf(tpl.count(), "total", usFmtPct),
412
- "Count as Fraction of Rows": tpl.fractionOf(tpl.count(), "row", usFmtPct),
413
- "Count as Fraction of Columns": tpl.fractionOf(tpl.count(), "col", usFmtPct)
414
- };
415
- })(aggregatorTemplates);
416
- renderers = {
417
- "Table": function(data, opts) {
418
- return pivotTableRenderer(data, opts);
419
- },
420
- "Table Barchart": function(data, opts) {
421
- return $(pivotTableRenderer(data, opts)).barchart();
422
- },
423
- "Heatmap": function(data, opts) {
424
- return $(pivotTableRenderer(data, opts)).heatmap("heatmap", opts);
425
- },
426
- "Row Heatmap": function(data, opts) {
427
- return $(pivotTableRenderer(data, opts)).heatmap("rowheatmap", opts);
428
- },
429
- "Col Heatmap": function(data, opts) {
430
- return $(pivotTableRenderer(data, opts)).heatmap("colheatmap", opts);
431
- }
432
- };
433
- locales = {
434
- en: {
435
- aggregators: aggregators,
436
- renderers: renderers,
437
- localeStrings: {
438
- renderError: "An error occurred rendering the PivotTable results.",
439
- computeError: "An error occurred computing the PivotTable results.",
440
- uiRenderError: "An error occurred rendering the PivotTable UI.",
441
- selectAll: "Select All",
442
- selectNone: "Select None",
443
- tooMany: "(too many to list)",
444
- filterResults: "Filter values",
445
- apply: "Apply",
446
- cancel: "Cancel",
447
- totals: "Totals",
448
- vs: "vs",
449
- by: "by"
450
- }
451
- }
452
- };
453
- mthNamesEn = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
454
- dayNamesEn = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
455
- zeroPad = function(number) {
456
- return ("0" + number).substr(-2, 2);
457
- };
458
- derivers = {
459
- bin: function(col, binWidth) {
460
- return function(record) {
461
- return record[col] - record[col] % binWidth;
462
- };
463
- },
464
- dateFormat: function(col, formatString, utcOutput, mthNames, dayNames) {
465
- var utc;
466
- if (utcOutput == null) {
467
- utcOutput = false;
468
- }
469
- if (mthNames == null) {
470
- mthNames = mthNamesEn;
471
- }
472
- if (dayNames == null) {
473
- dayNames = dayNamesEn;
474
- }
475
- utc = utcOutput ? "UTC" : "";
476
- return function(record) {
477
- var date;
478
- date = new Date(Date.parse(record[col]));
479
- if (isNaN(date)) {
480
- return "";
481
- }
482
- return formatString.replace(/%(.)/g, function(m, p) {
483
- switch (p) {
484
- case "y":
485
- return date["get" + utc + "FullYear"]();
486
- case "m":
487
- return zeroPad(date["get" + utc + "Month"]() + 1);
488
- case "n":
489
- return mthNames[date["get" + utc + "Month"]()];
490
- case "d":
491
- return zeroPad(date["get" + utc + "Date"]());
492
- case "w":
493
- return dayNames[date["get" + utc + "Day"]()];
494
- case "x":
495
- return date["get" + utc + "Day"]();
496
- case "H":
497
- return zeroPad(date["get" + utc + "Hours"]());
498
- case "M":
499
- return zeroPad(date["get" + utc + "Minutes"]());
500
- case "S":
501
- return zeroPad(date["get" + utc + "Seconds"]());
502
- default:
503
- return "%" + p;
504
- }
505
- });
506
- };
507
- }
508
- };
509
- rx = /(\d+)|(\D+)/g;
510
- rd = /\d/;
511
- rz = /^0/;
512
- naturalSort = (function(_this) {
513
- return function(as, bs) {
514
- var a, a1, b, b1, nas, nbs;
515
- if ((bs != null) && (as == null)) {
516
- return -1;
517
- }
518
- if ((as != null) && (bs == null)) {
519
- return 1;
520
- }
521
- if (typeof as === "number" && isNaN(as)) {
522
- return -1;
523
- }
524
- if (typeof bs === "number" && isNaN(bs)) {
525
- return 1;
526
- }
527
- nas = +as;
528
- nbs = +bs;
529
- if (nas < nbs) {
530
- return -1;
531
- }
532
- if (nas > nbs) {
533
- return 1;
534
- }
535
- if (typeof as === "number" && typeof bs !== "number") {
536
- return -1;
537
- }
538
- if (typeof bs === "number" && typeof as !== "number") {
539
- return 1;
540
- }
541
- if (typeof as === "number" && typeof bs === "number") {
542
- return 0;
543
- }
544
- if (isNaN(nbs) && !isNaN(nas)) {
545
- return -1;
546
- }
547
- if (isNaN(nas) && !isNaN(nbs)) {
548
- return 1;
549
- }
550
- a = String(as).toLowerCase();
551
- b = String(bs).toLowerCase();
552
- if (a === b) {
553
- return 0;
554
- }
555
- if (!(rd.test(a) && rd.test(b))) {
556
- return (a > b ? 1 : -1);
557
- }
558
- a = a.match(rx);
559
- b = b.match(rx);
560
- while (a.length && b.length) {
561
- a1 = a.shift();
562
- b1 = b.shift();
563
- if (a1 !== b1) {
564
- if (rd.test(a1) && rd.test(b1)) {
565
- return a1.replace(rz, ".0") - b1.replace(rz, ".0");
566
- } else {
567
- return (a1 > b1 ? 1 : -1);
568
- }
569
- }
570
- }
571
- return a.length - b.length;
572
- };
573
- })(this);
574
- sortAs = function(order) {
575
- var i, l_mapping, mapping, x;
576
- mapping = {};
577
- l_mapping = {};
578
- for (i in order) {
579
- x = order[i];
580
- mapping[x] = i;
581
- if (typeof x === "string") {
582
- l_mapping[x.toLowerCase()] = i;
583
- }
584
- }
585
- return function(a, b) {
586
- if ((mapping[a] != null) && (mapping[b] != null)) {
587
- return mapping[a] - mapping[b];
588
- } else if (mapping[a] != null) {
589
- return -1;
590
- } else if (mapping[b] != null) {
591
- return 1;
592
- } else if ((l_mapping[a] != null) && (l_mapping[b] != null)) {
593
- return l_mapping[a] - l_mapping[b];
594
- } else if (l_mapping[a] != null) {
595
- return -1;
596
- } else if (l_mapping[b] != null) {
597
- return 1;
598
- } else {
599
- return naturalSort(a, b);
600
- }
601
- };
602
- };
603
- getSort = function(sorters, attr) {
604
- var sort;
605
- if (sorters != null) {
606
- if ($.isFunction(sorters)) {
607
- sort = sorters(attr);
608
- if ($.isFunction(sort)) {
609
- return sort;
610
- }
611
- } else if (sorters[attr] != null) {
612
- return sorters[attr];
613
- }
614
- }
615
- return naturalSort;
616
- };
617
- errorHandling = {
618
- placeholders: {
619
- nodata: {
620
- title: 'No Data Available',
621
- text: 'This might happen because of a global filter or a change in the underlying data',
622
- btnText: '',
623
- class: 'nodata',
624
- },
625
- noPermission: {
626
- title: 'No Permission',
627
- text: 'You do not have permission to view the data',
628
- btnText: 'Request Permission',
629
- class: 'no-permission',
630
- },
631
- tooMuchData: {
632
- title: 'There is too much data. Please edit this widget',
633
- text: '',
634
- btnText: 'Edit Widget',
635
- class: 'too-much-data',
636
- },
637
- noPublishItem: {
638
- title: 'We can’t find the published item in the source file',
639
- text: '',
640
- btnText: 'Go to filebox',
641
- class: 'no-publish-item',
642
- },
643
- },
644
- getErrorPlaceholder: function(placeholder, useNewUx = true) {
645
- if (placeholder && typeof placeholder === 'object') {
646
- return $(`
647
- <div class="noData">
648
- <div class="noData-title">${placeholder.title}</div>
649
- <i class="noData-image ${useNewUx ? placeholder.class : 'fa fa-info'}"></i>
650
- <div class="noData-text">${placeholder.text}</div>
651
- <div class="noData-error-action"></div>
652
- </div>
653
- `);
654
- }
655
- return null;
656
- },
657
- };
658
-
659
- /*
660
- Data Model class
661
- */
662
- PivotData = (function() {
663
- function PivotData(input, opts) {
664
- var ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9;
665
- if (opts == null) {
666
- opts = {};
667
- }
668
- this.getAggregator = bind(this.getAggregator, this);
669
- this.getRowKeys = bind(this.getRowKeys, this);
670
- this.getColKeys = bind(this.getColKeys, this);
671
- this.sortKeys = bind(this.sortKeys, this);
672
- this.arrSort = bind(this.arrSort, this);
673
- this.input = input;
674
- this.aggregator = (ref = opts.aggregator) != null ? ref : aggregatorTemplates.count()();
675
- this.aggregatorName = (ref1 = opts.aggregatorName) != null ? ref1 : "Count";
676
- this.colAttrs = (ref2 = opts.cols) != null ? ref2 : [];
677
- this.rowAttrs = (ref3 = opts.rows) != null ? ref3 : [];
678
- this.valAttrs = (ref4 = opts.vals) != null ? ref4 : [];
679
- this.sorters = (ref5 = opts.sorters) != null ? ref5 : {};
680
- this.rowOrder = (ref6 = opts.rowOrder) != null ? ref6 : "key_a_to_z";
681
- this.colOrder = (ref7 = opts.colOrder) != null ? ref7 : "key_a_to_z";
682
- this.derivedAttributes = (ref8 = opts.derivedAttributes) != null ? ref8 : {};
683
- this.filter = (ref9 = opts.filter) != null ? ref9 : (function() {
684
- return true;
685
- });
686
- this.tree = {};
687
- this.rowKeys = [];
688
- this.colKeys = [];
689
- this.rowTotals = {};
690
- this.colTotals = {};
691
- this.allTotal = this.aggregator(this, [], []);
692
- this.sorted = false;
693
- PivotData.forEachRecord(this.input, this.derivedAttributes, (function(_this) {
694
- return function(record) {
695
- if (_this.filter(record)) {
696
- return _this.processRecord(record, useTotalsCalculation);
697
- }
698
- };
699
- })(this));
700
- }
701
-
702
- PivotData.forEachRecord = function(input, derivedAttributes, f) {
703
- var addRecord, compactRecord, i, j, k, l, len1, record, ref, results, results1, tblCols;
704
- if ($.isEmptyObject(derivedAttributes)) {
705
- addRecord = f;
706
- } else {
707
- addRecord = function(record) {
708
- var k, ref, v;
709
- for (k in derivedAttributes) {
710
- v = derivedAttributes[k];
711
- record[k] = (ref = v(record)) != null ? ref : record[k];
712
- }
713
- return f(record);
714
- };
715
- }
716
- if ($.isFunction(input)) {
717
- return input(addRecord);
718
- } else if ($.isArray(input)) {
719
- if ($.isArray(input[0])) {
720
- results = [];
721
- for (i in input) {
722
- if (!hasProp.call(input, i)) continue;
723
- compactRecord = input[i];
724
- if (!(i > 0)) {
725
- continue;
726
- }
727
- record = {};
728
- ref = input[0];
729
- for (j in ref) {
730
- if (!hasProp.call(ref, j)) continue;
731
- k = ref[j];
732
- record[k] = compactRecord[j];
733
- }
734
- results.push(addRecord(record));
735
- }
736
- return results;
737
- } else {
738
- results1 = [];
739
- for (l = 0, len1 = input.length; l < len1; l++) {
740
- record = input[l];
741
- results1.push(addRecord(record));
742
- }
743
- return results1;
744
- }
745
- } else if (input instanceof $) {
746
- tblCols = [];
747
- $("thead > tr > th", input).each(function(i) {
748
- return tblCols.push($(this).text());
749
- });
750
- return $("tbody > tr", input).each(function(i) {
751
- record = {};
752
- $("td", this).each(function(j) {
753
- return record[tblCols[j]] = $(this).text();
754
- });
755
- return addRecord(record);
756
- });
757
- } else {
758
- throw new Error("unknown input format");
759
- }
760
- };
761
-
762
- PivotData.prototype.forEachMatchingRecord = function(criteria, callback) {
763
- return PivotData.forEachRecord(this.input, this.derivedAttributes, (function(_this) {
764
- return function(record) {
765
- var k, ref, v;
766
- if (!_this.filter(record)) {
767
- return;
768
- }
769
- for (k in criteria) {
770
- v = criteria[k];
771
- if (v !== ((ref = record[k]) != null ? ref : "null")) {
772
- return;
773
- }
774
- }
775
- return callback(record);
776
- };
777
- })(this));
778
- };
779
-
780
- PivotData.prototype.arrSort = function(attrs) {
781
- var a, sortersArr;
782
- sortersArr = (function() {
783
- var l, len1, results;
784
- results = [];
785
- for (l = 0, len1 = attrs.length; l < len1; l++) {
786
- a = attrs[l];
787
- results.push(getSort(this.sorters, a));
788
- }
789
- return results;
790
- }).call(this);
791
- return function(a, b) {
792
- var comparison, i, sorter;
793
- for (i in sortersArr) {
794
- if (!hasProp.call(sortersArr, i)) continue;
795
- sorter = sortersArr[i];
796
- comparison = sorter(a[i], b[i]);
797
- if (comparison !== 0) {
798
- return comparison;
799
- }
800
- }
801
- return 0;
802
- };
803
- };
804
-
805
- PivotData.prototype.sortKeys = function() {
806
- var v;
807
- if (!this.sorted) {
808
- this.sorted = true;
809
- v = (function(_this) {
810
- return function(r, c) {
811
- return _this.getAggregator(r, c).value();
812
- };
813
- })(this);
814
- switch (this.rowOrder) {
815
- case "value_a_to_z":
816
- this.rowKeys.sort((function(_this) {
817
- return function(a, b) {
818
- return naturalSort(v(a, []), v(b, []));
819
- };
820
- })(this));
821
- break;
822
- case "value_z_to_a":
823
- this.rowKeys.sort((function(_this) {
824
- return function(a, b) {
825
- return -naturalSort(v(a, []), v(b, []));
826
- };
827
- })(this));
828
- break;
829
- default:
830
- this.rowKeys.sort(this.arrSort(this.rowAttrs));
831
- }
832
- switch (this.colOrder) {
833
- case "value_a_to_z":
834
- return this.colKeys.sort((function(_this) {
835
- return function(a, b) {
836
- return naturalSort(v([], a), v([], b));
837
- };
838
- })(this));
839
- case "value_z_to_a":
840
- return this.colKeys.sort((function(_this) {
841
- return function(a, b) {
842
- return -naturalSort(v([], a), v([], b));
843
- };
844
- })(this));
845
- default:
846
- return this.colKeys.sort(this.arrSort(this.colAttrs));
847
- }
848
- }
849
- };
850
-
851
- PivotData.prototype.getColKeys = function() {
852
- this.sortKeys();
853
- return this.colKeys;
854
- };
855
-
856
- PivotData.prototype.getRowKeys = function() {
857
- this.sortKeys();
858
- return this.rowKeys;
859
- };
860
-
861
- PivotData.prototype.processRecord = function(record) {
862
- var colKey, flatColKey, flatRowKey, l, len1, len2, n, ref, ref1, ref2, ref3, rowKey, x;
863
- colKey = [];
864
- rowKey = [];
865
- ref = this.colAttrs;
866
- for (l = 0, len1 = ref.length; l < len1; l++) {
867
- x = ref[l];
868
- colKey.push((ref1 = record[x]) != null ? ref1 : "null");
869
- }
870
- ref2 = this.rowAttrs;
871
- for (n = 0, len2 = ref2.length; n < len2; n++) {
872
- x = ref2[n];
873
- rowKey.push((ref3 = record[x]) != null ? ref3 : "null");
874
- }
875
- flatRowKey = rowKey.join(String.fromCharCode(0));
876
- flatColKey = colKey.join(String.fromCharCode(0));
877
- this.allTotal.push(record);
878
- if (rowKey.length !== 0) {
879
- if (!this.rowTotals[flatRowKey]) {
880
- this.rowKeys.push(rowKey);
881
- this.rowTotals[flatRowKey] = this.aggregator(this, rowKey, []);
882
- }
883
- this.rowTotals[flatRowKey].push(record);
884
- }
885
- if (colKey.length !== 0) {
886
- if (!this.colTotals[flatColKey]) {
887
- this.colKeys.push(colKey);
888
- this.colTotals[flatColKey] = this.aggregator(this, [], colKey);
889
- }
890
- this.colTotals[flatColKey].push(record);
891
- }
892
- if (colKey.length !== 0 && rowKey.length !== 0) {
893
- if (!this.tree[flatRowKey]) {
894
- this.tree[flatRowKey] = {};
895
- }
896
- if (!this.tree[flatRowKey][flatColKey]) {
897
- this.tree[flatRowKey][flatColKey] = this.aggregator(this, rowKey, colKey);
898
- }
899
- return this.tree[flatRowKey][flatColKey].push(record);
900
- }
901
- };
902
-
903
- PivotData.prototype.getAggregator = function(rowKey, colKey) {
904
- var agg, flatColKey, flatRowKey;
905
- flatRowKey = rowKey.join(String.fromCharCode(0));
906
- flatColKey = colKey.join(String.fromCharCode(0));
907
- if (rowKey.length === 0 && colKey.length === 0) {
908
- agg = this.allTotal;
909
- } else if (rowKey.length === 0) {
910
- agg = this.colTotals[flatColKey];
911
- } else if (colKey.length === 0) {
912
- agg = this.rowTotals[flatRowKey];
913
- } else {
914
- agg = this.tree[flatRowKey][flatColKey];
915
- }
916
- return agg != null ? agg : {
917
- value: (function() {
918
- return null;
919
- }),
920
- format: function() {
921
- return "";
922
- }
923
- };
924
- };
925
-
926
- return PivotData;
927
-
928
- })();
929
-
930
- $.pivotUtilities = {
931
- aggregatorTemplates: aggregatorTemplates,
932
- aggregators: aggregators,
933
- renderers: renderers,
934
- derivers: derivers,
935
- locales: locales,
936
- naturalSort: naturalSort,
937
- numberFormat: numberFormat,
938
- sortAs: sortAs,
939
- PivotData: PivotData,
940
- errorHandling: errorHandling,
941
- };
942
- if (window.$) {
943
- window.$.pivotUtilities = $.pivotUtilities
944
- }
945
-
946
- /*
947
- Default Renderer for hierarchical table layout
948
- */
949
- pivotTableRenderer = function(pivotData, opts) {
950
- var aggregator, c, colAttrs, colKey, colKeys, defaults, getClickHandler, i, j, r, result, rowAttrs, rowKey, rowKeys, spanSize, tbody, td, th, thead, totalAggregator, tr, txt, val, x;
951
- defaults = {
952
- table: {
953
- clickCallback: null,
954
- rowTotals: true,
955
- colTotals: true
956
- },
957
- localeStrings: {
958
- totals: "Totals"
959
- }
960
- };
961
- opts = $.extend(true, {}, defaults, opts);
962
- colAttrs = pivotData.colAttrs;
963
- rowAttrs = pivotData.rowAttrs;
964
- rowKeys = pivotData.getRowKeys();
965
- colKeys = pivotData.getColKeys();
966
- if (opts.table.clickCallback) {
967
- getClickHandler = function(value, rowValues, colValues) {
968
- var attr, filters, i;
969
- filters = {};
970
- for (i in colAttrs) {
971
- if (!hasProp.call(colAttrs, i)) continue;
972
- attr = colAttrs[i];
973
- if (colValues[i] != null) {
974
- filters[attr] = colValues[i];
975
- }
976
- }
977
- for (i in rowAttrs) {
978
- if (!hasProp.call(rowAttrs, i)) continue;
979
- attr = rowAttrs[i];
980
- if (rowValues[i] != null) {
981
- filters[attr] = rowValues[i];
982
- }
983
- }
984
- return function(e) {
985
- return opts.table.clickCallback(e, value, filters, pivotData);
986
- };
987
- };
988
- }
989
- result = document.createElement("table");
990
- result.className = "pvtTable";
991
- spanSize = function(arr, i, j) {
992
- var l, len, n, noDraw, ref, ref1, stop, x;
993
- if (i !== 0) {
994
- noDraw = true;
995
- for (x = l = 0, ref = j; 0 <= ref ? l <= ref : l >= ref; x = 0 <= ref ? ++l : --l) {
996
- if (arr[i - 1][x] !== arr[i][x]) {
997
- noDraw = false;
998
- }
999
- }
1000
- if (noDraw) {
1001
- return -1;
1002
- }
1003
- }
1004
- len = 0;
1005
- while (i + len < arr.length) {
1006
- stop = false;
1007
- for (x = n = 0, ref1 = j; 0 <= ref1 ? n <= ref1 : n >= ref1; x = 0 <= ref1 ? ++n : --n) {
1008
- if (arr[i][x] !== arr[i + len][x]) {
1009
- stop = true;
1010
- }
1011
- }
1012
- if (stop) {
1013
- break;
1014
- }
1015
- len++;
1016
- }
1017
- return len;
1018
- };
1019
- thead = document.createElement("thead");
1020
- for (j in colAttrs) {
1021
- if (!hasProp.call(colAttrs, j)) continue;
1022
- c = colAttrs[j];
1023
- tr = document.createElement("tr");
1024
- if (parseInt(j) === 0 && rowAttrs.length !== 0) {
1025
- th = document.createElement("th");
1026
- th.setAttribute("colspan", rowAttrs.length);
1027
- th.setAttribute("rowspan", colAttrs.length);
1028
- tr.appendChild(th);
1029
- }
1030
- th = document.createElement("th");
1031
- th.className = "pvtAxisLabel";
1032
- th.textContent = c;
1033
- tr.appendChild(th);
1034
- for (i in colKeys) {
1035
- if (!hasProp.call(colKeys, i)) continue;
1036
- colKey = colKeys[i];
1037
- x = spanSize(colKeys, parseInt(i), parseInt(j));
1038
- if (x !== -1) {
1039
- th = document.createElement("th");
1040
- th.className = "pvtColLabel";
1041
- th.textContent = colKey[j];
1042
- th.setAttribute("colspan", x);
1043
- if (parseInt(j) === colAttrs.length - 1 && rowAttrs.length !== 0) {
1044
- th.setAttribute("rowspan", 2);
1045
- }
1046
- tr.appendChild(th);
1047
- }
1048
- }
1049
- if (parseInt(j) === 0 && opts.table.rowTotals) {
1050
- th = document.createElement("th");
1051
- th.className = "pvtTotalLabel pvtRowTotalLabel";
1052
- th.innerHTML = opts.localeStrings.totals;
1053
- th.setAttribute("rowspan", colAttrs.length + (rowAttrs.length === 0 ? 0 : 1));
1054
- tr.appendChild(th);
1055
- }
1056
- thead.appendChild(tr);
1057
- }
1058
- if (rowAttrs.length !== 0) {
1059
- tr = document.createElement("tr");
1060
- for (i in rowAttrs) {
1061
- if (!hasProp.call(rowAttrs, i)) continue;
1062
- r = rowAttrs[i];
1063
- th = document.createElement("th");
1064
- th.className = "pvtAxisLabel";
1065
- th.textContent = r;
1066
- tr.appendChild(th);
1067
- }
1068
- th = document.createElement("th");
1069
- if (colAttrs.length === 0) {
1070
- th.className = "pvtTotalLabel pvtRowTotalLabel";
1071
- th.innerHTML = opts.localeStrings.totals;
1072
- }
1073
- tr.appendChild(th);
1074
- thead.appendChild(tr);
1075
- }
1076
- result.appendChild(thead);
1077
- tbody = document.createElement("tbody");
1078
- for (i in rowKeys) {
1079
- if (!hasProp.call(rowKeys, i)) continue;
1080
- rowKey = rowKeys[i];
1081
- tr = document.createElement("tr");
1082
- for (j in rowKey) {
1083
- if (!hasProp.call(rowKey, j)) continue;
1084
- txt = rowKey[j];
1085
- x = spanSize(rowKeys, parseInt(i), parseInt(j));
1086
- if (x !== -1) {
1087
- th = document.createElement("th");
1088
- th.className = "pvtRowLabel";
1089
- th.textContent = txt;
1090
- th.setAttribute("rowspan", x);
1091
- if (parseInt(j) === rowAttrs.length - 1 && colAttrs.length !== 0) {
1092
- th.setAttribute("colspan", 2);
1093
- }
1094
- tr.appendChild(th);
1095
- }
1096
- }
1097
- for (j in colKeys) {
1098
- if (!hasProp.call(colKeys, j)) continue;
1099
- colKey = colKeys[j];
1100
- aggregator = pivotData.getAggregator(rowKey, colKey);
1101
- val = aggregator.value();
1102
- td = document.createElement("td");
1103
- td.className = "pvtVal row" + i + " col" + j;
1104
- td.textContent = aggregator.format(val);
1105
- td.setAttribute("data-value", val);
1106
- if (getClickHandler != null) {
1107
- td.onclick = getClickHandler(val, rowKey, colKey);
1108
- }
1109
- tr.appendChild(td);
1110
- }
1111
- if (opts.table.rowTotals || colAttrs.length === 0) {
1112
- totalAggregator = pivotData.getAggregator(rowKey, []);
1113
- val = totalAggregator.value();
1114
- td = document.createElement("td");
1115
- td.className = "pvtTotal rowTotal";
1116
- td.textContent = totalAggregator.format(val);
1117
- td.setAttribute("data-value", val);
1118
- if (getClickHandler != null) {
1119
- td.onclick = getClickHandler(val, rowKey, []);
1120
- }
1121
- td.setAttribute("data-for", "row" + i);
1122
- tr.appendChild(td);
1123
- }
1124
- tbody.appendChild(tr);
1125
- }
1126
- if (opts.table.colTotals || rowAttrs.length === 0) {
1127
- tr = document.createElement("tr");
1128
- if (opts.table.colTotals || rowAttrs.length === 0) {
1129
- th = document.createElement("th");
1130
- th.className = "pvtTotalLabel pvtColTotalLabel";
1131
- th.innerHTML = opts.localeStrings.totals;
1132
- th.setAttribute("colspan", rowAttrs.length + (colAttrs.length === 0 ? 0 : 1));
1133
- tr.appendChild(th);
1134
- }
1135
- for (j in colKeys) {
1136
- if (!hasProp.call(colKeys, j)) continue;
1137
- colKey = colKeys[j];
1138
- totalAggregator = pivotData.getAggregator([], colKey);
1139
- val = totalAggregator.value();
1140
- td = document.createElement("td");
1141
- td.className = "pvtTotal colTotal";
1142
- td.textContent = totalAggregator.format(val);
1143
- td.setAttribute("data-value", val);
1144
- if (getClickHandler != null) {
1145
- td.onclick = getClickHandler(val, [], colKey);
1146
- }
1147
- td.setAttribute("data-for", "col" + j);
1148
- tr.appendChild(td);
1149
- }
1150
- if (opts.table.rowTotals || colAttrs.length === 0) {
1151
- totalAggregator = pivotData.getAggregator([], []);
1152
- val = totalAggregator.value();
1153
- td = document.createElement("td");
1154
- td.className = "pvtGrandTotal";
1155
- td.textContent = totalAggregator.format(val);
1156
- td.setAttribute("data-value", val);
1157
- if (getClickHandler != null) {
1158
- td.onclick = getClickHandler(val, [], []);
1159
- }
1160
- tr.appendChild(td);
1161
- }
1162
- tbody.appendChild(tr);
1163
- }
1164
- result.appendChild(tbody);
1165
- result.setAttribute("data-numrows", rowKeys.length);
1166
- result.setAttribute("data-numcols", colKeys.length);
1167
- return result;
1168
- };
1169
-
1170
- /*
1171
- Pivot Table core: create PivotData object and call Renderer on it
1172
- */
1173
- $.fn.pivot = function(input, inputOpts, locale) {
1174
- var defaults, e, localeDefaults, localeStrings, opts, pivotData, result, x;
1175
- if (locale == null) {
1176
- locale = "en";
1177
- }
1178
- if (locales[locale] == null) {
1179
- locale = "en";
1180
- }
1181
- defaults = {
1182
- cols: [],
1183
- rows: [],
1184
- vals: [],
1185
- rowOrder: "key_a_to_z",
1186
- colOrder: "key_a_to_z",
1187
- dataClass: PivotData,
1188
- filter: function() {
1189
- return true;
1190
- },
1191
- aggregator: aggregatorTemplates.count()(),
1192
- aggregatorName: "Count",
1193
- sorters: {},
1194
- derivedAttributes: {},
1195
- renderer: pivotTableRenderer
1196
- };
1197
- localeStrings = $.extend(true, {}, locales.en.localeStrings, locales[locale].localeStrings);
1198
- localeDefaults = {
1199
- rendererOptions: {
1200
- localeStrings: localeStrings
1201
- },
1202
- localeStrings: localeStrings
1203
- };
1204
- opts = $.extend(true, {}, localeDefaults, $.extend({}, defaults, inputOpts));
1205
- result = null;
1206
- try {
1207
- pivotData = new opts.dataClass(input, opts);
1208
- try {
1209
- result = opts.renderer(pivotData, opts.rendererOptions);
1210
- } catch (error) {
1211
- e = error;
1212
- if (typeof console !== "undefined" && console !== null) {
1213
- console.error(e.stack);
1214
- }
1215
- result = $("<span>").html(opts.localeStrings.renderError);
1216
- }
1217
- } catch (error) {
1218
- e = error;
1219
- if (typeof console !== "undefined" && console !== null) {
1220
- console.error(e.stack);
1221
- }
1222
- result = $("<span>").html(opts.localeStrings.computeError);
1223
- }
1224
- x = this[0];
1225
- while (x.hasChildNodes()) {
1226
- x.removeChild(x.lastChild);
1227
- }
1228
- return this.append(result);
1229
- };
1230
-
1231
- /*
1232
- Pivot Table UI: calls Pivot Table core above with options set by user
1233
- */
1234
- $.fn.pivotUI = function(input, inputOpts, overwrite, locale) {
1235
- var a, aggregator, attr, attrLength, attrValues, c, colOrderArrow, defaults, e, existingOpts, fn1, i, initialRender, l, len1, len2, len3, localeDefaults, localeStrings, materializedInput, n, o, opts, ordering, pivotTable, recordsProcessed, ref, ref1, ref2, ref3, refresh, refreshDelayed, renderer, rendererControl, rowOrderArrow, shownAttributes, shownInAggregators, shownInDragDrop, tr1, tr2, uiTable, unused, unusedAttrsVerticalAutoCutoff, unusedAttrsVerticalAutoOverride, x;
1236
- if (overwrite == null) {
1237
- overwrite = false;
1238
- }
1239
- if (locale == null) {
1240
- locale = "en";
1241
- }
1242
- if (locales[locale] == null) {
1243
- locale = "en";
1244
- }
1245
- defaults = {
1246
- derivedAttributes: {},
1247
- aggregators: locales[locale].aggregators,
1248
- renderers: locales[locale].renderers,
1249
- hiddenAttributes: [],
1250
- hiddenFromAggregators: [],
1251
- hiddenFromDragDrop: [],
1252
- menuLimit: 500,
1253
- cols: [],
1254
- rows: [],
1255
- vals: [],
1256
- rowOrder: "key_a_to_z",
1257
- colOrder: "key_a_to_z",
1258
- dataClass: PivotData,
1259
- exclusions: {},
1260
- inclusions: {},
1261
- unusedAttrsVertical: 85,
1262
- autoSortUnusedAttrs: false,
1263
- onRefresh: null,
1264
- showUI: true,
1265
- filter: function() {
1266
- return true;
1267
- },
1268
- sorters: {}
1269
- };
1270
- localeStrings = $.extend(true, {}, locales.en.localeStrings, locales[locale].localeStrings);
1271
- localeDefaults = {
1272
- rendererOptions: {
1273
- localeStrings: localeStrings
1274
- },
1275
- localeStrings: localeStrings
1276
- };
1277
- existingOpts = this.data("pivotUIOptions");
1278
- if ((existingOpts == null) || overwrite) {
1279
- opts = $.extend(true, {}, localeDefaults, $.extend({}, defaults, inputOpts));
1280
- } else {
1281
- opts = existingOpts;
1282
- }
1283
- try {
1284
- attrValues = {};
1285
- materializedInput = [];
1286
- recordsProcessed = 0;
1287
- PivotData.forEachRecord(input, opts.derivedAttributes, function(record) {
1288
- var attr, base, ref, value;
1289
- if (!opts.filter(record)) {
1290
- return;
1291
- }
1292
- materializedInput.push(record);
1293
- for (attr in record) {
1294
- if (!hasProp.call(record, attr)) continue;
1295
- if (attrValues[attr] == null) {
1296
- attrValues[attr] = {};
1297
- if (recordsProcessed > 0) {
1298
- attrValues[attr]["null"] = recordsProcessed;
1299
- }
1300
- }
1301
- }
1302
- for (attr in attrValues) {
1303
- value = (ref = record[attr]) != null ? ref : "null";
1304
- if ((base = attrValues[attr])[value] == null) {
1305
- base[value] = 0;
1306
- }
1307
- attrValues[attr][value]++;
1308
- }
1309
- return recordsProcessed++;
1310
- });
1311
- uiTable = $("<table>", {
1312
- "class": "pvtUi"
1313
- }).attr("cellpadding", 5);
1314
- rendererControl = $("<td>").addClass("pvtUiCell");
1315
- renderer = $("<select>").addClass('pvtRenderer').appendTo(rendererControl).bind("change", function() {
1316
- return refresh();
1317
- });
1318
- ref = opts.renderers;
1319
- for (x in ref) {
1320
- if (!hasProp.call(ref, x)) continue;
1321
- $("<option>").val(x).html(x).appendTo(renderer);
1322
- }
1323
- unused = $("<td>").addClass('pvtAxisContainer pvtUnused pvtUiCell');
1324
- shownAttributes = (function() {
1325
- var results;
1326
- results = [];
1327
- for (a in attrValues) {
1328
- if (indexOf.call(opts.hiddenAttributes, a) < 0) {
1329
- results.push(a);
1330
- }
1331
- }
1332
- return results;
1333
- })();
1334
- shownInAggregators = (function() {
1335
- var l, len1, results;
1336
- results = [];
1337
- for (l = 0, len1 = shownAttributes.length; l < len1; l++) {
1338
- c = shownAttributes[l];
1339
- if (indexOf.call(opts.hiddenFromAggregators, c) < 0) {
1340
- results.push(c);
1341
- }
1342
- }
1343
- return results;
1344
- })();
1345
- shownInDragDrop = (function() {
1346
- var l, len1, results;
1347
- results = [];
1348
- for (l = 0, len1 = shownAttributes.length; l < len1; l++) {
1349
- c = shownAttributes[l];
1350
- if (indexOf.call(opts.hiddenFromDragDrop, c) < 0) {
1351
- results.push(c);
1352
- }
1353
- }
1354
- return results;
1355
- })();
1356
- unusedAttrsVerticalAutoOverride = false;
1357
- if (opts.unusedAttrsVertical === "auto") {
1358
- unusedAttrsVerticalAutoCutoff = 120;
1359
- } else {
1360
- unusedAttrsVerticalAutoCutoff = parseInt(opts.unusedAttrsVertical);
1361
- }
1362
- if (!isNaN(unusedAttrsVerticalAutoCutoff)) {
1363
- attrLength = 0;
1364
- for (l = 0, len1 = shownInDragDrop.length; l < len1; l++) {
1365
- a = shownInDragDrop[l];
1366
- attrLength += a.length;
1367
- }
1368
- unusedAttrsVerticalAutoOverride = attrLength > unusedAttrsVerticalAutoCutoff;
1369
- }
1370
- if (opts.unusedAttrsVertical === true || unusedAttrsVerticalAutoOverride) {
1371
- unused.addClass('pvtVertList');
1372
- } else {
1373
- unused.addClass('pvtHorizList');
1374
- }
1375
- fn1 = function(attr) {
1376
- var attrElem, checkContainer, closeFilterBox, controls, filterItem, filterItemExcluded, finalButtons, hasExcludedItem, len2, n, placeholder, ref1, sorter, triangleLink, v, value, valueCount, valueList, values;
1377
- values = (function() {
1378
- var results;
1379
- results = [];
1380
- for (v in attrValues[attr]) {
1381
- results.push(v);
1382
- }
1383
- return results;
1384
- })();
1385
- hasExcludedItem = false;
1386
- valueList = $("<div>").addClass('pvtFilterBox').hide();
1387
- valueList.append($("<h4>").append($("<span>").text(attr), $("<span>").addClass("count").text("(" + values.length + ")")));
1388
- if (values.length > opts.menuLimit) {
1389
- valueList.append($("<p>").html(opts.localeStrings.tooMany));
1390
- } else {
1391
- if (values.length > 5) {
1392
- controls = $("<p>").appendTo(valueList);
1393
- sorter = getSort(opts.sorters, attr);
1394
- placeholder = opts.localeStrings.filterResults;
1395
- $("<input>", {
1396
- type: "text"
1397
- }).appendTo(controls).attr({
1398
- placeholder: placeholder,
1399
- "class": "pvtSearch"
1400
- }).bind("keyup", function() {
1401
- var accept, accept_gen, filter;
1402
- filter = $(this).val().toLowerCase().trim();
1403
- accept_gen = function(prefix, accepted) {
1404
- return function(v) {
1405
- var real_filter, ref1;
1406
- real_filter = filter.substring(prefix.length).trim();
1407
- if (real_filter.length === 0) {
1408
- return true;
1409
- }
1410
- return ref1 = Math.sign(sorter(v.toLowerCase(), real_filter)), indexOf.call(accepted, ref1) >= 0;
1411
- };
1412
- };
1413
- accept = filter.indexOf(">=") === 0 ? accept_gen(">=", [1, 0]) : filter.indexOf("<=") === 0 ? accept_gen("<=", [-1, 0]) : filter.indexOf(">") === 0 ? accept_gen(">", [1]) : filter.indexOf("<") === 0 ? accept_gen("<", [-1]) : filter.indexOf("~") === 0 ? function(v) {
1414
- if (filter.substring(1).trim().length === 0) {
1415
- return true;
1416
- }
1417
- return v.toLowerCase().match(filter.substring(1));
1418
- } : function(v) {
1419
- return v.toLowerCase().indexOf(filter) !== -1;
1420
- };
1421
- return valueList.find('.pvtCheckContainer p label span.value').each(function() {
1422
- if (accept($(this).text())) {
1423
- return $(this).parent().parent().show();
1424
- } else {
1425
- return $(this).parent().parent().hide();
1426
- }
1427
- });
1428
- });
1429
- controls.append($("<br>"));
1430
- $("<button>", {
1431
- type: "button"
1432
- }).appendTo(controls).html(opts.localeStrings.selectAll).bind("click", function() {
1433
- valueList.find("input:visible:not(:checked)").prop("checked", true).toggleClass("changed");
1434
- return false;
1435
- });
1436
- $("<button>", {
1437
- type: "button"
1438
- }).appendTo(controls).html(opts.localeStrings.selectNone).bind("click", function() {
1439
- valueList.find("input:visible:checked").prop("checked", false).toggleClass("changed");
1440
- return false;
1441
- });
1442
- }
1443
- checkContainer = $("<div>").addClass("pvtCheckContainer").appendTo(valueList);
1444
- ref1 = values.sort(getSort(opts.sorters, attr));
1445
- for (n = 0, len2 = ref1.length; n < len2; n++) {
1446
- value = ref1[n];
1447
- valueCount = attrValues[attr][value];
1448
- filterItem = $("<label>");
1449
- filterItemExcluded = false;
1450
- if (opts.inclusions[attr]) {
1451
- filterItemExcluded = (indexOf.call(opts.inclusions[attr], value) < 0);
1452
- } else if (opts.exclusions[attr]) {
1453
- filterItemExcluded = (indexOf.call(opts.exclusions[attr], value) >= 0);
1454
- }
1455
- hasExcludedItem || (hasExcludedItem = filterItemExcluded);
1456
- $("<input>").attr("type", "checkbox").addClass('pvtFilter').attr("checked", !filterItemExcluded).data("filter", [attr, value]).appendTo(filterItem).bind("change", function() {
1457
- return $(this).toggleClass("changed");
1458
- });
1459
- filterItem.append($("<span>").addClass("value").text(value));
1460
- filterItem.append($("<span>").addClass("count").text("(" + valueCount + ")"));
1461
- checkContainer.append($("<p>").append(filterItem));
1462
- }
1463
- }
1464
- closeFilterBox = function() {
1465
- if (valueList.find("[type='checkbox']").length > valueList.find("[type='checkbox']:checked").length) {
1466
- attrElem.addClass("pvtFilteredAttribute");
1467
- } else {
1468
- attrElem.removeClass("pvtFilteredAttribute");
1469
- }
1470
- valueList.find('.pvtSearch').val('');
1471
- valueList.find('.pvtCheckContainer p').show();
1472
- return valueList.hide();
1473
- };
1474
- finalButtons = $("<p>").appendTo(valueList);
1475
- if (values.length <= opts.menuLimit) {
1476
- $("<button>", {
1477
- type: "button"
1478
- }).text(opts.localeStrings.apply).appendTo(finalButtons).bind("click", function() {
1479
- if (valueList.find(".changed").removeClass("changed").length) {
1480
- refresh();
1481
- }
1482
- return closeFilterBox();
1483
- });
1484
- }
1485
- $("<button>", {
1486
- type: "button"
1487
- }).text(opts.localeStrings.cancel).appendTo(finalButtons).bind("click", function() {
1488
- valueList.find(".changed:checked").removeClass("changed").prop("checked", false);
1489
- valueList.find(".changed:not(:checked)").removeClass("changed").prop("checked", true);
1490
- return closeFilterBox();
1491
- });
1492
- triangleLink = $("<span>").addClass('pvtTriangle').html(" &#x25BE;").bind("click", function(e) {
1493
- var left, ref2, top;
1494
- ref2 = $(e.currentTarget).position(), left = ref2.left, top = ref2.top;
1495
- return valueList.css({
1496
- left: left + 10,
1497
- top: top + 10
1498
- }).show();
1499
- });
1500
- attrElem = $("<li>").addClass("axis_" + i).append($("<span>").addClass('pvtAttr').text(attr).data("attrName", attr).append(triangleLink));
1501
- if (hasExcludedItem) {
1502
- attrElem.addClass('pvtFilteredAttribute');
1503
- }
1504
- return unused.append(attrElem).append(valueList);
1505
- };
1506
- for (i in shownInDragDrop) {
1507
- if (!hasProp.call(shownInDragDrop, i)) continue;
1508
- attr = shownInDragDrop[i];
1509
- fn1(attr);
1510
- }
1511
- tr1 = $("<tr>").appendTo(uiTable);
1512
- aggregator = $("<select>").addClass('pvtAggregator').bind("change", function() {
1513
- return refresh();
1514
- });
1515
- ref1 = opts.aggregators;
1516
- for (x in ref1) {
1517
- if (!hasProp.call(ref1, x)) continue;
1518
- aggregator.append($("<option>").val(x).html(x));
1519
- }
1520
- ordering = {
1521
- key_a_to_z: {
1522
- rowSymbol: "&varr;",
1523
- colSymbol: "&harr;",
1524
- next: "value_a_to_z"
1525
- },
1526
- value_a_to_z: {
1527
- rowSymbol: "&darr;",
1528
- colSymbol: "&rarr;",
1529
- next: "value_z_to_a"
1530
- },
1531
- value_z_to_a: {
1532
- rowSymbol: "&uarr;",
1533
- colSymbol: "&larr;",
1534
- next: "key_a_to_z"
1535
- }
1536
- };
1537
- rowOrderArrow = $("<a>", {
1538
- role: "button"
1539
- }).addClass("pvtRowOrder").data("order", opts.rowOrder).html(ordering[opts.rowOrder].rowSymbol).bind("click", function() {
1540
- $(this).data("order", ordering[$(this).data("order")].next);
1541
- $(this).html(ordering[$(this).data("order")].rowSymbol);
1542
- return refresh();
1543
- });
1544
- colOrderArrow = $("<a>", {
1545
- role: "button"
1546
- }).addClass("pvtColOrder").data("order", opts.colOrder).html(ordering[opts.colOrder].colSymbol).bind("click", function() {
1547
- $(this).data("order", ordering[$(this).data("order")].next);
1548
- $(this).html(ordering[$(this).data("order")].colSymbol);
1549
- return refresh();
1550
- });
1551
- $("<td>").addClass('pvtVals pvtUiCell').appendTo(tr1).append(aggregator).append(rowOrderArrow).append(colOrderArrow).append($("<br>"));
1552
- $("<td>").addClass('pvtAxisContainer pvtHorizList pvtCols pvtUiCell').appendTo(tr1);
1553
- tr2 = $("<tr>").appendTo(uiTable);
1554
- tr2.append($("<td>").addClass('pvtAxisContainer pvtRows pvtUiCell').attr("valign", "top"));
1555
- pivotTable = $("<td>").attr("valign", "top").addClass('pvtRendererArea').appendTo(tr2);
1556
- if (opts.unusedAttrsVertical === true || unusedAttrsVerticalAutoOverride) {
1557
- uiTable.find('tr:nth-child(1)').prepend(rendererControl);
1558
- uiTable.find('tr:nth-child(2)').prepend(unused);
1559
- } else {
1560
- uiTable.prepend($("<tr>").append(rendererControl).append(unused));
1561
- }
1562
- this.html(uiTable);
1563
- ref2 = opts.cols;
1564
- for (n = 0, len2 = ref2.length; n < len2; n++) {
1565
- x = ref2[n];
1566
- this.find(".pvtCols").append(this.find(".axis_" + ($.inArray(x, shownInDragDrop))));
1567
- }
1568
- ref3 = opts.rows;
1569
- for (o = 0, len3 = ref3.length; o < len3; o++) {
1570
- x = ref3[o];
1571
- this.find(".pvtRows").append(this.find(".axis_" + ($.inArray(x, shownInDragDrop))));
1572
- }
1573
- if (opts.aggregatorName != null) {
1574
- this.find(".pvtAggregator").val(opts.aggregatorName);
1575
- }
1576
- if (opts.rendererName != null) {
1577
- this.find(".pvtRenderer").val(opts.rendererName);
1578
- }
1579
- if (!opts.showUI) {
1580
- this.find(".pvtUiCell").hide();
1581
- }
1582
- initialRender = true;
1583
- refreshDelayed = (function(_this) {
1584
- return function() {
1585
- var exclusions, inclusions, len4, newDropdown, numInputsToProcess, pivotUIOptions, pvtVals, ref4, ref5, subopts, t, u, unusedAttrsContainer, vals;
1586
- subopts = {
1587
- derivedAttributes: opts.derivedAttributes,
1588
- localeStrings: opts.localeStrings,
1589
- rendererOptions: opts.rendererOptions,
1590
- sorters: opts.sorters,
1591
- cols: [],
1592
- rows: [],
1593
- dataClass: opts.dataClass
1594
- };
1595
- numInputsToProcess = (ref4 = opts.aggregators[aggregator.val()]([])().numInputs) != null ? ref4 : 0;
1596
- vals = [];
1597
- _this.find(".pvtRows li span.pvtAttr").each(function() {
1598
- return subopts.rows.push($(this).data("attrName"));
1599
- });
1600
- _this.find(".pvtCols li span.pvtAttr").each(function() {
1601
- return subopts.cols.push($(this).data("attrName"));
1602
- });
1603
- _this.find(".pvtVals select.pvtAttrDropdown").each(function() {
1604
- if (numInputsToProcess === 0) {
1605
- return $(this).remove();
1606
- } else {
1607
- numInputsToProcess--;
1608
- if ($(this).val() !== "") {
1609
- return vals.push($(this).val());
1610
- }
1611
- }
1612
- });
1613
- if (numInputsToProcess !== 0) {
1614
- pvtVals = _this.find(".pvtVals");
1615
- for (x = t = 0, ref5 = numInputsToProcess; 0 <= ref5 ? t < ref5 : t > ref5; x = 0 <= ref5 ? ++t : --t) {
1616
- newDropdown = $("<select>").addClass('pvtAttrDropdown').append($("<option>")).bind("change", function() {
1617
- return refresh();
1618
- });
1619
- for (u = 0, len4 = shownInAggregators.length; u < len4; u++) {
1620
- attr = shownInAggregators[u];
1621
- newDropdown.append($("<option>").val(attr).text(attr));
1622
- }
1623
- pvtVals.append(newDropdown);
1624
- }
1625
- }
1626
- if (initialRender) {
1627
- vals = opts.vals;
1628
- i = 0;
1629
- _this.find(".pvtVals select.pvtAttrDropdown").each(function() {
1630
- $(this).val(vals[i]);
1631
- return i++;
1632
- });
1633
- initialRender = false;
1634
- }
1635
- subopts.aggregatorName = aggregator.val();
1636
- subopts.vals = vals;
1637
- subopts.aggregator = opts.aggregators[aggregator.val()](vals);
1638
- subopts.renderer = opts.renderers[renderer.val()];
1639
- subopts.rowOrder = rowOrderArrow.data("order");
1640
- subopts.colOrder = colOrderArrow.data("order");
1641
- exclusions = {};
1642
- _this.find('input.pvtFilter').not(':checked').each(function() {
1643
- var filter;
1644
- filter = $(this).data("filter");
1645
- if (exclusions[filter[0]] != null) {
1646
- return exclusions[filter[0]].push(filter[1]);
1647
- } else {
1648
- return exclusions[filter[0]] = [filter[1]];
1649
- }
1650
- });
1651
- inclusions = {};
1652
- _this.find('input.pvtFilter:checked').each(function() {
1653
- var filter;
1654
- filter = $(this).data("filter");
1655
- if (exclusions[filter[0]] != null) {
1656
- if (inclusions[filter[0]] != null) {
1657
- return inclusions[filter[0]].push(filter[1]);
1658
- } else {
1659
- return inclusions[filter[0]] = [filter[1]];
1660
- }
1661
- }
1662
- });
1663
- subopts.filter = function(record) {
1664
- var excludedItems, k, ref6, ref7;
1665
- if (!opts.filter(record)) {
1666
- return false;
1667
- }
1668
- for (k in exclusions) {
1669
- excludedItems = exclusions[k];
1670
- if (ref6 = "" + ((ref7 = record[k]) != null ? ref7 : 'null'), indexOf.call(excludedItems, ref6) >= 0) {
1671
- return false;
1672
- }
1673
- }
1674
- return true;
1675
- };
1676
- pivotTable.pivot(materializedInput, subopts);
1677
- pivotUIOptions = $.extend({}, opts, {
1678
- cols: subopts.cols,
1679
- rows: subopts.rows,
1680
- colOrder: subopts.colOrder,
1681
- rowOrder: subopts.rowOrder,
1682
- vals: vals,
1683
- exclusions: exclusions,
1684
- inclusions: inclusions,
1685
- inclusionsInfo: inclusions,
1686
- aggregatorName: aggregator.val(),
1687
- rendererName: renderer.val()
1688
- });
1689
- _this.data("pivotUIOptions", pivotUIOptions);
1690
- if (opts.autoSortUnusedAttrs) {
1691
- unusedAttrsContainer = _this.find("td.pvtUnused.pvtAxisContainer");
1692
- $(unusedAttrsContainer).children("li").sort(function(a, b) {
1693
- return naturalSort($(a).text(), $(b).text());
1694
- }).appendTo(unusedAttrsContainer);
1695
- }
1696
- pivotTable.css("opacity", 1);
1697
- if (opts.onRefresh != null) {
1698
- return opts.onRefresh(pivotUIOptions);
1699
- }
1700
- };
1701
- })(this);
1702
- refresh = (function(_this) {
1703
- return function() {
1704
- pivotTable.css("opacity", 0.5);
1705
- return setTimeout(refreshDelayed, 10);
1706
- };
1707
- })(this);
1708
- refresh();
1709
- this.find(".pvtAxisContainer").sortable({
1710
- update: function(e, ui) {
1711
- if (ui.sender == null) {
1712
- return refresh();
1713
- }
1714
- },
1715
- connectWith: this.find(".pvtAxisContainer"),
1716
- items: 'li',
1717
- placeholder: 'pvtPlaceholder'
1718
- });
1719
- } catch (error) {
1720
- e = error;
1721
- if (typeof console !== "undefined" && console !== null) {
1722
- console.error(e.stack);
1723
- }
1724
- this.html(opts.localeStrings.uiRenderError);
1725
- }
1726
- return this;
1727
- };
1728
-
1729
- /*
1730
- Heatmap post-processing
1731
- */
1732
- $.fn.heatmap = function(scope, opts) {
1733
- var colorScaleGenerator, heatmapper, i, j, l, n, numCols, numRows, ref, ref1, ref2;
1734
- if (scope == null) {
1735
- scope = "heatmap";
1736
- }
1737
- numRows = this.data("numrows");
1738
- numCols = this.data("numcols");
1739
- colorScaleGenerator = opts != null ? (ref = opts.heatmap) != null ? ref.colorScaleGenerator : void 0 : void 0;
1740
- if (colorScaleGenerator == null) {
1741
- colorScaleGenerator = function(values) {
1742
- var max, min;
1743
- min = Math.min.apply(Math, values);
1744
- max = Math.max.apply(Math, values);
1745
- return function(x) {
1746
- var nonRed;
1747
- nonRed = 255 - Math.round(255 * (x - min) / (max - min));
1748
- return "rgb(255," + nonRed + "," + nonRed + ")";
1749
- };
1750
- };
1751
- }
1752
- heatmapper = (function(_this) {
1753
- return function(scope) {
1754
- var colorScale, forEachCell, values;
1755
- forEachCell = function(f) {
1756
- return _this.find(scope).each(function() {
1757
- var x;
1758
- x = $(this).data("value");
1759
- if ((x != null) && isFinite(x)) {
1760
- return f(x, $(this));
1761
- }
1762
- });
1763
- };
1764
- values = [];
1765
- forEachCell(function(x) {
1766
- return values.push(x);
1767
- });
1768
- colorScale = colorScaleGenerator(values);
1769
- return forEachCell(function(x, elem) {
1770
- return elem.css("background-color", colorScale(x));
1771
- });
1772
- };
1773
- })(this);
1774
- switch (scope) {
1775
- case "heatmap":
1776
- heatmapper(".pvtVal");
1777
- break;
1778
- case "rowheatmap":
1779
- for (i = l = 0, ref1 = numRows; 0 <= ref1 ? l < ref1 : l > ref1; i = 0 <= ref1 ? ++l : --l) {
1780
- heatmapper(".pvtVal.row" + i);
1781
- }
1782
- break;
1783
- case "colheatmap":
1784
- for (j = n = 0, ref2 = numCols; 0 <= ref2 ? n < ref2 : n > ref2; j = 0 <= ref2 ? ++n : --n) {
1785
- heatmapper(".pvtVal.col" + j);
1786
- }
1787
- }
1788
- heatmapper(".pvtTotal.rowTotal");
1789
- heatmapper(".pvtTotal.colTotal");
1790
- return this;
1791
- };
1792
-
1793
- /*
1794
- Barchart post-processing
1795
- */
1796
- return $.fn.barchart = function(opts) {
1797
- var barcharter, i, l, numCols, numRows, ref;
1798
- numRows = this.data("numrows");
1799
- numCols = this.data("numcols");
1800
- barcharter = (function(_this) {
1801
- return function(scope) {
1802
- var forEachCell, max, min, range, scaler, values;
1803
- forEachCell = function(f) {
1804
- return _this.find(scope).each(function() {
1805
- var x;
1806
- x = $(this).data("value");
1807
- if ((x != null) && isFinite(x)) {
1808
- return f(x, $(this));
1809
- }
1810
- });
1811
- };
1812
- values = [];
1813
- forEachCell(function(x) {
1814
- return values.push(x);
1815
- });
1816
- max = Math.max.apply(Math, values);
1817
- if (max < 0) {
1818
- max = 0;
1819
- }
1820
- range = max;
1821
- min = Math.min.apply(Math, values);
1822
- if (min < 0) {
1823
- range = max - min;
1824
- }
1825
- scaler = function(x) {
1826
- return 100 * x / (1.4 * range);
1827
- };
1828
- return forEachCell(function(x, elem) {
1829
- var bBase, bgColor, text, wrapper;
1830
- text = elem.text();
1831
- wrapper = $("<div>").css({
1832
- "position": "relative",
1833
- "height": "55px"
1834
- });
1835
- bgColor = "gray";
1836
- bBase = 0;
1837
- if (min < 0) {
1838
- bBase = scaler(-min);
1839
- }
1840
- if (x < 0) {
1841
- bBase += scaler(x);
1842
- bgColor = "darkred";
1843
- x = -x;
1844
- }
1845
- wrapper.append($("<div>").css({
1846
- "position": "absolute",
1847
- "bottom": bBase + "%",
1848
- "left": 0,
1849
- "right": 0,
1850
- "height": scaler(x) + "%",
1851
- "background-color": bgColor
1852
- }));
1853
- wrapper.append($("<div>").text(text).css({
1854
- "position": "relative",
1855
- "padding-left": "5px",
1856
- "padding-right": "5px"
1857
- }));
1858
- return elem.css({
1859
- "padding": 0,
1860
- "padding-top": "5px",
1861
- "text-align": "center"
1862
- }).html(wrapper);
1863
- });
1864
- };
1865
- })(this);
1866
- for (i = l = 0, ref = numRows; 0 <= ref ? l < ref : l > ref; i = 0 <= ref ? ++l : --l) {
1867
- barcharter(".pvtVal.row" + i);
1868
- }
1869
- barcharter(".pvtTotal.colTotal");
1870
- return this;
1871
- };
1872
- };
1873
-
1874
- module.exports = initPivotTable;
1
+ // from pivottable@2.23.0
2
+ let initPivotTable = function($, window, document) {
3
+ var indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
4
+ slice = [].slice,
5
+ bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
6
+ hasProp = {}.hasOwnProperty;
7
+ /*
8
+ Utilities
9
+ */
10
+ var PivotData, addSeparators, aggregatorTemplates, aggregators, dayNamesEn, derivers, getSort, locales, mthNamesEn, naturalSort, numberFormat, pivotTableRenderer, rd, renderers, rx, rz, sortAs, usFmt, usFmtInt, usFmtPct, zeroPad, errorHandling;
11
+ addSeparators = function(nStr, thousandsSep, decimalSep) {
12
+ var rgx, x, x1, x2;
13
+ nStr += '';
14
+ x = nStr.split('.');
15
+ x1 = x[0];
16
+ x2 = x.length > 1 ? decimalSep + x[1] : '';
17
+ rgx = /(\d+)(\d{3})/;
18
+ while (rgx.test(x1)) {
19
+ x1 = x1.replace(rgx, '$1' + thousandsSep + '$2');
20
+ }
21
+ return x1 + x2;
22
+ };
23
+ let useTotalsCalculation = false;
24
+ if (document.ReportHippo && document.ReportHippo && document.ReportHippo.user) {
25
+ useTotalsCalculation = _.includes(document.ReportHippo.user.features, 'enable_server_totals_calculation');
26
+ }
27
+ numberFormat = function(opts) {
28
+ var defaults;
29
+ defaults = {
30
+ digitsAfterDecimal: 2,
31
+ scaler: 1,
32
+ thousandsSep: ",",
33
+ decimalSep: ".",
34
+ prefix: "",
35
+ suffix: ""
36
+ };
37
+ opts = $.extend({}, defaults, opts);
38
+ return function(x) {
39
+ var result;
40
+ if (isNaN(x) || !isFinite(x)) {
41
+ return "";
42
+ }
43
+ result = addSeparators((opts.scaler * x).toFixed(opts.digitsAfterDecimal), opts.thousandsSep, opts.decimalSep);
44
+ return "" + opts.prefix + result + opts.suffix;
45
+ };
46
+ };
47
+ usFmt = numberFormat();
48
+ usFmtInt = numberFormat({
49
+ digitsAfterDecimal: 0
50
+ });
51
+ usFmtPct = numberFormat({
52
+ digitsAfterDecimal: 1,
53
+ scaler: 100,
54
+ suffix: "%"
55
+ });
56
+ aggregatorTemplates = {
57
+ count: function(formatter) {
58
+ if (formatter == null) {
59
+ formatter = usFmtInt;
60
+ }
61
+ return function() {
62
+ return function(data, rowKey, colKey) {
63
+ return {
64
+ count: 0,
65
+ push: function() {
66
+ return this.count++;
67
+ },
68
+ value: function() {
69
+ return this.count;
70
+ },
71
+ format: formatter
72
+ };
73
+ };
74
+ };
75
+ },
76
+ uniques: function(fn, formatter) {
77
+ if (formatter == null) {
78
+ formatter = usFmtInt;
79
+ }
80
+ return function(arg) {
81
+ var attr;
82
+ attr = arg[0];
83
+ return function(data, rowKey, colKey) {
84
+ return {
85
+ uniq: [],
86
+ push: function(record) {
87
+ var ref;
88
+ if (ref = record[attr], indexOf.call(this.uniq, ref) < 0) {
89
+ return this.uniq.push(record[attr]);
90
+ }
91
+ },
92
+ value: function() {
93
+ return fn(this.uniq);
94
+ },
95
+ format: formatter,
96
+ numInputs: attr != null ? 0 : 1
97
+ };
98
+ };
99
+ };
100
+ },
101
+ sum: function(formatter) {
102
+ if (formatter == null) {
103
+ formatter = usFmt;
104
+ }
105
+ return function(arg) {
106
+ var attr;
107
+ attr = arg[0];
108
+ return function(data, rowKey, colKey) {
109
+ return {
110
+ sum: 0,
111
+ push: function(record) {
112
+ if (!isNaN(parseFloat(record[attr]))) {
113
+ return this.sum += parseFloat(record[attr]);
114
+ }
115
+ },
116
+ value: function() {
117
+ return this.sum;
118
+ },
119
+ format: formatter,
120
+ numInputs: attr != null ? 0 : 1
121
+ };
122
+ };
123
+ };
124
+ },
125
+ extremes: function(mode, formatter) {
126
+ if (formatter == null) {
127
+ formatter = usFmt;
128
+ }
129
+ return function(arg) {
130
+ var attr;
131
+ attr = arg[0];
132
+ return function(data, rowKey, colKey) {
133
+ return {
134
+ val: null,
135
+ sorter: getSort(data != null ? data.sorters : void 0, attr),
136
+ push: function(record) {
137
+ var ref, ref1, ref2, x;
138
+ x = record[attr];
139
+ if (mode === "min" || mode === "max") {
140
+ x = parseFloat(x);
141
+ if (!isNaN(x)) {
142
+ this.val = Math[mode](x, (ref = this.val) != null ? ref : x);
143
+ }
144
+ }
145
+ if (mode === "first") {
146
+ if (this.sorter(x, (ref1 = this.val) != null ? ref1 : x) <= 0) {
147
+ this.val = x;
148
+ }
149
+ }
150
+ if (mode === "last") {
151
+ if (this.sorter(x, (ref2 = this.val) != null ? ref2 : x) >= 0) {
152
+ return this.val = x;
153
+ }
154
+ }
155
+ },
156
+ value: function() {
157
+ return this.val;
158
+ },
159
+ format: function(x) {
160
+ if (isNaN(x)) {
161
+ return x;
162
+ } else {
163
+ return formatter(x);
164
+ }
165
+ },
166
+ numInputs: attr != null ? 0 : 1
167
+ };
168
+ };
169
+ };
170
+ },
171
+ quantile: function(q, formatter) {
172
+ if (formatter == null) {
173
+ formatter = usFmt;
174
+ }
175
+ return function(arg) {
176
+ var attr;
177
+ attr = arg[0];
178
+ return function(data, rowKey, colKey) {
179
+ return {
180
+ vals: [],
181
+ push: function(record) {
182
+ var x;
183
+ x = parseFloat(record[attr]);
184
+ if (!isNaN(x)) {
185
+ return this.vals.push(x);
186
+ }
187
+ },
188
+ value: function() {
189
+ var i;
190
+ if (this.vals.length === 0) {
191
+ return null;
192
+ }
193
+ this.vals.sort(function(a, b) {
194
+ return a - b;
195
+ });
196
+ i = (this.vals.length - 1) * q;
197
+ return (this.vals[Math.floor(i)] + this.vals[Math.ceil(i)]) / 2.0;
198
+ },
199
+ format: formatter,
200
+ numInputs: attr != null ? 0 : 1
201
+ };
202
+ };
203
+ };
204
+ },
205
+ runningStat: function(mode, ddof, formatter) {
206
+ if (mode == null) {
207
+ mode = "mean";
208
+ }
209
+ if (ddof == null) {
210
+ ddof = 1;
211
+ }
212
+ if (formatter == null) {
213
+ formatter = usFmt;
214
+ }
215
+ return function(arg) {
216
+ var attr;
217
+ attr = arg[0];
218
+ return function(data, rowKey, colKey) {
219
+ return {
220
+ n: 0.0,
221
+ m: 0.0,
222
+ s: 0.0,
223
+ push: function(record) {
224
+ var m_new, x;
225
+ x = parseFloat(record[attr]);
226
+ if (isNaN(x)) {
227
+ return;
228
+ }
229
+ this.n += 1.0;
230
+ if (this.n === 1.0) {
231
+ return this.m = x;
232
+ } else {
233
+ m_new = this.m + (x - this.m) / this.n;
234
+ this.s = this.s + (x - this.m) * (x - m_new);
235
+ return this.m = m_new;
236
+ }
237
+ },
238
+ value: function() {
239
+ if (mode === "mean") {
240
+ if (this.n === 0) {
241
+ return 0 / 0;
242
+ } else {
243
+ return this.m;
244
+ }
245
+ }
246
+ if (this.n <= ddof) {
247
+ return 0;
248
+ }
249
+ switch (mode) {
250
+ case "var":
251
+ return this.s / (this.n - ddof);
252
+ case "stdev":
253
+ return Math.sqrt(this.s / (this.n - ddof));
254
+ }
255
+ },
256
+ format: formatter,
257
+ numInputs: attr != null ? 0 : 1
258
+ };
259
+ };
260
+ };
261
+ },
262
+ sumOverSum: function(formatter) {
263
+ if (formatter == null) {
264
+ formatter = usFmt;
265
+ }
266
+ return function(arg) {
267
+ var denom, num;
268
+ num = arg[0], denom = arg[1];
269
+ return function(data, rowKey, colKey) {
270
+ return {
271
+ sumNum: 0,
272
+ sumDenom: 0,
273
+ push: function(record) {
274
+ if (!isNaN(parseFloat(record[num]))) {
275
+ this.sumNum += parseFloat(record[num]);
276
+ }
277
+ if (!isNaN(parseFloat(record[denom]))) {
278
+ return this.sumDenom += parseFloat(record[denom]);
279
+ }
280
+ },
281
+ value: function() {
282
+ return this.sumNum / this.sumDenom;
283
+ },
284
+ format: formatter,
285
+ numInputs: (num != null) && (denom != null) ? 0 : 2
286
+ };
287
+ };
288
+ };
289
+ },
290
+ sumOverSumBound80: function(upper, formatter) {
291
+ if (upper == null) {
292
+ upper = true;
293
+ }
294
+ if (formatter == null) {
295
+ formatter = usFmt;
296
+ }
297
+ return function(arg) {
298
+ var denom, num;
299
+ num = arg[0], denom = arg[1];
300
+ return function(data, rowKey, colKey) {
301
+ return {
302
+ sumNum: 0,
303
+ sumDenom: 0,
304
+ push: function(record) {
305
+ if (!isNaN(parseFloat(record[num]))) {
306
+ this.sumNum += parseFloat(record[num]);
307
+ }
308
+ if (!isNaN(parseFloat(record[denom]))) {
309
+ return this.sumDenom += parseFloat(record[denom]);
310
+ }
311
+ },
312
+ value: function() {
313
+ var sign;
314
+ sign = upper ? 1 : -1;
315
+ return (0.821187207574908 / this.sumDenom + this.sumNum / this.sumDenom + 1.2815515655446004 * sign * Math.sqrt(0.410593603787454 / (this.sumDenom * this.sumDenom) + (this.sumNum * (1 - this.sumNum / this.sumDenom)) / (this.sumDenom * this.sumDenom))) / (1 + 1.642374415149816 / this.sumDenom);
316
+ },
317
+ format: formatter,
318
+ numInputs: (num != null) && (denom != null) ? 0 : 2
319
+ };
320
+ };
321
+ };
322
+ },
323
+ fractionOf: function(wrapped, type, formatter) {
324
+ if (type == null) {
325
+ type = "total";
326
+ }
327
+ if (formatter == null) {
328
+ formatter = usFmtPct;
329
+ }
330
+ return function() {
331
+ var x;
332
+ x = 1 <= arguments.length ? slice.call(arguments, 0) : [];
333
+ return function(data, rowKey, colKey) {
334
+ return {
335
+ selector: {
336
+ total: [[], []],
337
+ row: [rowKey, []],
338
+ col: [[], colKey]
339
+ }[type],
340
+ inner: wrapped.apply(null, x)(data, rowKey, colKey),
341
+ push: function(record) {
342
+ return this.inner.push(record);
343
+ },
344
+ format: formatter,
345
+ value: function() {
346
+ return this.inner.value() / data.getAggregator.apply(data, this.selector).inner.value();
347
+ },
348
+ numInputs: wrapped.apply(null, x)().numInputs
349
+ };
350
+ };
351
+ };
352
+ }
353
+ };
354
+ aggregatorTemplates.countUnique = function(f) {
355
+ return aggregatorTemplates.uniques((function(x) {
356
+ return x.length;
357
+ }), f);
358
+ };
359
+ aggregatorTemplates.listUnique = function(s) {
360
+ return aggregatorTemplates.uniques((function(x) {
361
+ return x.sort(naturalSort).join(s);
362
+ }), (function(x) {
363
+ return x;
364
+ }));
365
+ };
366
+ aggregatorTemplates.max = function(f) {
367
+ return aggregatorTemplates.extremes('max', f);
368
+ };
369
+ aggregatorTemplates.min = function(f) {
370
+ return aggregatorTemplates.extremes('min', f);
371
+ };
372
+ aggregatorTemplates.first = function(f) {
373
+ return aggregatorTemplates.extremes('first', f);
374
+ };
375
+ aggregatorTemplates.last = function(f) {
376
+ return aggregatorTemplates.extremes('last', f);
377
+ };
378
+ aggregatorTemplates.median = function(f) {
379
+ return aggregatorTemplates.quantile(0.5, f);
380
+ };
381
+ aggregatorTemplates.average = function(f) {
382
+ return aggregatorTemplates.runningStat("mean", 1, f);
383
+ };
384
+ aggregatorTemplates["var"] = function(ddof, f) {
385
+ return aggregatorTemplates.runningStat("var", ddof, f);
386
+ };
387
+ aggregatorTemplates.stdev = function(ddof, f) {
388
+ return aggregatorTemplates.runningStat("stdev", ddof, f);
389
+ };
390
+ aggregators = (function(tpl) {
391
+ return {
392
+ "Count": tpl.count(usFmtInt),
393
+ "Count Unique Values": tpl.countUnique(usFmtInt),
394
+ "List Unique Values": tpl.listUnique(", "),
395
+ "Sum": tpl.sum(usFmt),
396
+ "Integer Sum": tpl.sum(usFmtInt),
397
+ "Average": tpl.average(usFmt),
398
+ "Median": tpl.median(usFmt),
399
+ "Sample Variance": tpl["var"](1, usFmt),
400
+ "Sample Standard Deviation": tpl.stdev(1, usFmt),
401
+ "Minimum": tpl.min(usFmt),
402
+ "Maximum": tpl.max(usFmt),
403
+ "First": tpl.first(usFmt),
404
+ "Last": tpl.last(usFmt),
405
+ "Sum over Sum": tpl.sumOverSum(usFmt),
406
+ "80% Upper Bound": tpl.sumOverSumBound80(true, usFmt),
407
+ "80% Lower Bound": tpl.sumOverSumBound80(false, usFmt),
408
+ "Sum as Fraction of Total": tpl.fractionOf(tpl.sum(), "total", usFmtPct),
409
+ "Sum as Fraction of Rows": tpl.fractionOf(tpl.sum(), "row", usFmtPct),
410
+ "Sum as Fraction of Columns": tpl.fractionOf(tpl.sum(), "col", usFmtPct),
411
+ "Count as Fraction of Total": tpl.fractionOf(tpl.count(), "total", usFmtPct),
412
+ "Count as Fraction of Rows": tpl.fractionOf(tpl.count(), "row", usFmtPct),
413
+ "Count as Fraction of Columns": tpl.fractionOf(tpl.count(), "col", usFmtPct)
414
+ };
415
+ })(aggregatorTemplates);
416
+ renderers = {
417
+ "Table": function(data, opts) {
418
+ return pivotTableRenderer(data, opts);
419
+ },
420
+ "Table Barchart": function(data, opts) {
421
+ return $(pivotTableRenderer(data, opts)).barchart();
422
+ },
423
+ "Heatmap": function(data, opts) {
424
+ return $(pivotTableRenderer(data, opts)).heatmap("heatmap", opts);
425
+ },
426
+ "Row Heatmap": function(data, opts) {
427
+ return $(pivotTableRenderer(data, opts)).heatmap("rowheatmap", opts);
428
+ },
429
+ "Col Heatmap": function(data, opts) {
430
+ return $(pivotTableRenderer(data, opts)).heatmap("colheatmap", opts);
431
+ }
432
+ };
433
+ locales = {
434
+ en: {
435
+ aggregators: aggregators,
436
+ renderers: renderers,
437
+ localeStrings: {
438
+ renderError: "An error occurred rendering the PivotTable results.",
439
+ computeError: "An error occurred computing the PivotTable results.",
440
+ uiRenderError: "An error occurred rendering the PivotTable UI.",
441
+ selectAll: "Select All",
442
+ selectNone: "Select None",
443
+ tooMany: "(too many to list)",
444
+ filterResults: "Filter values",
445
+ apply: "Apply",
446
+ cancel: "Cancel",
447
+ totals: "Totals",
448
+ vs: "vs",
449
+ by: "by"
450
+ }
451
+ }
452
+ };
453
+ mthNamesEn = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
454
+ dayNamesEn = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
455
+ zeroPad = function(number) {
456
+ return ("0" + number).substr(-2, 2);
457
+ };
458
+ derivers = {
459
+ bin: function(col, binWidth) {
460
+ return function(record) {
461
+ return record[col] - record[col] % binWidth;
462
+ };
463
+ },
464
+ dateFormat: function(col, formatString, utcOutput, mthNames, dayNames) {
465
+ var utc;
466
+ if (utcOutput == null) {
467
+ utcOutput = false;
468
+ }
469
+ if (mthNames == null) {
470
+ mthNames = mthNamesEn;
471
+ }
472
+ if (dayNames == null) {
473
+ dayNames = dayNamesEn;
474
+ }
475
+ utc = utcOutput ? "UTC" : "";
476
+ return function(record) {
477
+ var date;
478
+ date = new Date(Date.parse(record[col]));
479
+ if (isNaN(date)) {
480
+ return "";
481
+ }
482
+ return formatString.replace(/%(.)/g, function(m, p) {
483
+ switch (p) {
484
+ case "y":
485
+ return date["get" + utc + "FullYear"]();
486
+ case "m":
487
+ return zeroPad(date["get" + utc + "Month"]() + 1);
488
+ case "n":
489
+ return mthNames[date["get" + utc + "Month"]()];
490
+ case "d":
491
+ return zeroPad(date["get" + utc + "Date"]());
492
+ case "w":
493
+ return dayNames[date["get" + utc + "Day"]()];
494
+ case "x":
495
+ return date["get" + utc + "Day"]();
496
+ case "H":
497
+ return zeroPad(date["get" + utc + "Hours"]());
498
+ case "M":
499
+ return zeroPad(date["get" + utc + "Minutes"]());
500
+ case "S":
501
+ return zeroPad(date["get" + utc + "Seconds"]());
502
+ default:
503
+ return "%" + p;
504
+ }
505
+ });
506
+ };
507
+ }
508
+ };
509
+ rx = /(\d+)|(\D+)/g;
510
+ rd = /\d/;
511
+ rz = /^0/;
512
+ naturalSort = (function(_this) {
513
+ return function(as, bs) {
514
+ var a, a1, b, b1, nas, nbs;
515
+ if ((bs != null) && (as == null)) {
516
+ return -1;
517
+ }
518
+ if ((as != null) && (bs == null)) {
519
+ return 1;
520
+ }
521
+ if (typeof as === "number" && isNaN(as)) {
522
+ return -1;
523
+ }
524
+ if (typeof bs === "number" && isNaN(bs)) {
525
+ return 1;
526
+ }
527
+ nas = +as;
528
+ nbs = +bs;
529
+ if (nas < nbs) {
530
+ return -1;
531
+ }
532
+ if (nas > nbs) {
533
+ return 1;
534
+ }
535
+ if (typeof as === "number" && typeof bs !== "number") {
536
+ return -1;
537
+ }
538
+ if (typeof bs === "number" && typeof as !== "number") {
539
+ return 1;
540
+ }
541
+ if (typeof as === "number" && typeof bs === "number") {
542
+ return 0;
543
+ }
544
+ if (isNaN(nbs) && !isNaN(nas)) {
545
+ return -1;
546
+ }
547
+ if (isNaN(nas) && !isNaN(nbs)) {
548
+ return 1;
549
+ }
550
+ a = String(as).toLowerCase();
551
+ b = String(bs).toLowerCase();
552
+ if (a === b) {
553
+ return 0;
554
+ }
555
+ if (!(rd.test(a) && rd.test(b))) {
556
+ return (a > b ? 1 : -1);
557
+ }
558
+ a = a.match(rx);
559
+ b = b.match(rx);
560
+ while (a.length && b.length) {
561
+ a1 = a.shift();
562
+ b1 = b.shift();
563
+ if (a1 !== b1) {
564
+ if (rd.test(a1) && rd.test(b1)) {
565
+ return a1.replace(rz, ".0") - b1.replace(rz, ".0");
566
+ } else {
567
+ return (a1 > b1 ? 1 : -1);
568
+ }
569
+ }
570
+ }
571
+ return a.length - b.length;
572
+ };
573
+ })(this);
574
+ sortAs = function(order) {
575
+ var i, l_mapping, mapping, x;
576
+ mapping = {};
577
+ l_mapping = {};
578
+ for (i in order) {
579
+ x = order[i];
580
+ mapping[x] = i;
581
+ if (typeof x === "string") {
582
+ l_mapping[x.toLowerCase()] = i;
583
+ }
584
+ }
585
+ return function(a, b) {
586
+ if ((mapping[a] != null) && (mapping[b] != null)) {
587
+ return mapping[a] - mapping[b];
588
+ } else if (mapping[a] != null) {
589
+ return -1;
590
+ } else if (mapping[b] != null) {
591
+ return 1;
592
+ } else if ((l_mapping[a] != null) && (l_mapping[b] != null)) {
593
+ return l_mapping[a] - l_mapping[b];
594
+ } else if (l_mapping[a] != null) {
595
+ return -1;
596
+ } else if (l_mapping[b] != null) {
597
+ return 1;
598
+ } else {
599
+ return naturalSort(a, b);
600
+ }
601
+ };
602
+ };
603
+ getSort = function(sorters, attr) {
604
+ var sort;
605
+ if (sorters != null) {
606
+ if ($.isFunction(sorters)) {
607
+ sort = sorters(attr);
608
+ if ($.isFunction(sort)) {
609
+ return sort;
610
+ }
611
+ } else if (sorters[attr] != null) {
612
+ return sorters[attr];
613
+ }
614
+ }
615
+ return naturalSort;
616
+ };
617
+ errorHandling = {
618
+ placeholders: {
619
+ nodata: {
620
+ title: 'No Data Available',
621
+ text: 'This might happen because of a global filter or a change in the underlying data',
622
+ btnText: '',
623
+ class: 'nodata',
624
+ },
625
+ noPermission: {
626
+ title: 'No Permission',
627
+ text: 'You do not have permission to view the data',
628
+ btnText: 'Request Permission',
629
+ class: 'no-permission',
630
+ },
631
+ tooMuchData: {
632
+ title: 'There is too much data. Please edit this widget',
633
+ text: '',
634
+ btnText: 'Edit Widget',
635
+ class: 'too-much-data',
636
+ },
637
+ noPublishItem: {
638
+ title: 'We can’t find the published item in the source file',
639
+ text: '',
640
+ btnText: 'Go to filebox',
641
+ class: 'no-publish-item',
642
+ },
643
+ },
644
+ getErrorPlaceholder: function(placeholder) {
645
+ if (placeholder && typeof placeholder === 'object') {
646
+ return $(`
647
+ <div class="noData">
648
+ <div class="noData-title">${placeholder.title}</div>
649
+ <i class="noData-image ${placeholder.class}"></i>
650
+ <div class="noData-text">${placeholder.text}</div>
651
+ <div class="noData-error-action"></div>
652
+ </div>
653
+ `);
654
+ }
655
+ return null;
656
+ },
657
+ };
658
+
659
+ /*
660
+ Data Model class
661
+ */
662
+ PivotData = (function() {
663
+ function PivotData(input, opts) {
664
+ var ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9;
665
+ if (opts == null) {
666
+ opts = {};
667
+ }
668
+ this.getAggregator = bind(this.getAggregator, this);
669
+ this.getRowKeys = bind(this.getRowKeys, this);
670
+ this.getColKeys = bind(this.getColKeys, this);
671
+ this.sortKeys = bind(this.sortKeys, this);
672
+ this.arrSort = bind(this.arrSort, this);
673
+ this.input = input;
674
+ this.aggregator = (ref = opts.aggregator) != null ? ref : aggregatorTemplates.count()();
675
+ this.aggregatorName = (ref1 = opts.aggregatorName) != null ? ref1 : "Count";
676
+ this.colAttrs = (ref2 = opts.cols) != null ? ref2 : [];
677
+ this.rowAttrs = (ref3 = opts.rows) != null ? ref3 : [];
678
+ this.valAttrs = (ref4 = opts.vals) != null ? ref4 : [];
679
+ this.sorters = (ref5 = opts.sorters) != null ? ref5 : {};
680
+ this.rowOrder = (ref6 = opts.rowOrder) != null ? ref6 : "key_a_to_z";
681
+ this.colOrder = (ref7 = opts.colOrder) != null ? ref7 : "key_a_to_z";
682
+ this.derivedAttributes = (ref8 = opts.derivedAttributes) != null ? ref8 : {};
683
+ this.filter = (ref9 = opts.filter) != null ? ref9 : (function() {
684
+ return true;
685
+ });
686
+ this.tree = {};
687
+ this.rowKeys = [];
688
+ this.colKeys = [];
689
+ this.rowTotals = {};
690
+ this.colTotals = {};
691
+ this.allTotal = this.aggregator(this, [], []);
692
+ this.sorted = false;
693
+ PivotData.forEachRecord(this.input, this.derivedAttributes, (function(_this) {
694
+ return function(record) {
695
+ if (_this.filter(record)) {
696
+ return _this.processRecord(record, useTotalsCalculation);
697
+ }
698
+ };
699
+ })(this));
700
+ }
701
+
702
+ PivotData.forEachRecord = function(input, derivedAttributes, f) {
703
+ var addRecord, compactRecord, i, j, k, l, len1, record, ref, results, results1, tblCols;
704
+ if ($.isEmptyObject(derivedAttributes)) {
705
+ addRecord = f;
706
+ } else {
707
+ addRecord = function(record) {
708
+ var k, ref, v;
709
+ for (k in derivedAttributes) {
710
+ v = derivedAttributes[k];
711
+ record[k] = (ref = v(record)) != null ? ref : record[k];
712
+ }
713
+ return f(record);
714
+ };
715
+ }
716
+ if ($.isFunction(input)) {
717
+ return input(addRecord);
718
+ } else if ($.isArray(input)) {
719
+ if ($.isArray(input[0])) {
720
+ results = [];
721
+ for (i in input) {
722
+ if (!hasProp.call(input, i)) continue;
723
+ compactRecord = input[i];
724
+ if (!(i > 0)) {
725
+ continue;
726
+ }
727
+ record = {};
728
+ ref = input[0];
729
+ for (j in ref) {
730
+ if (!hasProp.call(ref, j)) continue;
731
+ k = ref[j];
732
+ record[k] = compactRecord[j];
733
+ }
734
+ results.push(addRecord(record));
735
+ }
736
+ return results;
737
+ } else {
738
+ results1 = [];
739
+ for (l = 0, len1 = input.length; l < len1; l++) {
740
+ record = input[l];
741
+ results1.push(addRecord(record));
742
+ }
743
+ return results1;
744
+ }
745
+ } else if (input instanceof $) {
746
+ tblCols = [];
747
+ $("thead > tr > th", input).each(function(i) {
748
+ return tblCols.push($(this).text());
749
+ });
750
+ return $("tbody > tr", input).each(function(i) {
751
+ record = {};
752
+ $("td", this).each(function(j) {
753
+ return record[tblCols[j]] = $(this).text();
754
+ });
755
+ return addRecord(record);
756
+ });
757
+ } else {
758
+ throw new Error("unknown input format");
759
+ }
760
+ };
761
+
762
+ PivotData.prototype.forEachMatchingRecord = function(criteria, callback) {
763
+ return PivotData.forEachRecord(this.input, this.derivedAttributes, (function(_this) {
764
+ return function(record) {
765
+ var k, ref, v;
766
+ if (!_this.filter(record)) {
767
+ return;
768
+ }
769
+ for (k in criteria) {
770
+ v = criteria[k];
771
+ if (v !== ((ref = record[k]) != null ? ref : "null")) {
772
+ return;
773
+ }
774
+ }
775
+ return callback(record);
776
+ };
777
+ })(this));
778
+ };
779
+
780
+ PivotData.prototype.arrSort = function(attrs) {
781
+ var a, sortersArr;
782
+ sortersArr = (function() {
783
+ var l, len1, results;
784
+ results = [];
785
+ for (l = 0, len1 = attrs.length; l < len1; l++) {
786
+ a = attrs[l];
787
+ results.push(getSort(this.sorters, a));
788
+ }
789
+ return results;
790
+ }).call(this);
791
+ return function(a, b) {
792
+ var comparison, i, sorter;
793
+ for (i in sortersArr) {
794
+ if (!hasProp.call(sortersArr, i)) continue;
795
+ sorter = sortersArr[i];
796
+ comparison = sorter(a[i], b[i]);
797
+ if (comparison !== 0) {
798
+ return comparison;
799
+ }
800
+ }
801
+ return 0;
802
+ };
803
+ };
804
+
805
+ PivotData.prototype.sortKeys = function() {
806
+ var v;
807
+ if (!this.sorted) {
808
+ this.sorted = true;
809
+ v = (function(_this) {
810
+ return function(r, c) {
811
+ return _this.getAggregator(r, c).value();
812
+ };
813
+ })(this);
814
+ switch (this.rowOrder) {
815
+ case "value_a_to_z":
816
+ this.rowKeys.sort((function(_this) {
817
+ return function(a, b) {
818
+ return naturalSort(v(a, []), v(b, []));
819
+ };
820
+ })(this));
821
+ break;
822
+ case "value_z_to_a":
823
+ this.rowKeys.sort((function(_this) {
824
+ return function(a, b) {
825
+ return -naturalSort(v(a, []), v(b, []));
826
+ };
827
+ })(this));
828
+ break;
829
+ default:
830
+ this.rowKeys.sort(this.arrSort(this.rowAttrs));
831
+ }
832
+ switch (this.colOrder) {
833
+ case "value_a_to_z":
834
+ return this.colKeys.sort((function(_this) {
835
+ return function(a, b) {
836
+ return naturalSort(v([], a), v([], b));
837
+ };
838
+ })(this));
839
+ case "value_z_to_a":
840
+ return this.colKeys.sort((function(_this) {
841
+ return function(a, b) {
842
+ return -naturalSort(v([], a), v([], b));
843
+ };
844
+ })(this));
845
+ default:
846
+ return this.colKeys.sort(this.arrSort(this.colAttrs));
847
+ }
848
+ }
849
+ };
850
+
851
+ PivotData.prototype.getColKeys = function() {
852
+ this.sortKeys();
853
+ return this.colKeys;
854
+ };
855
+
856
+ PivotData.prototype.getRowKeys = function() {
857
+ this.sortKeys();
858
+ return this.rowKeys;
859
+ };
860
+
861
+ PivotData.prototype.processRecord = function(record) {
862
+ var colKey, flatColKey, flatRowKey, l, len1, len2, n, ref, ref1, ref2, ref3, rowKey, x;
863
+ colKey = [];
864
+ rowKey = [];
865
+ ref = this.colAttrs;
866
+ for (l = 0, len1 = ref.length; l < len1; l++) {
867
+ x = ref[l];
868
+ colKey.push((ref1 = record[x]) != null ? ref1 : "null");
869
+ }
870
+ ref2 = this.rowAttrs;
871
+ for (n = 0, len2 = ref2.length; n < len2; n++) {
872
+ x = ref2[n];
873
+ rowKey.push((ref3 = record[x]) != null ? ref3 : "null");
874
+ }
875
+ flatRowKey = rowKey.join(String.fromCharCode(0));
876
+ flatColKey = colKey.join(String.fromCharCode(0));
877
+ this.allTotal.push(record);
878
+ if (rowKey.length !== 0) {
879
+ if (!this.rowTotals[flatRowKey]) {
880
+ this.rowKeys.push(rowKey);
881
+ this.rowTotals[flatRowKey] = this.aggregator(this, rowKey, []);
882
+ }
883
+ this.rowTotals[flatRowKey].push(record);
884
+ }
885
+ if (colKey.length !== 0) {
886
+ if (!this.colTotals[flatColKey]) {
887
+ this.colKeys.push(colKey);
888
+ this.colTotals[flatColKey] = this.aggregator(this, [], colKey);
889
+ }
890
+ this.colTotals[flatColKey].push(record);
891
+ }
892
+ if (colKey.length !== 0 && rowKey.length !== 0) {
893
+ if (!this.tree[flatRowKey]) {
894
+ this.tree[flatRowKey] = {};
895
+ }
896
+ if (!this.tree[flatRowKey][flatColKey]) {
897
+ this.tree[flatRowKey][flatColKey] = this.aggregator(this, rowKey, colKey);
898
+ }
899
+ return this.tree[flatRowKey][flatColKey].push(record);
900
+ }
901
+ };
902
+
903
+ PivotData.prototype.getAggregator = function(rowKey, colKey) {
904
+ var agg, flatColKey, flatRowKey;
905
+ flatRowKey = rowKey.join(String.fromCharCode(0));
906
+ flatColKey = colKey.join(String.fromCharCode(0));
907
+ if (rowKey.length === 0 && colKey.length === 0) {
908
+ agg = this.allTotal;
909
+ } else if (rowKey.length === 0) {
910
+ agg = this.colTotals[flatColKey];
911
+ } else if (colKey.length === 0) {
912
+ agg = this.rowTotals[flatRowKey];
913
+ } else {
914
+ agg = this.tree[flatRowKey][flatColKey];
915
+ }
916
+ return agg != null ? agg : {
917
+ value: (function() {
918
+ return null;
919
+ }),
920
+ format: function() {
921
+ return "";
922
+ }
923
+ };
924
+ };
925
+
926
+ return PivotData;
927
+
928
+ })();
929
+
930
+ $.pivotUtilities = {
931
+ aggregatorTemplates: aggregatorTemplates,
932
+ aggregators: aggregators,
933
+ renderers: renderers,
934
+ derivers: derivers,
935
+ locales: locales,
936
+ naturalSort: naturalSort,
937
+ numberFormat: numberFormat,
938
+ sortAs: sortAs,
939
+ PivotData: PivotData,
940
+ errorHandling: errorHandling,
941
+ };
942
+ if (window.$) {
943
+ window.$.pivotUtilities = $.pivotUtilities
944
+ }
945
+
946
+ /*
947
+ Default Renderer for hierarchical table layout
948
+ */
949
+ pivotTableRenderer = function(pivotData, opts) {
950
+ var aggregator, c, colAttrs, colKey, colKeys, defaults, getClickHandler, i, j, r, result, rowAttrs, rowKey, rowKeys, spanSize, tbody, td, th, thead, totalAggregator, tr, txt, val, x;
951
+ defaults = {
952
+ table: {
953
+ clickCallback: null,
954
+ rowTotals: true,
955
+ colTotals: true
956
+ },
957
+ localeStrings: {
958
+ totals: "Totals"
959
+ }
960
+ };
961
+ opts = $.extend(true, {}, defaults, opts);
962
+ colAttrs = pivotData.colAttrs;
963
+ rowAttrs = pivotData.rowAttrs;
964
+ rowKeys = pivotData.getRowKeys();
965
+ colKeys = pivotData.getColKeys();
966
+ if (opts.table.clickCallback) {
967
+ getClickHandler = function(value, rowValues, colValues) {
968
+ var attr, filters, i;
969
+ filters = {};
970
+ for (i in colAttrs) {
971
+ if (!hasProp.call(colAttrs, i)) continue;
972
+ attr = colAttrs[i];
973
+ if (colValues[i] != null) {
974
+ filters[attr] = colValues[i];
975
+ }
976
+ }
977
+ for (i in rowAttrs) {
978
+ if (!hasProp.call(rowAttrs, i)) continue;
979
+ attr = rowAttrs[i];
980
+ if (rowValues[i] != null) {
981
+ filters[attr] = rowValues[i];
982
+ }
983
+ }
984
+ return function(e) {
985
+ return opts.table.clickCallback(e, value, filters, pivotData);
986
+ };
987
+ };
988
+ }
989
+ result = document.createElement("table");
990
+ result.className = "pvtTable";
991
+ spanSize = function(arr, i, j) {
992
+ var l, len, n, noDraw, ref, ref1, stop, x;
993
+ if (i !== 0) {
994
+ noDraw = true;
995
+ for (x = l = 0, ref = j; 0 <= ref ? l <= ref : l >= ref; x = 0 <= ref ? ++l : --l) {
996
+ if (arr[i - 1][x] !== arr[i][x]) {
997
+ noDraw = false;
998
+ }
999
+ }
1000
+ if (noDraw) {
1001
+ return -1;
1002
+ }
1003
+ }
1004
+ len = 0;
1005
+ while (i + len < arr.length) {
1006
+ stop = false;
1007
+ for (x = n = 0, ref1 = j; 0 <= ref1 ? n <= ref1 : n >= ref1; x = 0 <= ref1 ? ++n : --n) {
1008
+ if (arr[i][x] !== arr[i + len][x]) {
1009
+ stop = true;
1010
+ }
1011
+ }
1012
+ if (stop) {
1013
+ break;
1014
+ }
1015
+ len++;
1016
+ }
1017
+ return len;
1018
+ };
1019
+ thead = document.createElement("thead");
1020
+ for (j in colAttrs) {
1021
+ if (!hasProp.call(colAttrs, j)) continue;
1022
+ c = colAttrs[j];
1023
+ tr = document.createElement("tr");
1024
+ if (parseInt(j) === 0 && rowAttrs.length !== 0) {
1025
+ th = document.createElement("th");
1026
+ th.setAttribute("colspan", rowAttrs.length);
1027
+ th.setAttribute("rowspan", colAttrs.length);
1028
+ tr.appendChild(th);
1029
+ }
1030
+ th = document.createElement("th");
1031
+ th.className = "pvtAxisLabel";
1032
+ th.textContent = c;
1033
+ tr.appendChild(th);
1034
+ for (i in colKeys) {
1035
+ if (!hasProp.call(colKeys, i)) continue;
1036
+ colKey = colKeys[i];
1037
+ x = spanSize(colKeys, parseInt(i), parseInt(j));
1038
+ if (x !== -1) {
1039
+ th = document.createElement("th");
1040
+ th.className = "pvtColLabel";
1041
+ th.textContent = colKey[j];
1042
+ th.setAttribute("colspan", x);
1043
+ if (parseInt(j) === colAttrs.length - 1 && rowAttrs.length !== 0) {
1044
+ th.setAttribute("rowspan", 2);
1045
+ }
1046
+ tr.appendChild(th);
1047
+ }
1048
+ }
1049
+ if (parseInt(j) === 0 && opts.table.rowTotals) {
1050
+ th = document.createElement("th");
1051
+ th.className = "pvtTotalLabel pvtRowTotalLabel";
1052
+ th.innerHTML = opts.localeStrings.totals;
1053
+ th.setAttribute("rowspan", colAttrs.length + (rowAttrs.length === 0 ? 0 : 1));
1054
+ tr.appendChild(th);
1055
+ }
1056
+ thead.appendChild(tr);
1057
+ }
1058
+ if (rowAttrs.length !== 0) {
1059
+ tr = document.createElement("tr");
1060
+ for (i in rowAttrs) {
1061
+ if (!hasProp.call(rowAttrs, i)) continue;
1062
+ r = rowAttrs[i];
1063
+ th = document.createElement("th");
1064
+ th.className = "pvtAxisLabel";
1065
+ th.textContent = r;
1066
+ tr.appendChild(th);
1067
+ }
1068
+ th = document.createElement("th");
1069
+ if (colAttrs.length === 0) {
1070
+ th.className = "pvtTotalLabel pvtRowTotalLabel";
1071
+ th.innerHTML = opts.localeStrings.totals;
1072
+ }
1073
+ tr.appendChild(th);
1074
+ thead.appendChild(tr);
1075
+ }
1076
+ result.appendChild(thead);
1077
+ tbody = document.createElement("tbody");
1078
+ for (i in rowKeys) {
1079
+ if (!hasProp.call(rowKeys, i)) continue;
1080
+ rowKey = rowKeys[i];
1081
+ tr = document.createElement("tr");
1082
+ for (j in rowKey) {
1083
+ if (!hasProp.call(rowKey, j)) continue;
1084
+ txt = rowKey[j];
1085
+ x = spanSize(rowKeys, parseInt(i), parseInt(j));
1086
+ if (x !== -1) {
1087
+ th = document.createElement("th");
1088
+ th.className = "pvtRowLabel";
1089
+ th.textContent = txt;
1090
+ th.setAttribute("rowspan", x);
1091
+ if (parseInt(j) === rowAttrs.length - 1 && colAttrs.length !== 0) {
1092
+ th.setAttribute("colspan", 2);
1093
+ }
1094
+ tr.appendChild(th);
1095
+ }
1096
+ }
1097
+ for (j in colKeys) {
1098
+ if (!hasProp.call(colKeys, j)) continue;
1099
+ colKey = colKeys[j];
1100
+ aggregator = pivotData.getAggregator(rowKey, colKey);
1101
+ val = aggregator.value();
1102
+ td = document.createElement("td");
1103
+ td.className = "pvtVal row" + i + " col" + j;
1104
+ td.textContent = aggregator.format(val);
1105
+ td.setAttribute("data-value", val);
1106
+ if (getClickHandler != null) {
1107
+ td.onclick = getClickHandler(val, rowKey, colKey);
1108
+ }
1109
+ tr.appendChild(td);
1110
+ }
1111
+ if (opts.table.rowTotals || colAttrs.length === 0) {
1112
+ totalAggregator = pivotData.getAggregator(rowKey, []);
1113
+ val = totalAggregator.value();
1114
+ td = document.createElement("td");
1115
+ td.className = "pvtTotal rowTotal";
1116
+ td.textContent = totalAggregator.format(val);
1117
+ td.setAttribute("data-value", val);
1118
+ if (getClickHandler != null) {
1119
+ td.onclick = getClickHandler(val, rowKey, []);
1120
+ }
1121
+ td.setAttribute("data-for", "row" + i);
1122
+ tr.appendChild(td);
1123
+ }
1124
+ tbody.appendChild(tr);
1125
+ }
1126
+ if (opts.table.colTotals || rowAttrs.length === 0) {
1127
+ tr = document.createElement("tr");
1128
+ if (opts.table.colTotals || rowAttrs.length === 0) {
1129
+ th = document.createElement("th");
1130
+ th.className = "pvtTotalLabel pvtColTotalLabel";
1131
+ th.innerHTML = opts.localeStrings.totals;
1132
+ th.setAttribute("colspan", rowAttrs.length + (colAttrs.length === 0 ? 0 : 1));
1133
+ tr.appendChild(th);
1134
+ }
1135
+ for (j in colKeys) {
1136
+ if (!hasProp.call(colKeys, j)) continue;
1137
+ colKey = colKeys[j];
1138
+ totalAggregator = pivotData.getAggregator([], colKey);
1139
+ val = totalAggregator.value();
1140
+ td = document.createElement("td");
1141
+ td.className = "pvtTotal colTotal";
1142
+ td.textContent = totalAggregator.format(val);
1143
+ td.setAttribute("data-value", val);
1144
+ if (getClickHandler != null) {
1145
+ td.onclick = getClickHandler(val, [], colKey);
1146
+ }
1147
+ td.setAttribute("data-for", "col" + j);
1148
+ tr.appendChild(td);
1149
+ }
1150
+ if (opts.table.rowTotals || colAttrs.length === 0) {
1151
+ totalAggregator = pivotData.getAggregator([], []);
1152
+ val = totalAggregator.value();
1153
+ td = document.createElement("td");
1154
+ td.className = "pvtGrandTotal";
1155
+ td.textContent = totalAggregator.format(val);
1156
+ td.setAttribute("data-value", val);
1157
+ if (getClickHandler != null) {
1158
+ td.onclick = getClickHandler(val, [], []);
1159
+ }
1160
+ tr.appendChild(td);
1161
+ }
1162
+ tbody.appendChild(tr);
1163
+ }
1164
+ result.appendChild(tbody);
1165
+ result.setAttribute("data-numrows", rowKeys.length);
1166
+ result.setAttribute("data-numcols", colKeys.length);
1167
+ return result;
1168
+ };
1169
+
1170
+ /*
1171
+ Pivot Table core: create PivotData object and call Renderer on it
1172
+ */
1173
+ $.fn.pivot = function(input, inputOpts, locale) {
1174
+ var defaults, e, localeDefaults, localeStrings, opts, pivotData, result, x;
1175
+ if (locale == null) {
1176
+ locale = "en";
1177
+ }
1178
+ if (locales[locale] == null) {
1179
+ locale = "en";
1180
+ }
1181
+ defaults = {
1182
+ cols: [],
1183
+ rows: [],
1184
+ vals: [],
1185
+ rowOrder: "key_a_to_z",
1186
+ colOrder: "key_a_to_z",
1187
+ dataClass: PivotData,
1188
+ filter: function() {
1189
+ return true;
1190
+ },
1191
+ aggregator: aggregatorTemplates.count()(),
1192
+ aggregatorName: "Count",
1193
+ sorters: {},
1194
+ derivedAttributes: {},
1195
+ renderer: pivotTableRenderer
1196
+ };
1197
+ localeStrings = $.extend(true, {}, locales.en.localeStrings, locales[locale].localeStrings);
1198
+ localeDefaults = {
1199
+ rendererOptions: {
1200
+ localeStrings: localeStrings
1201
+ },
1202
+ localeStrings: localeStrings
1203
+ };
1204
+ opts = $.extend(true, {}, localeDefaults, $.extend({}, defaults, inputOpts));
1205
+ result = null;
1206
+ try {
1207
+ pivotData = new opts.dataClass(input, opts);
1208
+ try {
1209
+ result = opts.renderer(pivotData, opts.rendererOptions);
1210
+ } catch (error) {
1211
+ e = error;
1212
+ if (typeof console !== "undefined" && console !== null) {
1213
+ console.error(e.stack);
1214
+ }
1215
+ result = $("<span>").html(opts.localeStrings.renderError);
1216
+ }
1217
+ } catch (error) {
1218
+ e = error;
1219
+ if (typeof console !== "undefined" && console !== null) {
1220
+ console.error(e.stack);
1221
+ }
1222
+ result = $("<span>").html(opts.localeStrings.computeError);
1223
+ }
1224
+ x = this[0];
1225
+ while (x.hasChildNodes()) {
1226
+ x.removeChild(x.lastChild);
1227
+ }
1228
+ return this.append(result);
1229
+ };
1230
+
1231
+ /*
1232
+ Pivot Table UI: calls Pivot Table core above with options set by user
1233
+ */
1234
+ $.fn.pivotUI = function(input, inputOpts, overwrite, locale) {
1235
+ var a, aggregator, attr, attrLength, attrValues, c, colOrderArrow, defaults, e, existingOpts, fn1, i, initialRender, l, len1, len2, len3, localeDefaults, localeStrings, materializedInput, n, o, opts, ordering, pivotTable, recordsProcessed, ref, ref1, ref2, ref3, refresh, refreshDelayed, renderer, rendererControl, rowOrderArrow, shownAttributes, shownInAggregators, shownInDragDrop, tr1, tr2, uiTable, unused, unusedAttrsVerticalAutoCutoff, unusedAttrsVerticalAutoOverride, x;
1236
+ if (overwrite == null) {
1237
+ overwrite = false;
1238
+ }
1239
+ if (locale == null) {
1240
+ locale = "en";
1241
+ }
1242
+ if (locales[locale] == null) {
1243
+ locale = "en";
1244
+ }
1245
+ defaults = {
1246
+ derivedAttributes: {},
1247
+ aggregators: locales[locale].aggregators,
1248
+ renderers: locales[locale].renderers,
1249
+ hiddenAttributes: [],
1250
+ hiddenFromAggregators: [],
1251
+ hiddenFromDragDrop: [],
1252
+ menuLimit: 500,
1253
+ cols: [],
1254
+ rows: [],
1255
+ vals: [],
1256
+ rowOrder: "key_a_to_z",
1257
+ colOrder: "key_a_to_z",
1258
+ dataClass: PivotData,
1259
+ exclusions: {},
1260
+ inclusions: {},
1261
+ unusedAttrsVertical: 85,
1262
+ autoSortUnusedAttrs: false,
1263
+ onRefresh: null,
1264
+ showUI: true,
1265
+ filter: function() {
1266
+ return true;
1267
+ },
1268
+ sorters: {}
1269
+ };
1270
+ localeStrings = $.extend(true, {}, locales.en.localeStrings, locales[locale].localeStrings);
1271
+ localeDefaults = {
1272
+ rendererOptions: {
1273
+ localeStrings: localeStrings
1274
+ },
1275
+ localeStrings: localeStrings
1276
+ };
1277
+ existingOpts = this.data("pivotUIOptions");
1278
+ if ((existingOpts == null) || overwrite) {
1279
+ opts = $.extend(true, {}, localeDefaults, $.extend({}, defaults, inputOpts));
1280
+ } else {
1281
+ opts = existingOpts;
1282
+ }
1283
+ try {
1284
+ attrValues = {};
1285
+ materializedInput = [];
1286
+ recordsProcessed = 0;
1287
+ PivotData.forEachRecord(input, opts.derivedAttributes, function(record) {
1288
+ var attr, base, ref, value;
1289
+ if (!opts.filter(record)) {
1290
+ return;
1291
+ }
1292
+ materializedInput.push(record);
1293
+ for (attr in record) {
1294
+ if (!hasProp.call(record, attr)) continue;
1295
+ if (attrValues[attr] == null) {
1296
+ attrValues[attr] = {};
1297
+ if (recordsProcessed > 0) {
1298
+ attrValues[attr]["null"] = recordsProcessed;
1299
+ }
1300
+ }
1301
+ }
1302
+ for (attr in attrValues) {
1303
+ value = (ref = record[attr]) != null ? ref : "null";
1304
+ if ((base = attrValues[attr])[value] == null) {
1305
+ base[value] = 0;
1306
+ }
1307
+ attrValues[attr][value]++;
1308
+ }
1309
+ return recordsProcessed++;
1310
+ });
1311
+ uiTable = $("<table>", {
1312
+ "class": "pvtUi"
1313
+ }).attr("cellpadding", 5);
1314
+ rendererControl = $("<td>").addClass("pvtUiCell");
1315
+ renderer = $("<select>").addClass('pvtRenderer').appendTo(rendererControl).bind("change", function() {
1316
+ return refresh();
1317
+ });
1318
+ ref = opts.renderers;
1319
+ for (x in ref) {
1320
+ if (!hasProp.call(ref, x)) continue;
1321
+ $("<option>").val(x).html(x).appendTo(renderer);
1322
+ }
1323
+ unused = $("<td>").addClass('pvtAxisContainer pvtUnused pvtUiCell');
1324
+ shownAttributes = (function() {
1325
+ var results;
1326
+ results = [];
1327
+ for (a in attrValues) {
1328
+ if (indexOf.call(opts.hiddenAttributes, a) < 0) {
1329
+ results.push(a);
1330
+ }
1331
+ }
1332
+ return results;
1333
+ })();
1334
+ shownInAggregators = (function() {
1335
+ var l, len1, results;
1336
+ results = [];
1337
+ for (l = 0, len1 = shownAttributes.length; l < len1; l++) {
1338
+ c = shownAttributes[l];
1339
+ if (indexOf.call(opts.hiddenFromAggregators, c) < 0) {
1340
+ results.push(c);
1341
+ }
1342
+ }
1343
+ return results;
1344
+ })();
1345
+ shownInDragDrop = (function() {
1346
+ var l, len1, results;
1347
+ results = [];
1348
+ for (l = 0, len1 = shownAttributes.length; l < len1; l++) {
1349
+ c = shownAttributes[l];
1350
+ if (indexOf.call(opts.hiddenFromDragDrop, c) < 0) {
1351
+ results.push(c);
1352
+ }
1353
+ }
1354
+ return results;
1355
+ })();
1356
+ unusedAttrsVerticalAutoOverride = false;
1357
+ if (opts.unusedAttrsVertical === "auto") {
1358
+ unusedAttrsVerticalAutoCutoff = 120;
1359
+ } else {
1360
+ unusedAttrsVerticalAutoCutoff = parseInt(opts.unusedAttrsVertical);
1361
+ }
1362
+ if (!isNaN(unusedAttrsVerticalAutoCutoff)) {
1363
+ attrLength = 0;
1364
+ for (l = 0, len1 = shownInDragDrop.length; l < len1; l++) {
1365
+ a = shownInDragDrop[l];
1366
+ attrLength += a.length;
1367
+ }
1368
+ unusedAttrsVerticalAutoOverride = attrLength > unusedAttrsVerticalAutoCutoff;
1369
+ }
1370
+ if (opts.unusedAttrsVertical === true || unusedAttrsVerticalAutoOverride) {
1371
+ unused.addClass('pvtVertList');
1372
+ } else {
1373
+ unused.addClass('pvtHorizList');
1374
+ }
1375
+ fn1 = function(attr) {
1376
+ var attrElem, checkContainer, closeFilterBox, controls, filterItem, filterItemExcluded, finalButtons, hasExcludedItem, len2, n, placeholder, ref1, sorter, triangleLink, v, value, valueCount, valueList, values;
1377
+ values = (function() {
1378
+ var results;
1379
+ results = [];
1380
+ for (v in attrValues[attr]) {
1381
+ results.push(v);
1382
+ }
1383
+ return results;
1384
+ })();
1385
+ hasExcludedItem = false;
1386
+ valueList = $("<div>").addClass('pvtFilterBox').hide();
1387
+ valueList.append($("<h4>").append($("<span>").text(attr), $("<span>").addClass("count").text("(" + values.length + ")")));
1388
+ if (values.length > opts.menuLimit) {
1389
+ valueList.append($("<p>").html(opts.localeStrings.tooMany));
1390
+ } else {
1391
+ if (values.length > 5) {
1392
+ controls = $("<p>").appendTo(valueList);
1393
+ sorter = getSort(opts.sorters, attr);
1394
+ placeholder = opts.localeStrings.filterResults;
1395
+ $("<input>", {
1396
+ type: "text"
1397
+ }).appendTo(controls).attr({
1398
+ placeholder: placeholder,
1399
+ "class": "pvtSearch"
1400
+ }).bind("keyup", function() {
1401
+ var accept, accept_gen, filter;
1402
+ filter = $(this).val().toLowerCase().trim();
1403
+ accept_gen = function(prefix, accepted) {
1404
+ return function(v) {
1405
+ var real_filter, ref1;
1406
+ real_filter = filter.substring(prefix.length).trim();
1407
+ if (real_filter.length === 0) {
1408
+ return true;
1409
+ }
1410
+ return ref1 = Math.sign(sorter(v.toLowerCase(), real_filter)), indexOf.call(accepted, ref1) >= 0;
1411
+ };
1412
+ };
1413
+ accept = filter.indexOf(">=") === 0 ? accept_gen(">=", [1, 0]) : filter.indexOf("<=") === 0 ? accept_gen("<=", [-1, 0]) : filter.indexOf(">") === 0 ? accept_gen(">", [1]) : filter.indexOf("<") === 0 ? accept_gen("<", [-1]) : filter.indexOf("~") === 0 ? function(v) {
1414
+ if (filter.substring(1).trim().length === 0) {
1415
+ return true;
1416
+ }
1417
+ return v.toLowerCase().match(filter.substring(1));
1418
+ } : function(v) {
1419
+ return v.toLowerCase().indexOf(filter) !== -1;
1420
+ };
1421
+ return valueList.find('.pvtCheckContainer p label span.value').each(function() {
1422
+ if (accept($(this).text())) {
1423
+ return $(this).parent().parent().show();
1424
+ } else {
1425
+ return $(this).parent().parent().hide();
1426
+ }
1427
+ });
1428
+ });
1429
+ controls.append($("<br>"));
1430
+ $("<button>", {
1431
+ type: "button"
1432
+ }).appendTo(controls).html(opts.localeStrings.selectAll).bind("click", function() {
1433
+ valueList.find("input:visible:not(:checked)").prop("checked", true).toggleClass("changed");
1434
+ return false;
1435
+ });
1436
+ $("<button>", {
1437
+ type: "button"
1438
+ }).appendTo(controls).html(opts.localeStrings.selectNone).bind("click", function() {
1439
+ valueList.find("input:visible:checked").prop("checked", false).toggleClass("changed");
1440
+ return false;
1441
+ });
1442
+ }
1443
+ checkContainer = $("<div>").addClass("pvtCheckContainer").appendTo(valueList);
1444
+ ref1 = values.sort(getSort(opts.sorters, attr));
1445
+ for (n = 0, len2 = ref1.length; n < len2; n++) {
1446
+ value = ref1[n];
1447
+ valueCount = attrValues[attr][value];
1448
+ filterItem = $("<label>");
1449
+ filterItemExcluded = false;
1450
+ if (opts.inclusions[attr]) {
1451
+ filterItemExcluded = (indexOf.call(opts.inclusions[attr], value) < 0);
1452
+ } else if (opts.exclusions[attr]) {
1453
+ filterItemExcluded = (indexOf.call(opts.exclusions[attr], value) >= 0);
1454
+ }
1455
+ hasExcludedItem || (hasExcludedItem = filterItemExcluded);
1456
+ $("<input>").attr("type", "checkbox").addClass('pvtFilter').attr("checked", !filterItemExcluded).data("filter", [attr, value]).appendTo(filterItem).bind("change", function() {
1457
+ return $(this).toggleClass("changed");
1458
+ });
1459
+ filterItem.append($("<span>").addClass("value").text(value));
1460
+ filterItem.append($("<span>").addClass("count").text("(" + valueCount + ")"));
1461
+ checkContainer.append($("<p>").append(filterItem));
1462
+ }
1463
+ }
1464
+ closeFilterBox = function() {
1465
+ if (valueList.find("[type='checkbox']").length > valueList.find("[type='checkbox']:checked").length) {
1466
+ attrElem.addClass("pvtFilteredAttribute");
1467
+ } else {
1468
+ attrElem.removeClass("pvtFilteredAttribute");
1469
+ }
1470
+ valueList.find('.pvtSearch').val('');
1471
+ valueList.find('.pvtCheckContainer p').show();
1472
+ return valueList.hide();
1473
+ };
1474
+ finalButtons = $("<p>").appendTo(valueList);
1475
+ if (values.length <= opts.menuLimit) {
1476
+ $("<button>", {
1477
+ type: "button"
1478
+ }).text(opts.localeStrings.apply).appendTo(finalButtons).bind("click", function() {
1479
+ if (valueList.find(".changed").removeClass("changed").length) {
1480
+ refresh();
1481
+ }
1482
+ return closeFilterBox();
1483
+ });
1484
+ }
1485
+ $("<button>", {
1486
+ type: "button"
1487
+ }).text(opts.localeStrings.cancel).appendTo(finalButtons).bind("click", function() {
1488
+ valueList.find(".changed:checked").removeClass("changed").prop("checked", false);
1489
+ valueList.find(".changed:not(:checked)").removeClass("changed").prop("checked", true);
1490
+ return closeFilterBox();
1491
+ });
1492
+ triangleLink = $("<span>").addClass('pvtTriangle').html(" &#x25BE;").bind("click", function(e) {
1493
+ var left, ref2, top;
1494
+ ref2 = $(e.currentTarget).position(), left = ref2.left, top = ref2.top;
1495
+ return valueList.css({
1496
+ left: left + 10,
1497
+ top: top + 10
1498
+ }).show();
1499
+ });
1500
+ attrElem = $("<li>").addClass("axis_" + i).append($("<span>").addClass('pvtAttr').text(attr).data("attrName", attr).append(triangleLink));
1501
+ if (hasExcludedItem) {
1502
+ attrElem.addClass('pvtFilteredAttribute');
1503
+ }
1504
+ return unused.append(attrElem).append(valueList);
1505
+ };
1506
+ for (i in shownInDragDrop) {
1507
+ if (!hasProp.call(shownInDragDrop, i)) continue;
1508
+ attr = shownInDragDrop[i];
1509
+ fn1(attr);
1510
+ }
1511
+ tr1 = $("<tr>").appendTo(uiTable);
1512
+ aggregator = $("<select>").addClass('pvtAggregator').bind("change", function() {
1513
+ return refresh();
1514
+ });
1515
+ ref1 = opts.aggregators;
1516
+ for (x in ref1) {
1517
+ if (!hasProp.call(ref1, x)) continue;
1518
+ aggregator.append($("<option>").val(x).html(x));
1519
+ }
1520
+ ordering = {
1521
+ key_a_to_z: {
1522
+ rowSymbol: "&varr;",
1523
+ colSymbol: "&harr;",
1524
+ next: "value_a_to_z"
1525
+ },
1526
+ value_a_to_z: {
1527
+ rowSymbol: "&darr;",
1528
+ colSymbol: "&rarr;",
1529
+ next: "value_z_to_a"
1530
+ },
1531
+ value_z_to_a: {
1532
+ rowSymbol: "&uarr;",
1533
+ colSymbol: "&larr;",
1534
+ next: "key_a_to_z"
1535
+ }
1536
+ };
1537
+ rowOrderArrow = $("<a>", {
1538
+ role: "button"
1539
+ }).addClass("pvtRowOrder").data("order", opts.rowOrder).html(ordering[opts.rowOrder].rowSymbol).bind("click", function() {
1540
+ $(this).data("order", ordering[$(this).data("order")].next);
1541
+ $(this).html(ordering[$(this).data("order")].rowSymbol);
1542
+ return refresh();
1543
+ });
1544
+ colOrderArrow = $("<a>", {
1545
+ role: "button"
1546
+ }).addClass("pvtColOrder").data("order", opts.colOrder).html(ordering[opts.colOrder].colSymbol).bind("click", function() {
1547
+ $(this).data("order", ordering[$(this).data("order")].next);
1548
+ $(this).html(ordering[$(this).data("order")].colSymbol);
1549
+ return refresh();
1550
+ });
1551
+ $("<td>").addClass('pvtVals pvtUiCell').appendTo(tr1).append(aggregator).append(rowOrderArrow).append(colOrderArrow).append($("<br>"));
1552
+ $("<td>").addClass('pvtAxisContainer pvtHorizList pvtCols pvtUiCell').appendTo(tr1);
1553
+ tr2 = $("<tr>").appendTo(uiTable);
1554
+ tr2.append($("<td>").addClass('pvtAxisContainer pvtRows pvtUiCell').attr("valign", "top"));
1555
+ pivotTable = $("<td>").attr("valign", "top").addClass('pvtRendererArea').appendTo(tr2);
1556
+ if (opts.unusedAttrsVertical === true || unusedAttrsVerticalAutoOverride) {
1557
+ uiTable.find('tr:nth-child(1)').prepend(rendererControl);
1558
+ uiTable.find('tr:nth-child(2)').prepend(unused);
1559
+ } else {
1560
+ uiTable.prepend($("<tr>").append(rendererControl).append(unused));
1561
+ }
1562
+ this.html(uiTable);
1563
+ ref2 = opts.cols;
1564
+ for (n = 0, len2 = ref2.length; n < len2; n++) {
1565
+ x = ref2[n];
1566
+ this.find(".pvtCols").append(this.find(".axis_" + ($.inArray(x, shownInDragDrop))));
1567
+ }
1568
+ ref3 = opts.rows;
1569
+ for (o = 0, len3 = ref3.length; o < len3; o++) {
1570
+ x = ref3[o];
1571
+ this.find(".pvtRows").append(this.find(".axis_" + ($.inArray(x, shownInDragDrop))));
1572
+ }
1573
+ if (opts.aggregatorName != null) {
1574
+ this.find(".pvtAggregator").val(opts.aggregatorName);
1575
+ }
1576
+ if (opts.rendererName != null) {
1577
+ this.find(".pvtRenderer").val(opts.rendererName);
1578
+ }
1579
+ if (!opts.showUI) {
1580
+ this.find(".pvtUiCell").hide();
1581
+ }
1582
+ initialRender = true;
1583
+ refreshDelayed = (function(_this) {
1584
+ return function() {
1585
+ var exclusions, inclusions, len4, newDropdown, numInputsToProcess, pivotUIOptions, pvtVals, ref4, ref5, subopts, t, u, unusedAttrsContainer, vals;
1586
+ subopts = {
1587
+ derivedAttributes: opts.derivedAttributes,
1588
+ localeStrings: opts.localeStrings,
1589
+ rendererOptions: opts.rendererOptions,
1590
+ sorters: opts.sorters,
1591
+ cols: [],
1592
+ rows: [],
1593
+ dataClass: opts.dataClass
1594
+ };
1595
+ numInputsToProcess = (ref4 = opts.aggregators[aggregator.val()]([])().numInputs) != null ? ref4 : 0;
1596
+ vals = [];
1597
+ _this.find(".pvtRows li span.pvtAttr").each(function() {
1598
+ return subopts.rows.push($(this).data("attrName"));
1599
+ });
1600
+ _this.find(".pvtCols li span.pvtAttr").each(function() {
1601
+ return subopts.cols.push($(this).data("attrName"));
1602
+ });
1603
+ _this.find(".pvtVals select.pvtAttrDropdown").each(function() {
1604
+ if (numInputsToProcess === 0) {
1605
+ return $(this).remove();
1606
+ } else {
1607
+ numInputsToProcess--;
1608
+ if ($(this).val() !== "") {
1609
+ return vals.push($(this).val());
1610
+ }
1611
+ }
1612
+ });
1613
+ if (numInputsToProcess !== 0) {
1614
+ pvtVals = _this.find(".pvtVals");
1615
+ for (x = t = 0, ref5 = numInputsToProcess; 0 <= ref5 ? t < ref5 : t > ref5; x = 0 <= ref5 ? ++t : --t) {
1616
+ newDropdown = $("<select>").addClass('pvtAttrDropdown').append($("<option>")).bind("change", function() {
1617
+ return refresh();
1618
+ });
1619
+ for (u = 0, len4 = shownInAggregators.length; u < len4; u++) {
1620
+ attr = shownInAggregators[u];
1621
+ newDropdown.append($("<option>").val(attr).text(attr));
1622
+ }
1623
+ pvtVals.append(newDropdown);
1624
+ }
1625
+ }
1626
+ if (initialRender) {
1627
+ vals = opts.vals;
1628
+ i = 0;
1629
+ _this.find(".pvtVals select.pvtAttrDropdown").each(function() {
1630
+ $(this).val(vals[i]);
1631
+ return i++;
1632
+ });
1633
+ initialRender = false;
1634
+ }
1635
+ subopts.aggregatorName = aggregator.val();
1636
+ subopts.vals = vals;
1637
+ subopts.aggregator = opts.aggregators[aggregator.val()](vals);
1638
+ subopts.renderer = opts.renderers[renderer.val()];
1639
+ subopts.rowOrder = rowOrderArrow.data("order");
1640
+ subopts.colOrder = colOrderArrow.data("order");
1641
+ exclusions = {};
1642
+ _this.find('input.pvtFilter').not(':checked').each(function() {
1643
+ var filter;
1644
+ filter = $(this).data("filter");
1645
+ if (exclusions[filter[0]] != null) {
1646
+ return exclusions[filter[0]].push(filter[1]);
1647
+ } else {
1648
+ return exclusions[filter[0]] = [filter[1]];
1649
+ }
1650
+ });
1651
+ inclusions = {};
1652
+ _this.find('input.pvtFilter:checked').each(function() {
1653
+ var filter;
1654
+ filter = $(this).data("filter");
1655
+ if (exclusions[filter[0]] != null) {
1656
+ if (inclusions[filter[0]] != null) {
1657
+ return inclusions[filter[0]].push(filter[1]);
1658
+ } else {
1659
+ return inclusions[filter[0]] = [filter[1]];
1660
+ }
1661
+ }
1662
+ });
1663
+ subopts.filter = function(record) {
1664
+ var excludedItems, k, ref6, ref7;
1665
+ if (!opts.filter(record)) {
1666
+ return false;
1667
+ }
1668
+ for (k in exclusions) {
1669
+ excludedItems = exclusions[k];
1670
+ if (ref6 = "" + ((ref7 = record[k]) != null ? ref7 : 'null'), indexOf.call(excludedItems, ref6) >= 0) {
1671
+ return false;
1672
+ }
1673
+ }
1674
+ return true;
1675
+ };
1676
+ pivotTable.pivot(materializedInput, subopts);
1677
+ pivotUIOptions = $.extend({}, opts, {
1678
+ cols: subopts.cols,
1679
+ rows: subopts.rows,
1680
+ colOrder: subopts.colOrder,
1681
+ rowOrder: subopts.rowOrder,
1682
+ vals: vals,
1683
+ exclusions: exclusions,
1684
+ inclusions: inclusions,
1685
+ inclusionsInfo: inclusions,
1686
+ aggregatorName: aggregator.val(),
1687
+ rendererName: renderer.val()
1688
+ });
1689
+ _this.data("pivotUIOptions", pivotUIOptions);
1690
+ if (opts.autoSortUnusedAttrs) {
1691
+ unusedAttrsContainer = _this.find("td.pvtUnused.pvtAxisContainer");
1692
+ $(unusedAttrsContainer).children("li").sort(function(a, b) {
1693
+ return naturalSort($(a).text(), $(b).text());
1694
+ }).appendTo(unusedAttrsContainer);
1695
+ }
1696
+ pivotTable.css("opacity", 1);
1697
+ if (opts.onRefresh != null) {
1698
+ return opts.onRefresh(pivotUIOptions);
1699
+ }
1700
+ };
1701
+ })(this);
1702
+ refresh = (function(_this) {
1703
+ return function() {
1704
+ pivotTable.css("opacity", 0.5);
1705
+ return setTimeout(refreshDelayed, 10);
1706
+ };
1707
+ })(this);
1708
+ refresh();
1709
+ this.find(".pvtAxisContainer").sortable({
1710
+ update: function(e, ui) {
1711
+ if (ui.sender == null) {
1712
+ return refresh();
1713
+ }
1714
+ },
1715
+ connectWith: this.find(".pvtAxisContainer"),
1716
+ items: 'li',
1717
+ placeholder: 'pvtPlaceholder'
1718
+ });
1719
+ } catch (error) {
1720
+ e = error;
1721
+ if (typeof console !== "undefined" && console !== null) {
1722
+ console.error(e.stack);
1723
+ }
1724
+ this.html(opts.localeStrings.uiRenderError);
1725
+ }
1726
+ return this;
1727
+ };
1728
+
1729
+ /*
1730
+ Heatmap post-processing
1731
+ */
1732
+ $.fn.heatmap = function(scope, opts) {
1733
+ var colorScaleGenerator, heatmapper, i, j, l, n, numCols, numRows, ref, ref1, ref2;
1734
+ if (scope == null) {
1735
+ scope = "heatmap";
1736
+ }
1737
+ numRows = this.data("numrows");
1738
+ numCols = this.data("numcols");
1739
+ colorScaleGenerator = opts != null ? (ref = opts.heatmap) != null ? ref.colorScaleGenerator : void 0 : void 0;
1740
+ if (colorScaleGenerator == null) {
1741
+ colorScaleGenerator = function(values) {
1742
+ var max, min;
1743
+ min = Math.min.apply(Math, values);
1744
+ max = Math.max.apply(Math, values);
1745
+ return function(x) {
1746
+ var nonRed;
1747
+ nonRed = 255 - Math.round(255 * (x - min) / (max - min));
1748
+ return "rgb(255," + nonRed + "," + nonRed + ")";
1749
+ };
1750
+ };
1751
+ }
1752
+ heatmapper = (function(_this) {
1753
+ return function(scope) {
1754
+ var colorScale, forEachCell, values;
1755
+ forEachCell = function(f) {
1756
+ return _this.find(scope).each(function() {
1757
+ var x;
1758
+ x = $(this).data("value");
1759
+ if ((x != null) && isFinite(x)) {
1760
+ return f(x, $(this));
1761
+ }
1762
+ });
1763
+ };
1764
+ values = [];
1765
+ forEachCell(function(x) {
1766
+ return values.push(x);
1767
+ });
1768
+ colorScale = colorScaleGenerator(values);
1769
+ return forEachCell(function(x, elem) {
1770
+ return elem.css("background-color", colorScale(x));
1771
+ });
1772
+ };
1773
+ })(this);
1774
+ switch (scope) {
1775
+ case "heatmap":
1776
+ heatmapper(".pvtVal");
1777
+ break;
1778
+ case "rowheatmap":
1779
+ for (i = l = 0, ref1 = numRows; 0 <= ref1 ? l < ref1 : l > ref1; i = 0 <= ref1 ? ++l : --l) {
1780
+ heatmapper(".pvtVal.row" + i);
1781
+ }
1782
+ break;
1783
+ case "colheatmap":
1784
+ for (j = n = 0, ref2 = numCols; 0 <= ref2 ? n < ref2 : n > ref2; j = 0 <= ref2 ? ++n : --n) {
1785
+ heatmapper(".pvtVal.col" + j);
1786
+ }
1787
+ }
1788
+ heatmapper(".pvtTotal.rowTotal");
1789
+ heatmapper(".pvtTotal.colTotal");
1790
+ return this;
1791
+ };
1792
+
1793
+ /*
1794
+ Barchart post-processing
1795
+ */
1796
+ return $.fn.barchart = function(opts) {
1797
+ var barcharter, i, l, numCols, numRows, ref;
1798
+ numRows = this.data("numrows");
1799
+ numCols = this.data("numcols");
1800
+ barcharter = (function(_this) {
1801
+ return function(scope) {
1802
+ var forEachCell, max, min, range, scaler, values;
1803
+ forEachCell = function(f) {
1804
+ return _this.find(scope).each(function() {
1805
+ var x;
1806
+ x = $(this).data("value");
1807
+ if ((x != null) && isFinite(x)) {
1808
+ return f(x, $(this));
1809
+ }
1810
+ });
1811
+ };
1812
+ values = [];
1813
+ forEachCell(function(x) {
1814
+ return values.push(x);
1815
+ });
1816
+ max = Math.max.apply(Math, values);
1817
+ if (max < 0) {
1818
+ max = 0;
1819
+ }
1820
+ range = max;
1821
+ min = Math.min.apply(Math, values);
1822
+ if (min < 0) {
1823
+ range = max - min;
1824
+ }
1825
+ scaler = function(x) {
1826
+ return 100 * x / (1.4 * range);
1827
+ };
1828
+ return forEachCell(function(x, elem) {
1829
+ var bBase, bgColor, text, wrapper;
1830
+ text = elem.text();
1831
+ wrapper = $("<div>").css({
1832
+ "position": "relative",
1833
+ "height": "55px"
1834
+ });
1835
+ bgColor = "gray";
1836
+ bBase = 0;
1837
+ if (min < 0) {
1838
+ bBase = scaler(-min);
1839
+ }
1840
+ if (x < 0) {
1841
+ bBase += scaler(x);
1842
+ bgColor = "darkred";
1843
+ x = -x;
1844
+ }
1845
+ wrapper.append($("<div>").css({
1846
+ "position": "absolute",
1847
+ "bottom": bBase + "%",
1848
+ "left": 0,
1849
+ "right": 0,
1850
+ "height": scaler(x) + "%",
1851
+ "background-color": bgColor
1852
+ }));
1853
+ wrapper.append($("<div>").text(text).css({
1854
+ "position": "relative",
1855
+ "padding-left": "5px",
1856
+ "padding-right": "5px"
1857
+ }));
1858
+ return elem.css({
1859
+ "padding": 0,
1860
+ "padding-top": "5px",
1861
+ "text-align": "center"
1862
+ }).html(wrapper);
1863
+ });
1864
+ };
1865
+ })(this);
1866
+ for (i = l = 0, ref = numRows; 0 <= ref ? l < ref : l > ref; i = 0 <= ref ? ++l : --l) {
1867
+ barcharter(".pvtVal.row" + i);
1868
+ }
1869
+ barcharter(".pvtTotal.colTotal");
1870
+ return this;
1871
+ };
1872
+ };
1873
+
1874
+ module.exports = initPivotTable;