@datarailsshared/dr_renderer 1.1.41 → 1.2.2

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