rails_pivot_table_js 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +3 -0
  4. data/Rakefile +37 -0
  5. data/app/assets/javascripts/rails_pivot_table_js/application.js +13 -0
  6. data/app/assets/javascripts/rails_pivot_table_js/d3_renderers.js +84 -0
  7. data/app/assets/javascripts/rails_pivot_table_js/gchart_renderers.js +183 -0
  8. data/app/assets/javascripts/rails_pivot_table_js/nrecopivottableext.js +356 -0
  9. data/app/assets/javascripts/rails_pivot_table_js/pivot.js +1510 -0
  10. data/app/assets/javascripts/rails_pivot_table_js/pivot.pt.js +83 -0
  11. data/app/assets/stylesheets/rails_pivot_table_js/application.css +15 -0
  12. data/app/assets/stylesheets/rails_pivot_table_js/pivot.css +228 -0
  13. data/app/controllers/rails_pivot_table_js/application_controller.rb +4 -0
  14. data/app/helpers/rails_pivot_table_js/application_helper.rb +7 -0
  15. data/app/views/layouts/rails_pivot_table_js/application.html.erb +14 -0
  16. data/app/views/rails_pivot_table_js/_pivot.html.haml +61 -0
  17. data/config/routes.rb +2 -0
  18. data/lib/rails_pivot_table_js/engine.rb +5 -0
  19. data/lib/rails_pivot_table_js/version.rb +3 -0
  20. data/lib/rails_pivot_table_js.rb +4 -0
  21. data/lib/tasks/rails_pivot_table_js_tasks.rake +4 -0
  22. data/test/dummy/README.rdoc +28 -0
  23. data/test/dummy/Rakefile +6 -0
  24. data/test/dummy/app/assets/javascripts/application.js +13 -0
  25. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  26. data/test/dummy/app/controllers/application_controller.rb +5 -0
  27. data/test/dummy/app/helpers/application_helper.rb +2 -0
  28. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  29. data/test/dummy/bin/bundle +3 -0
  30. data/test/dummy/bin/rails +4 -0
  31. data/test/dummy/bin/rake +4 -0
  32. data/test/dummy/bin/setup +29 -0
  33. data/test/dummy/config/application.rb +26 -0
  34. data/test/dummy/config/boot.rb +5 -0
  35. data/test/dummy/config/database.yml +25 -0
  36. data/test/dummy/config/environment.rb +5 -0
  37. data/test/dummy/config/environments/development.rb +41 -0
  38. data/test/dummy/config/environments/production.rb +79 -0
  39. data/test/dummy/config/environments/test.rb +42 -0
  40. data/test/dummy/config/initializers/assets.rb +11 -0
  41. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  42. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  43. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  44. data/test/dummy/config/initializers/inflections.rb +16 -0
  45. data/test/dummy/config/initializers/mime_types.rb +4 -0
  46. data/test/dummy/config/initializers/session_store.rb +3 -0
  47. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  48. data/test/dummy/config/locales/en.yml +23 -0
  49. data/test/dummy/config/routes.rb +4 -0
  50. data/test/dummy/config/secrets.yml +22 -0
  51. data/test/dummy/config.ru +4 -0
  52. data/test/dummy/public/404.html +67 -0
  53. data/test/dummy/public/422.html +67 -0
  54. data/test/dummy/public/500.html +66 -0
  55. data/test/dummy/public/favicon.ico +0 -0
  56. data/test/integration/navigation_test.rb +8 -0
  57. data/test/rails_pivot_table_js_test.rb +7 -0
  58. data/test/test_helper.rb +21 -0
  59. metadata +158 -0
@@ -0,0 +1,1510 @@
1
+ (function() {
2
+ var callWithJQuery,
3
+ 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
+ callWithJQuery = function(pivotModule) {
9
+ if (typeof exports === "object" && typeof module === "object") {
10
+ return pivotModule(require("jquery"));
11
+ } else if (typeof define === "function" && define.amd) {
12
+ return define(["jquery"], pivotModule);
13
+ } else {
14
+ return pivotModule(jQuery);
15
+ }
16
+ };
17
+
18
+ callWithJQuery(function($) {
19
+
20
+ /*
21
+ Utilities
22
+ */
23
+ var PivotData, addSeparators, aggregatorTemplates, aggregators, dayNamesEn, derivers, getSort, locales, mthNamesEn, naturalSort, numberFormat, pivotTableRenderer, renderers, sortAs, usFmt, usFmtInt, usFmtPct, zeroPad;
24
+ addSeparators = function(nStr, thousandsSep, decimalSep) {
25
+ var rgx, x, x1, x2;
26
+ nStr += '';
27
+ x = nStr.split('.');
28
+ x1 = x[0];
29
+ x2 = x.length > 1 ? decimalSep + x[1] : '';
30
+ rgx = /(\d+)(\d{3})/;
31
+ while (rgx.test(x1)) {
32
+ x1 = x1.replace(rgx, '$1' + thousandsSep + '$2');
33
+ }
34
+ return x1 + x2;
35
+ };
36
+ numberFormat = function(opts) {
37
+ var defaults;
38
+ defaults = {
39
+ digitsAfterDecimal: 2,
40
+ scaler: 1,
41
+ thousandsSep: ",",
42
+ decimalSep: ".",
43
+ prefix: "",
44
+ suffix: "",
45
+ showZero: false
46
+ };
47
+ opts = $.extend(defaults, opts);
48
+ return function(x) {
49
+ var result;
50
+ if (isNaN(x) || !isFinite(x)) {
51
+ return "";
52
+ }
53
+ if (x === 0 && !opts.showZero) {
54
+ return "";
55
+ }
56
+ result = addSeparators((opts.scaler * x).toFixed(opts.digitsAfterDecimal), opts.thousandsSep, opts.decimalSep);
57
+ return "" + opts.prefix + result + opts.suffix;
58
+ };
59
+ };
60
+ usFmt = numberFormat();
61
+ usFmtInt = numberFormat({
62
+ digitsAfterDecimal: 0
63
+ });
64
+ usFmtPct = numberFormat({
65
+ digitsAfterDecimal: 1,
66
+ scaler: 100,
67
+ suffix: "%"
68
+ });
69
+ aggregatorTemplates = {
70
+ count: function(formatter) {
71
+ if (formatter == null) {
72
+ formatter = usFmtInt;
73
+ }
74
+ return function() {
75
+ return function(data, rowKey, colKey) {
76
+ return {
77
+ count: 0,
78
+ push: function() {
79
+ return this.count++;
80
+ },
81
+ value: function() {
82
+ return this.count;
83
+ },
84
+ format: formatter
85
+ };
86
+ };
87
+ };
88
+ },
89
+ countUnique: function(formatter) {
90
+ if (formatter == null) {
91
+ formatter = usFmtInt;
92
+ }
93
+ return function(arg) {
94
+ var attr;
95
+ attr = arg[0];
96
+ return function(data, rowKey, colKey) {
97
+ return {
98
+ uniq: [],
99
+ push: function(record) {
100
+ var ref;
101
+ if (ref = record[attr], indexOf.call(this.uniq, ref) < 0) {
102
+ return this.uniq.push(record[attr]);
103
+ }
104
+ },
105
+ value: function() {
106
+ return this.uniq.length;
107
+ },
108
+ format: formatter,
109
+ numInputs: attr != null ? 0 : 1
110
+ };
111
+ };
112
+ };
113
+ },
114
+ listUnique: function(sep) {
115
+ return function(arg) {
116
+ var attr;
117
+ attr = arg[0];
118
+ return function(data, rowKey, colKey) {
119
+ return {
120
+ uniq: [],
121
+ push: function(record) {
122
+ var ref;
123
+ if (ref = record[attr], indexOf.call(this.uniq, ref) < 0) {
124
+ return this.uniq.push(record[attr]);
125
+ }
126
+ },
127
+ value: function() {
128
+ return this.uniq.join(sep);
129
+ },
130
+ format: function(x) {
131
+ return x;
132
+ },
133
+ numInputs: attr != null ? 0 : 1
134
+ };
135
+ };
136
+ };
137
+ },
138
+ sum: function(formatter) {
139
+ if (formatter == null) {
140
+ formatter = usFmt;
141
+ }
142
+ return function(arg) {
143
+ var attr;
144
+ attr = arg[0];
145
+ return function(data, rowKey, colKey) {
146
+ return {
147
+ sum: 0,
148
+ push: function(record) {
149
+ if (!isNaN(parseFloat(record[attr]))) {
150
+ return this.sum += parseFloat(record[attr]);
151
+ }
152
+ },
153
+ value: function() {
154
+ return this.sum;
155
+ },
156
+ format: formatter,
157
+ numInputs: attr != null ? 0 : 1
158
+ };
159
+ };
160
+ };
161
+ },
162
+ min: function(formatter) {
163
+ if (formatter == null) {
164
+ formatter = usFmt;
165
+ }
166
+ return function(arg) {
167
+ var attr;
168
+ attr = arg[0];
169
+ return function(data, rowKey, colKey) {
170
+ return {
171
+ val: null,
172
+ push: function(record) {
173
+ var ref, x;
174
+ x = parseFloat(record[attr]);
175
+ if (!isNaN(x)) {
176
+ return this.val = Math.min(x, (ref = this.val) != null ? ref : x);
177
+ }
178
+ },
179
+ value: function() {
180
+ return this.val;
181
+ },
182
+ format: formatter,
183
+ numInputs: attr != null ? 0 : 1
184
+ };
185
+ };
186
+ };
187
+ },
188
+ max: function(formatter) {
189
+ if (formatter == null) {
190
+ formatter = usFmt;
191
+ }
192
+ return function(arg) {
193
+ var attr;
194
+ attr = arg[0];
195
+ return function(data, rowKey, colKey) {
196
+ return {
197
+ val: null,
198
+ push: function(record) {
199
+ var ref, x;
200
+ x = parseFloat(record[attr]);
201
+ if (!isNaN(x)) {
202
+ return this.val = Math.max(x, (ref = this.val) != null ? ref : x);
203
+ }
204
+ },
205
+ value: function() {
206
+ return this.val;
207
+ },
208
+ format: formatter,
209
+ numInputs: attr != null ? 0 : 1
210
+ };
211
+ };
212
+ };
213
+ },
214
+ average: function(formatter) {
215
+ if (formatter == null) {
216
+ formatter = usFmt;
217
+ }
218
+ return function(arg) {
219
+ var attr;
220
+ attr = arg[0];
221
+ return function(data, rowKey, colKey) {
222
+ return {
223
+ sum: 0,
224
+ len: 0,
225
+ push: function(record) {
226
+ if (!isNaN(parseFloat(record[attr]))) {
227
+ this.sum += parseFloat(record[attr]);
228
+ return this.len++;
229
+ }
230
+ },
231
+ value: function() {
232
+ return this.sum / this.len;
233
+ },
234
+ format: formatter,
235
+ numInputs: attr != null ? 0 : 1
236
+ };
237
+ };
238
+ };
239
+ },
240
+ sumOverSum: function(formatter) {
241
+ if (formatter == null) {
242
+ formatter = usFmt;
243
+ }
244
+ return function(arg) {
245
+ var denom, num;
246
+ num = arg[0], denom = arg[1];
247
+ return function(data, rowKey, colKey) {
248
+ return {
249
+ sumNum: 0,
250
+ sumDenom: 0,
251
+ push: function(record) {
252
+ if (!isNaN(parseFloat(record[num]))) {
253
+ this.sumNum += parseFloat(record[num]);
254
+ }
255
+ if (!isNaN(parseFloat(record[denom]))) {
256
+ return this.sumDenom += parseFloat(record[denom]);
257
+ }
258
+ },
259
+ value: function() {
260
+ return this.sumNum / this.sumDenom;
261
+ },
262
+ format: formatter,
263
+ numInputs: (num != null) && (denom != null) ? 0 : 2
264
+ };
265
+ };
266
+ };
267
+ },
268
+ sumOverSumBound80: function(upper, formatter) {
269
+ if (upper == null) {
270
+ upper = true;
271
+ }
272
+ if (formatter == null) {
273
+ formatter = usFmt;
274
+ }
275
+ return function(arg) {
276
+ var denom, num;
277
+ num = arg[0], denom = arg[1];
278
+ return function(data, rowKey, colKey) {
279
+ return {
280
+ sumNum: 0,
281
+ sumDenom: 0,
282
+ push: function(record) {
283
+ if (!isNaN(parseFloat(record[num]))) {
284
+ this.sumNum += parseFloat(record[num]);
285
+ }
286
+ if (!isNaN(parseFloat(record[denom]))) {
287
+ return this.sumDenom += parseFloat(record[denom]);
288
+ }
289
+ },
290
+ value: function() {
291
+ var sign;
292
+ sign = upper ? 1 : -1;
293
+ 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);
294
+ },
295
+ format: formatter,
296
+ numInputs: (num != null) && (denom != null) ? 0 : 2
297
+ };
298
+ };
299
+ };
300
+ },
301
+ fractionOf: function(wrapped, type, formatter) {
302
+ if (type == null) {
303
+ type = "total";
304
+ }
305
+ if (formatter == null) {
306
+ formatter = usFmtPct;
307
+ }
308
+ return function() {
309
+ var x;
310
+ x = 1 <= arguments.length ? slice.call(arguments, 0) : [];
311
+ return function(data, rowKey, colKey) {
312
+ return {
313
+ selector: {
314
+ total: [[], []],
315
+ row: [rowKey, []],
316
+ col: [[], colKey]
317
+ }[type],
318
+ inner: wrapped.apply(null, x)(data, rowKey, colKey),
319
+ push: function(record) {
320
+ return this.inner.push(record);
321
+ },
322
+ format: formatter,
323
+ value: function() {
324
+ return this.inner.value() / data.getAggregator.apply(data, this.selector).inner.value();
325
+ },
326
+ numInputs: wrapped.apply(null, x)().numInputs
327
+ };
328
+ };
329
+ };
330
+ }
331
+ };
332
+ aggregators = (function(tpl) {
333
+ return {
334
+ "Count": tpl.count(usFmtInt),
335
+ "Count Unique Values": tpl.countUnique(usFmtInt),
336
+ "List Unique Values": tpl.listUnique(", "),
337
+ "Sum": tpl.sum(usFmt),
338
+ "Integer Sum": tpl.sum(usFmtInt),
339
+ "Average": tpl.average(usFmt),
340
+ "Minimum": tpl.min(usFmt),
341
+ "Maximum": tpl.max(usFmt),
342
+ "Sum over Sum": tpl.sumOverSum(usFmt),
343
+ "80% Upper Bound": tpl.sumOverSumBound80(true, usFmt),
344
+ "80% Lower Bound": tpl.sumOverSumBound80(false, usFmt),
345
+ "Sum as Fraction of Total": tpl.fractionOf(tpl.sum(), "total", usFmtPct),
346
+ "Sum as Fraction of Rows": tpl.fractionOf(tpl.sum(), "row", usFmtPct),
347
+ "Sum as Fraction of Columns": tpl.fractionOf(tpl.sum(), "col", usFmtPct),
348
+ "Count as Fraction of Total": tpl.fractionOf(tpl.count(), "total", usFmtPct),
349
+ "Count as Fraction of Rows": tpl.fractionOf(tpl.count(), "row", usFmtPct),
350
+ "Count as Fraction of Columns": tpl.fractionOf(tpl.count(), "col", usFmtPct)
351
+ };
352
+ })(aggregatorTemplates);
353
+ renderers = {
354
+ "Table": function(pvtData, opts) {
355
+ return pivotTableRenderer(pvtData, opts);
356
+ },
357
+ "Table Barchart": function(pvtData, opts) {
358
+ return $(pivotTableRenderer(pvtData, opts)).barchart();
359
+ },
360
+ "Heatmap": function(pvtData, opts) {
361
+ return $(pivotTableRenderer(pvtData, opts)).heatmap();
362
+ },
363
+ "Row Heatmap": function(pvtData, opts) {
364
+ return $(pivotTableRenderer(pvtData, opts)).heatmap("rowheatmap");
365
+ },
366
+ "Col Heatmap": function(pvtData, opts) {
367
+ return $(pivotTableRenderer(pvtData, opts)).heatmap("colheatmap");
368
+ }
369
+ };
370
+ locales = {
371
+ en: {
372
+ aggregators: aggregators,
373
+ renderers: renderers,
374
+ localeStrings: {
375
+ renderError: "An error occurred rendering the PivotTable results.",
376
+ computeError: "An error occurred computing the PivotTable results.",
377
+ uiRenderError: "An error occurred rendering the PivotTable UI.",
378
+ selectAll: "Select All",
379
+ selectNone: "Select None",
380
+ tooMany: "(too many to list)",
381
+ filterResults: "Filter results",
382
+ totals: "Totals",
383
+ vs: "vs",
384
+ by: "by"
385
+ }
386
+ }
387
+ };
388
+ mthNamesEn = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
389
+ dayNamesEn = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
390
+ zeroPad = function(number) {
391
+ return ("0" + number).substr(-2, 2);
392
+ };
393
+ derivers = {
394
+ bin: function(col, binWidth) {
395
+ return function(record) {
396
+ return record[col] - record[col] % binWidth;
397
+ };
398
+ },
399
+ dateFormat: function(col, formatString, utcOutput, mthNames, dayNames) {
400
+ var utc;
401
+ if (utcOutput == null) {
402
+ utcOutput = false;
403
+ }
404
+ if (mthNames == null) {
405
+ mthNames = mthNamesEn;
406
+ }
407
+ if (dayNames == null) {
408
+ dayNames = dayNamesEn;
409
+ }
410
+ utc = utcOutput ? "UTC" : "";
411
+ return function(record) {
412
+ var date;
413
+ date = new Date(Date.parse(record[col]));
414
+ if (isNaN(date)) {
415
+ return "";
416
+ }
417
+ return formatString.replace(/%(.)/g, function(m, p) {
418
+ switch (p) {
419
+ case "y":
420
+ return date["get" + utc + "FullYear"]();
421
+ case "m":
422
+ return zeroPad(date["get" + utc + "Month"]() + 1);
423
+ case "n":
424
+ return mthNames[date["get" + utc + "Month"]()];
425
+ case "d":
426
+ return zeroPad(date["get" + utc + "Date"]());
427
+ case "w":
428
+ return dayNames[date["get" + utc + "Day"]()];
429
+ case "x":
430
+ return date["get" + utc + "Day"]();
431
+ case "H":
432
+ return zeroPad(date["get" + utc + "Hours"]());
433
+ case "M":
434
+ return zeroPad(date["get" + utc + "Minutes"]());
435
+ case "S":
436
+ return zeroPad(date["get" + utc + "Seconds"]());
437
+ default:
438
+ return "%" + p;
439
+ }
440
+ });
441
+ };
442
+ }
443
+ };
444
+ naturalSort = (function(_this) {
445
+ return function(as, bs) {
446
+ var a, a1, b, b1, rd, rx, rz;
447
+ rx = /(\d+)|(\D+)/g;
448
+ rd = /\d/;
449
+ rz = /^0/;
450
+ if (typeof as === "number" || typeof bs === "number") {
451
+ if (isNaN(as)) {
452
+ return 1;
453
+ }
454
+ if (isNaN(bs)) {
455
+ return -1;
456
+ }
457
+ return as - bs;
458
+ }
459
+ a = String(as).toLowerCase();
460
+ b = String(bs).toLowerCase();
461
+ if (a === b) {
462
+ return 0;
463
+ }
464
+ if (!(rd.test(a) && rd.test(b))) {
465
+ return (a > b ? 1 : -1);
466
+ }
467
+ a = a.match(rx);
468
+ b = b.match(rx);
469
+ while (a.length && b.length) {
470
+ a1 = a.shift();
471
+ b1 = b.shift();
472
+ if (a1 !== b1) {
473
+ if (rd.test(a1) && rd.test(b1)) {
474
+ return a1.replace(rz, ".0") - b1.replace(rz, ".0");
475
+ } else {
476
+ return (a1 > b1 ? 1 : -1);
477
+ }
478
+ }
479
+ }
480
+ return a.length - b.length;
481
+ };
482
+ })(this);
483
+ sortAs = function(order) {
484
+ var i, mapping, x;
485
+ mapping = {};
486
+ for (i in order) {
487
+ x = order[i];
488
+ mapping[x] = i;
489
+ }
490
+ return function(a, b) {
491
+ if ((mapping[a] != null) && (mapping[b] != null)) {
492
+ return mapping[a] - mapping[b];
493
+ } else if (mapping[a] != null) {
494
+ return -1;
495
+ } else if (mapping[b] != null) {
496
+ return 1;
497
+ } else {
498
+ return naturalSort(a, b);
499
+ }
500
+ };
501
+ };
502
+ getSort = function(sorters, attr) {
503
+ var sort;
504
+ sort = sorters(attr);
505
+ if ($.isFunction(sort)) {
506
+ return sort;
507
+ } else {
508
+ return naturalSort;
509
+ }
510
+ };
511
+ $.pivotUtilities = {
512
+ aggregatorTemplates: aggregatorTemplates,
513
+ aggregators: aggregators,
514
+ renderers: renderers,
515
+ derivers: derivers,
516
+ locales: locales,
517
+ naturalSort: naturalSort,
518
+ numberFormat: numberFormat,
519
+ sortAs: sortAs
520
+ };
521
+
522
+ /*
523
+ Data Model class
524
+ */
525
+ PivotData = (function() {
526
+ function PivotData(input, opts) {
527
+ this.getAggregator = bind(this.getAggregator, this);
528
+ this.getRowKeys = bind(this.getRowKeys, this);
529
+ this.getColKeys = bind(this.getColKeys, this);
530
+ this.sortKeys = bind(this.sortKeys, this);
531
+ this.arrSort = bind(this.arrSort, this);
532
+ this.aggregator = opts.aggregator;
533
+ this.aggregatorName = opts.aggregatorName;
534
+ this.colAttrs = opts.cols;
535
+ this.rowAttrs = opts.rows;
536
+ this.valAttrs = opts.vals;
537
+ this.sorters = opts.sorters;
538
+ this.tree = {};
539
+ this.rowKeys = [];
540
+ this.colKeys = [];
541
+ this.rowTotals = {};
542
+ this.colTotals = {};
543
+ this.allTotal = this.aggregator(this, [], []);
544
+ this.sorted = false;
545
+ PivotData.forEachRecord(input, opts.derivedAttributes, (function(_this) {
546
+ return function(record) {
547
+ if (opts.filter(record)) {
548
+ return _this.processRecord(record);
549
+ }
550
+ };
551
+ })(this));
552
+ }
553
+
554
+ PivotData.forEachRecord = function(input, derivedAttributes, f) {
555
+ var addRecord, compactRecord, i, j, k, l, len1, record, ref, results, results1, tblCols;
556
+ if ($.isEmptyObject(derivedAttributes)) {
557
+ addRecord = f;
558
+ } else {
559
+ addRecord = function(record) {
560
+ var k, ref, v;
561
+ for (k in derivedAttributes) {
562
+ v = derivedAttributes[k];
563
+ record[k] = (ref = v(record)) != null ? ref : record[k];
564
+ }
565
+ return f(record);
566
+ };
567
+ }
568
+ if ($.isFunction(input)) {
569
+ return input(addRecord);
570
+ } else if ($.isArray(input)) {
571
+ if ($.isArray(input[0])) {
572
+ results = [];
573
+ for (i in input) {
574
+ if (!hasProp.call(input, i)) continue;
575
+ compactRecord = input[i];
576
+ if (!(i > 0)) {
577
+ continue;
578
+ }
579
+ record = {};
580
+ ref = input[0];
581
+ for (j in ref) {
582
+ if (!hasProp.call(ref, j)) continue;
583
+ k = ref[j];
584
+ record[k] = compactRecord[j];
585
+ }
586
+ results.push(addRecord(record));
587
+ }
588
+ return results;
589
+ } else {
590
+ results1 = [];
591
+ for (l = 0, len1 = input.length; l < len1; l++) {
592
+ record = input[l];
593
+ results1.push(addRecord(record));
594
+ }
595
+ return results1;
596
+ }
597
+ } else if (input instanceof jQuery) {
598
+ tblCols = [];
599
+ $("thead > tr > th", input).each(function(i) {
600
+ return tblCols.push($(this).text());
601
+ });
602
+ return $("tbody > tr", input).each(function(i) {
603
+ record = {};
604
+ $("td", this).each(function(j) {
605
+ return record[tblCols[j]] = $(this).text();
606
+ });
607
+ return addRecord(record);
608
+ });
609
+ } else {
610
+ throw new Error("unknown input format");
611
+ }
612
+ };
613
+
614
+ PivotData.convertToArray = function(input) {
615
+ var result;
616
+ result = [];
617
+ PivotData.forEachRecord(input, {}, function(record) {
618
+ return result.push(record);
619
+ });
620
+ return result;
621
+ };
622
+
623
+ PivotData.prototype.arrSort = function(attrs) {
624
+ var a, sortersArr;
625
+ sortersArr = (function() {
626
+ var l, len1, results;
627
+ results = [];
628
+ for (l = 0, len1 = attrs.length; l < len1; l++) {
629
+ a = attrs[l];
630
+ results.push(getSort(this.sorters, a));
631
+ }
632
+ return results;
633
+ }).call(this);
634
+ return function(a, b) {
635
+ var comparison, i, sorter;
636
+ for (i in sortersArr) {
637
+ if (!hasProp.call(sortersArr, i)) continue;
638
+ sorter = sortersArr[i];
639
+ comparison = sorter(a[i], b[i]);
640
+ if (comparison !== 0) {
641
+ return comparison;
642
+ }
643
+ }
644
+ return 0;
645
+ };
646
+ };
647
+
648
+ PivotData.prototype.sortKeys = function() {
649
+ if (!this.sorted) {
650
+ this.sorted = true;
651
+ this.rowKeys.sort(this.arrSort(this.rowAttrs));
652
+ return this.colKeys.sort(this.arrSort(this.colAttrs));
653
+ }
654
+ };
655
+
656
+ PivotData.prototype.getColKeys = function() {
657
+ this.sortKeys();
658
+ return this.colKeys;
659
+ };
660
+
661
+ PivotData.prototype.getRowKeys = function() {
662
+ this.sortKeys();
663
+ return this.rowKeys;
664
+ };
665
+
666
+ PivotData.prototype.processRecord = function(record) {
667
+ var colKey, flatColKey, flatRowKey, l, len1, len2, n, ref, ref1, ref2, ref3, rowKey, x;
668
+ colKey = [];
669
+ rowKey = [];
670
+ ref = this.colAttrs;
671
+ for (l = 0, len1 = ref.length; l < len1; l++) {
672
+ x = ref[l];
673
+ colKey.push((ref1 = record[x]) != null ? ref1 : "null");
674
+ }
675
+ ref2 = this.rowAttrs;
676
+ for (n = 0, len2 = ref2.length; n < len2; n++) {
677
+ x = ref2[n];
678
+ rowKey.push((ref3 = record[x]) != null ? ref3 : "null");
679
+ }
680
+ flatRowKey = rowKey.join(String.fromCharCode(0));
681
+ flatColKey = colKey.join(String.fromCharCode(0));
682
+ this.allTotal.push(record);
683
+ if (rowKey.length !== 0) {
684
+ if (!this.rowTotals[flatRowKey]) {
685
+ this.rowKeys.push(rowKey);
686
+ this.rowTotals[flatRowKey] = this.aggregator(this, rowKey, []);
687
+ }
688
+ this.rowTotals[flatRowKey].push(record);
689
+ }
690
+ if (colKey.length !== 0) {
691
+ if (!this.colTotals[flatColKey]) {
692
+ this.colKeys.push(colKey);
693
+ this.colTotals[flatColKey] = this.aggregator(this, [], colKey);
694
+ }
695
+ this.colTotals[flatColKey].push(record);
696
+ }
697
+ if (colKey.length !== 0 && rowKey.length !== 0) {
698
+ if (!this.tree[flatRowKey]) {
699
+ this.tree[flatRowKey] = {};
700
+ }
701
+ if (!this.tree[flatRowKey][flatColKey]) {
702
+ this.tree[flatRowKey][flatColKey] = this.aggregator(this, rowKey, colKey);
703
+ }
704
+ return this.tree[flatRowKey][flatColKey].push(record);
705
+ }
706
+ };
707
+
708
+ PivotData.prototype.getAggregator = function(rowKey, colKey) {
709
+ var agg, flatColKey, flatRowKey;
710
+ flatRowKey = rowKey.join(String.fromCharCode(0));
711
+ flatColKey = colKey.join(String.fromCharCode(0));
712
+ if (rowKey.length === 0 && colKey.length === 0) {
713
+ agg = this.allTotal;
714
+ } else if (rowKey.length === 0) {
715
+ agg = this.colTotals[flatColKey];
716
+ } else if (colKey.length === 0) {
717
+ agg = this.rowTotals[flatRowKey];
718
+ } else {
719
+ agg = this.tree[flatRowKey][flatColKey];
720
+ }
721
+ return agg != null ? agg : {
722
+ value: (function() {
723
+ return null;
724
+ }),
725
+ format: function() {
726
+ return "";
727
+ }
728
+ };
729
+ };
730
+
731
+ return PivotData;
732
+
733
+ })();
734
+
735
+ /*
736
+ Default Renderer for hierarchical table layout
737
+ */
738
+ pivotTableRenderer = function(pivotData, opts) {
739
+ var aggregator, c, colAttrs, colKey, colKeys, defaults, i, j, r, result, rowAttrs, rowKey, rowKeys, spanSize, td, th, totalAggregator, tr, txt, val, x;
740
+ defaults = {
741
+ localeStrings: {
742
+ totals: "Totals"
743
+ }
744
+ };
745
+ opts = $.extend(defaults, opts);
746
+ colAttrs = pivotData.colAttrs;
747
+ rowAttrs = pivotData.rowAttrs;
748
+ rowKeys = pivotData.getRowKeys();
749
+ colKeys = pivotData.getColKeys();
750
+ result = document.createElement("table");
751
+ result.className = "pvtTable";
752
+ spanSize = function(arr, i, j) {
753
+ var l, len, n, noDraw, ref, ref1, stop, x;
754
+ if (i !== 0) {
755
+ noDraw = true;
756
+ for (x = l = 0, ref = j; 0 <= ref ? l <= ref : l >= ref; x = 0 <= ref ? ++l : --l) {
757
+ if (arr[i - 1][x] !== arr[i][x]) {
758
+ noDraw = false;
759
+ }
760
+ }
761
+ if (noDraw) {
762
+ return -1;
763
+ }
764
+ }
765
+ len = 0;
766
+ while (i + len < arr.length) {
767
+ stop = false;
768
+ for (x = n = 0, ref1 = j; 0 <= ref1 ? n <= ref1 : n >= ref1; x = 0 <= ref1 ? ++n : --n) {
769
+ if (arr[i][x] !== arr[i + len][x]) {
770
+ stop = true;
771
+ }
772
+ }
773
+ if (stop) {
774
+ break;
775
+ }
776
+ len++;
777
+ }
778
+ return len;
779
+ };
780
+ for (j in colAttrs) {
781
+ if (!hasProp.call(colAttrs, j)) continue;
782
+ c = colAttrs[j];
783
+ tr = document.createElement("tr");
784
+ if (parseInt(j) === 0 && rowAttrs.length !== 0) {
785
+ th = document.createElement("th");
786
+ th.setAttribute("colspan", rowAttrs.length);
787
+ th.setAttribute("rowspan", colAttrs.length);
788
+ tr.appendChild(th);
789
+ }
790
+ th = document.createElement("th");
791
+ th.className = "pvtAxisLabel";
792
+ th.textContent = c;
793
+ tr.appendChild(th);
794
+ for (i in colKeys) {
795
+ if (!hasProp.call(colKeys, i)) continue;
796
+ colKey = colKeys[i];
797
+ x = spanSize(colKeys, parseInt(i), parseInt(j));
798
+ if (x !== -1) {
799
+ th = document.createElement("th");
800
+ th.className = "pvtColLabel";
801
+ th.textContent = colKey[j];
802
+ th.setAttribute("colspan", x);
803
+ if (parseInt(j) === colAttrs.length - 1 && rowAttrs.length !== 0) {
804
+ th.setAttribute("rowspan", 2);
805
+ }
806
+ tr.appendChild(th);
807
+ }
808
+ }
809
+ if (parseInt(j) === 0) {
810
+ th = document.createElement("th");
811
+ th.className = "pvtTotalLabel";
812
+ th.innerHTML = opts.localeStrings.totals;
813
+ th.setAttribute("rowspan", colAttrs.length + (rowAttrs.length === 0 ? 0 : 1));
814
+ tr.appendChild(th);
815
+ }
816
+ result.appendChild(tr);
817
+ }
818
+ if (rowAttrs.length !== 0) {
819
+ tr = document.createElement("tr");
820
+ for (i in rowAttrs) {
821
+ if (!hasProp.call(rowAttrs, i)) continue;
822
+ r = rowAttrs[i];
823
+ th = document.createElement("th");
824
+ th.className = "pvtAxisLabel";
825
+ th.textContent = r;
826
+ tr.appendChild(th);
827
+ }
828
+ th = document.createElement("th");
829
+ if (colAttrs.length === 0) {
830
+ th.className = "pvtTotalLabel";
831
+ th.innerHTML = opts.localeStrings.totals;
832
+ }
833
+ tr.appendChild(th);
834
+ result.appendChild(tr);
835
+ }
836
+ for (i in rowKeys) {
837
+ if (!hasProp.call(rowKeys, i)) continue;
838
+ rowKey = rowKeys[i];
839
+ tr = document.createElement("tr");
840
+ for (j in rowKey) {
841
+ if (!hasProp.call(rowKey, j)) continue;
842
+ txt = rowKey[j];
843
+ x = spanSize(rowKeys, parseInt(i), parseInt(j));
844
+ if (x !== -1) {
845
+ th = document.createElement("th");
846
+ th.className = "pvtRowLabel";
847
+ th.textContent = txt;
848
+ th.setAttribute("rowspan", x);
849
+ if (parseInt(j) === rowAttrs.length - 1 && colAttrs.length !== 0) {
850
+ th.setAttribute("colspan", 2);
851
+ }
852
+ tr.appendChild(th);
853
+ }
854
+ }
855
+ for (j in colKeys) {
856
+ if (!hasProp.call(colKeys, j)) continue;
857
+ colKey = colKeys[j];
858
+ aggregator = pivotData.getAggregator(rowKey, colKey);
859
+ val = aggregator.value();
860
+ td = document.createElement("td");
861
+ td.className = "pvtVal row" + i + " col" + j;
862
+ td.textContent = aggregator.format(val);
863
+ td.setAttribute("data-value", val);
864
+ tr.appendChild(td);
865
+ }
866
+ totalAggregator = pivotData.getAggregator(rowKey, []);
867
+ val = totalAggregator.value();
868
+ td = document.createElement("td");
869
+ td.className = "pvtTotal rowTotal";
870
+ td.textContent = totalAggregator.format(val);
871
+ td.setAttribute("data-value", val);
872
+ td.setAttribute("data-for", "row" + i);
873
+ tr.appendChild(td);
874
+ result.appendChild(tr);
875
+ }
876
+ tr = document.createElement("tr");
877
+ th = document.createElement("th");
878
+ th.className = "pvtTotalLabel";
879
+ th.innerHTML = opts.localeStrings.totals;
880
+ th.setAttribute("colspan", rowAttrs.length + (colAttrs.length === 0 ? 0 : 1));
881
+ tr.appendChild(th);
882
+ for (j in colKeys) {
883
+ if (!hasProp.call(colKeys, j)) continue;
884
+ colKey = colKeys[j];
885
+ totalAggregator = pivotData.getAggregator([], colKey);
886
+ val = totalAggregator.value();
887
+ td = document.createElement("td");
888
+ td.className = "pvtTotal colTotal";
889
+ td.textContent = totalAggregator.format(val);
890
+ td.setAttribute("data-value", val);
891
+ td.setAttribute("data-for", "col" + j);
892
+ tr.appendChild(td);
893
+ }
894
+ totalAggregator = pivotData.getAggregator([], []);
895
+ val = totalAggregator.value();
896
+ td = document.createElement("td");
897
+ td.className = "pvtGrandTotal";
898
+ td.textContent = totalAggregator.format(val);
899
+ td.setAttribute("data-value", val);
900
+ tr.appendChild(td);
901
+ result.appendChild(tr);
902
+ result.setAttribute("data-numrows", rowKeys.length);
903
+ result.setAttribute("data-numcols", colKeys.length);
904
+ return result;
905
+ };
906
+
907
+ /*
908
+ Pivot Table core: create PivotData object and call Renderer on it
909
+ */
910
+ $.fn.pivot = function(input, opts) {
911
+ var defaults, e, pivotData, result, x;
912
+ defaults = {
913
+ cols: [],
914
+ rows: [],
915
+ vals: [],
916
+ filter: function() {
917
+ return true;
918
+ },
919
+ aggregator: aggregatorTemplates.count()(),
920
+ aggregatorName: "Count",
921
+ sorters: function() {},
922
+ derivedAttributes: {},
923
+ renderer: pivotTableRenderer,
924
+ rendererOptions: null,
925
+ localeStrings: locales.en.localeStrings
926
+ };
927
+ opts = $.extend(defaults, opts);
928
+ result = null;
929
+ try {
930
+ pivotData = new PivotData(input, opts);
931
+ try {
932
+ result = opts.renderer(pivotData, opts.rendererOptions);
933
+ } catch (_error) {
934
+ e = _error;
935
+ if (typeof console !== "undefined" && console !== null) {
936
+ console.error(e.stack);
937
+ }
938
+ result = $("<span>").html(opts.localeStrings.renderError);
939
+ }
940
+ } catch (_error) {
941
+ e = _error;
942
+ if (typeof console !== "undefined" && console !== null) {
943
+ console.error(e.stack);
944
+ }
945
+ result = $("<span>").html(opts.localeStrings.computeError);
946
+ }
947
+ x = this[0];
948
+ while (x.hasChildNodes()) {
949
+ x.removeChild(x.lastChild);
950
+ }
951
+ return this.append(result);
952
+ };
953
+
954
+ /*
955
+ Pivot Table UI: calls Pivot Table core above with options set by user
956
+ */
957
+ $.fn.pivotUI = function(input, inputOpts, overwrite, locale) {
958
+ var a, aggregator, attrLength, axisValues, c, colList, defaults, e, existingOpts, fn, i, initialRender, k, l, len1, len2, len3, len4, n, o, opts, pivotTable, q, ref, ref1, ref2, ref3, ref4, refresh, refreshDelayed, renderer, rendererControl, shownAttributes, tblCols, tr1, tr2, uiTable, unusedAttrsVerticalAutoCutoff, unusedAttrsVerticalAutoOverride, x;
959
+ if (overwrite == null) {
960
+ overwrite = false;
961
+ }
962
+ if (locale == null) {
963
+ locale = "en";
964
+ }
965
+ if (locales[locale] == null) {
966
+ locale = "en";
967
+ }
968
+ defaults = {
969
+ derivedAttributes: {},
970
+ aggregators: locales[locale].aggregators,
971
+ renderers: locales[locale].renderers,
972
+ hiddenAttributes: [],
973
+ menuLimit: 200,
974
+ cols: [],
975
+ rows: [],
976
+ vals: [],
977
+ exclusions: {},
978
+ inclusions: {},
979
+ unusedAttrsVertical: 85,
980
+ autoSortUnusedAttrs: false,
981
+ rendererOptions: {
982
+ localeStrings: locales[locale].localeStrings
983
+ },
984
+ onRefresh: null,
985
+ filter: function() {
986
+ return true;
987
+ },
988
+ sorters: function() {},
989
+ localeStrings: locales[locale].localeStrings
990
+ };
991
+ existingOpts = this.data("pivotUIOptions");
992
+ if ((existingOpts == null) || overwrite) {
993
+ opts = $.extend(defaults, inputOpts);
994
+ } else {
995
+ opts = existingOpts;
996
+ }
997
+ try {
998
+ input = PivotData.convertToArray(input);
999
+ tblCols = (function() {
1000
+ var ref, results;
1001
+ ref = input[0];
1002
+ results = [];
1003
+ for (k in ref) {
1004
+ if (!hasProp.call(ref, k)) continue;
1005
+ results.push(k);
1006
+ }
1007
+ return results;
1008
+ })();
1009
+ ref = opts.derivedAttributes;
1010
+ for (c in ref) {
1011
+ if (!hasProp.call(ref, c)) continue;
1012
+ if ((indexOf.call(tblCols, c) < 0)) {
1013
+ tblCols.push(c);
1014
+ }
1015
+ }
1016
+ axisValues = {};
1017
+ for (l = 0, len1 = tblCols.length; l < len1; l++) {
1018
+ x = tblCols[l];
1019
+ axisValues[x] = {};
1020
+ }
1021
+ PivotData.forEachRecord(input, opts.derivedAttributes, function(record) {
1022
+ var base, results, v;
1023
+ results = [];
1024
+ for (k in record) {
1025
+ if (!hasProp.call(record, k)) continue;
1026
+ v = record[k];
1027
+ if (!(opts.filter(record))) {
1028
+ continue;
1029
+ }
1030
+ if (v == null) {
1031
+ v = "null";
1032
+ }
1033
+ if ((base = axisValues[k])[v] == null) {
1034
+ base[v] = 0;
1035
+ }
1036
+ results.push(axisValues[k][v]++);
1037
+ }
1038
+ return results;
1039
+ });
1040
+ uiTable = $("<table>", {
1041
+ "class": "pvtUi"
1042
+ }).attr("cellpadding", 5);
1043
+ rendererControl = $("<td>");
1044
+ renderer = $("<select>").addClass('pvtRenderer').appendTo(rendererControl).bind("change", function() {
1045
+ return refresh();
1046
+ });
1047
+ ref1 = opts.renderers;
1048
+ for (x in ref1) {
1049
+ if (!hasProp.call(ref1, x)) continue;
1050
+ $("<option>").val(x).html(x).appendTo(renderer);
1051
+ }
1052
+ colList = $("<td>").addClass('pvtAxisContainer pvtUnused');
1053
+ shownAttributes = (function() {
1054
+ var len2, n, results;
1055
+ results = [];
1056
+ for (n = 0, len2 = tblCols.length; n < len2; n++) {
1057
+ c = tblCols[n];
1058
+ if (indexOf.call(opts.hiddenAttributes, c) < 0) {
1059
+ results.push(c);
1060
+ }
1061
+ }
1062
+ return results;
1063
+ })();
1064
+ unusedAttrsVerticalAutoOverride = false;
1065
+ if (opts.unusedAttrsVertical === "auto") {
1066
+ unusedAttrsVerticalAutoCutoff = 120;
1067
+ } else {
1068
+ unusedAttrsVerticalAutoCutoff = parseInt(opts.unusedAttrsVertical);
1069
+ }
1070
+ if (!isNaN(unusedAttrsVerticalAutoCutoff)) {
1071
+ attrLength = 0;
1072
+ for (n = 0, len2 = shownAttributes.length; n < len2; n++) {
1073
+ a = shownAttributes[n];
1074
+ attrLength += a.length;
1075
+ }
1076
+ unusedAttrsVerticalAutoOverride = attrLength > unusedAttrsVerticalAutoCutoff;
1077
+ }
1078
+ if (opts.unusedAttrsVertical === true || unusedAttrsVerticalAutoOverride) {
1079
+ colList.addClass('pvtVertList');
1080
+ } else {
1081
+ colList.addClass('pvtHorizList');
1082
+ }
1083
+ fn = function(c) {
1084
+ var attrElem, btns, checkContainer, filterItem, filterItemExcluded, hasExcludedItem, keys, len3, o, ref2, showFilterList, triangleLink, updateFilter, v, valueList;
1085
+ keys = (function() {
1086
+ var results;
1087
+ results = [];
1088
+ for (k in axisValues[c]) {
1089
+ results.push(k);
1090
+ }
1091
+ return results;
1092
+ })();
1093
+ hasExcludedItem = false;
1094
+ valueList = $("<div>").addClass('pvtFilterBox').hide();
1095
+ valueList.append($("<h4>").text(c + " (" + keys.length + ")"));
1096
+ if (keys.length > opts.menuLimit) {
1097
+ valueList.append($("<p>").html(opts.localeStrings.tooMany));
1098
+ } else {
1099
+ btns = $("<p>").appendTo(valueList);
1100
+ btns.append($("<button>", {
1101
+ type: "button"
1102
+ }).html(opts.localeStrings.selectAll).bind("click", function() {
1103
+ return valueList.find("input:visible").prop("checked", true);
1104
+ }));
1105
+ btns.append($("<button>", {
1106
+ type: "button"
1107
+ }).html(opts.localeStrings.selectNone).bind("click", function() {
1108
+ return valueList.find("input:visible").prop("checked", false);
1109
+ }));
1110
+ btns.append($("<br>"));
1111
+ btns.append($("<input>", {
1112
+ type: "text",
1113
+ placeholder: opts.localeStrings.filterResults,
1114
+ "class": "pvtSearch"
1115
+ }).bind("keyup", function() {
1116
+ var filter;
1117
+ filter = $(this).val().toLowerCase();
1118
+ return valueList.find('.pvtCheckContainer p').each(function() {
1119
+ var testString;
1120
+ testString = $(this).text().toLowerCase().indexOf(filter);
1121
+ if (testString !== -1) {
1122
+ return $(this).show();
1123
+ } else {
1124
+ return $(this).hide();
1125
+ }
1126
+ });
1127
+ }));
1128
+ checkContainer = $("<div>").addClass("pvtCheckContainer").appendTo(valueList);
1129
+ ref2 = keys.sort(getSort(opts.sorters, c));
1130
+ for (o = 0, len3 = ref2.length; o < len3; o++) {
1131
+ k = ref2[o];
1132
+ v = axisValues[c][k];
1133
+ filterItem = $("<label>");
1134
+ filterItemExcluded = false;
1135
+ if (opts.inclusions[c]) {
1136
+ filterItemExcluded = (indexOf.call(opts.inclusions[c], k) < 0);
1137
+ } else if (opts.exclusions[c]) {
1138
+ filterItemExcluded = (indexOf.call(opts.exclusions[c], k) >= 0);
1139
+ }
1140
+ hasExcludedItem || (hasExcludedItem = filterItemExcluded);
1141
+ $("<input>").attr("type", "checkbox").addClass('pvtFilter').attr("checked", !filterItemExcluded).data("filter", [c, k]).appendTo(filterItem);
1142
+ filterItem.append($("<span>").text(k));
1143
+ filterItem.append($("<span>").text(" (" + v + ")"));
1144
+ checkContainer.append($("<p>").append(filterItem));
1145
+ }
1146
+ }
1147
+ updateFilter = function() {
1148
+ var unselectedCount;
1149
+ unselectedCount = valueList.find("[type='checkbox']").length - valueList.find("[type='checkbox']:checked").length;
1150
+ if (unselectedCount > 0) {
1151
+ attrElem.addClass("pvtFilteredAttribute");
1152
+ } else {
1153
+ attrElem.removeClass("pvtFilteredAttribute");
1154
+ }
1155
+ if (keys.length > opts.menuLimit) {
1156
+ return valueList.toggle();
1157
+ } else {
1158
+ return valueList.toggle(0, refresh);
1159
+ }
1160
+ };
1161
+ $("<p>").appendTo(valueList).append($("<button>", {
1162
+ type: "button"
1163
+ }).text("OK").bind("click", updateFilter));
1164
+ showFilterList = function(e) {
1165
+ var clickLeft, clickTop, ref3;
1166
+ ref3 = $(e.currentTarget).position(), clickLeft = ref3.left, clickTop = ref3.top;
1167
+ valueList.css({
1168
+ left: clickLeft + 10,
1169
+ top: clickTop + 10
1170
+ }).toggle();
1171
+ valueList.find('.pvtSearch').val('');
1172
+ return valueList.find('.pvtCheckContainer p').show();
1173
+ };
1174
+ triangleLink = $("<span>").addClass('pvtTriangle').html(" &#x25BE;").bind("click", showFilterList);
1175
+ attrElem = $("<li>").addClass("axis_" + i).append($("<span>").addClass('pvtAttr').text(c).data("attrName", c).append(triangleLink));
1176
+ if (hasExcludedItem) {
1177
+ attrElem.addClass('pvtFilteredAttribute');
1178
+ }
1179
+ colList.append(attrElem).append(valueList);
1180
+ return attrElem.bind("dblclick", showFilterList);
1181
+ };
1182
+ for (i in shownAttributes) {
1183
+ if (!hasProp.call(shownAttributes, i)) continue;
1184
+ c = shownAttributes[i];
1185
+ fn(c);
1186
+ }
1187
+ tr1 = $("<tr>").appendTo(uiTable);
1188
+ aggregator = $("<select>").addClass('pvtAggregator').bind("change", function() {
1189
+ return refresh();
1190
+ });
1191
+ ref2 = opts.aggregators;
1192
+ for (x in ref2) {
1193
+ if (!hasProp.call(ref2, x)) continue;
1194
+ aggregator.append($("<option>").val(x).html(x));
1195
+ }
1196
+ $("<td>").addClass('pvtVals').appendTo(tr1).append(aggregator).append($("<br>"));
1197
+ $("<td>").addClass('pvtAxisContainer pvtHorizList pvtCols').appendTo(tr1);
1198
+ tr2 = $("<tr>").appendTo(uiTable);
1199
+ tr2.append($("<td>").addClass('pvtAxisContainer pvtRows').attr("valign", "top"));
1200
+ pivotTable = $("<td>").attr("valign", "top").addClass('pvtRendererArea').appendTo(tr2);
1201
+ if (opts.unusedAttrsVertical === true || unusedAttrsVerticalAutoOverride) {
1202
+ uiTable.find('tr:nth-child(1)').prepend(rendererControl);
1203
+ uiTable.find('tr:nth-child(2)').prepend(colList);
1204
+ } else {
1205
+ uiTable.prepend($("<tr>").append(rendererControl).append(colList));
1206
+ }
1207
+ this.html(uiTable);
1208
+ ref3 = opts.cols;
1209
+ for (o = 0, len3 = ref3.length; o < len3; o++) {
1210
+ x = ref3[o];
1211
+ this.find(".pvtCols").append(this.find(".axis_" + ($.inArray(x, shownAttributes))));
1212
+ }
1213
+ ref4 = opts.rows;
1214
+ for (q = 0, len4 = ref4.length; q < len4; q++) {
1215
+ x = ref4[q];
1216
+ this.find(".pvtRows").append(this.find(".axis_" + ($.inArray(x, shownAttributes))));
1217
+ }
1218
+ if (opts.aggregatorName != null) {
1219
+ this.find(".pvtAggregator").val(opts.aggregatorName);
1220
+ }
1221
+ if (opts.rendererName != null) {
1222
+ this.find(".pvtRenderer").val(opts.rendererName);
1223
+ }
1224
+ initialRender = true;
1225
+ refreshDelayed = (function(_this) {
1226
+ return function() {
1227
+ var attr, exclusions, inclusions, len5, newDropdown, numInputsToProcess, pivotUIOptions, pvtVals, ref5, ref6, s, subopts, t, unusedAttrsContainer, vals;
1228
+ subopts = {
1229
+ derivedAttributes: opts.derivedAttributes,
1230
+ localeStrings: opts.localeStrings,
1231
+ rendererOptions: opts.rendererOptions,
1232
+ sorters: opts.sorters,
1233
+ cols: [],
1234
+ rows: []
1235
+ };
1236
+ numInputsToProcess = (ref5 = opts.aggregators[aggregator.val()]([])().numInputs) != null ? ref5 : 0;
1237
+ vals = [];
1238
+ _this.find(".pvtRows li span.pvtAttr").each(function() {
1239
+ return subopts.rows.push($(this).data("attrName"));
1240
+ });
1241
+ _this.find(".pvtCols li span.pvtAttr").each(function() {
1242
+ return subopts.cols.push($(this).data("attrName"));
1243
+ });
1244
+ _this.find(".pvtVals select.pvtAttrDropdown").each(function() {
1245
+ if (numInputsToProcess === 0) {
1246
+ return $(this).remove();
1247
+ } else {
1248
+ numInputsToProcess--;
1249
+ if ($(this).val() !== "") {
1250
+ return vals.push($(this).val());
1251
+ }
1252
+ }
1253
+ });
1254
+ if (numInputsToProcess !== 0) {
1255
+ pvtVals = _this.find(".pvtVals");
1256
+ for (x = s = 0, ref6 = numInputsToProcess; 0 <= ref6 ? s < ref6 : s > ref6; x = 0 <= ref6 ? ++s : --s) {
1257
+ newDropdown = $("<select>").addClass('pvtAttrDropdown').append($("<option>")).bind("change", function() {
1258
+ return refresh();
1259
+ });
1260
+ for (t = 0, len5 = shownAttributes.length; t < len5; t++) {
1261
+ attr = shownAttributes[t];
1262
+ newDropdown.append($("<option>").val(attr).text(attr));
1263
+ }
1264
+ pvtVals.append(newDropdown);
1265
+ }
1266
+ }
1267
+ if (initialRender) {
1268
+ vals = opts.vals;
1269
+ i = 0;
1270
+ _this.find(".pvtVals select.pvtAttrDropdown").each(function() {
1271
+ $(this).val(vals[i]);
1272
+ return i++;
1273
+ });
1274
+ initialRender = false;
1275
+ }
1276
+ subopts.aggregatorName = aggregator.val();
1277
+ subopts.vals = vals;
1278
+ subopts.aggregator = opts.aggregators[aggregator.val()](vals);
1279
+ subopts.renderer = opts.renderers[renderer.val()];
1280
+ exclusions = {};
1281
+ _this.find('input.pvtFilter').not(':checked').each(function() {
1282
+ var filter;
1283
+ filter = $(this).data("filter");
1284
+ if (exclusions[filter[0]] != null) {
1285
+ return exclusions[filter[0]].push(filter[1]);
1286
+ } else {
1287
+ return exclusions[filter[0]] = [filter[1]];
1288
+ }
1289
+ });
1290
+ inclusions = {};
1291
+ _this.find('input.pvtFilter:checked').each(function() {
1292
+ var filter;
1293
+ filter = $(this).data("filter");
1294
+ if (exclusions[filter[0]] != null) {
1295
+ if (inclusions[filter[0]] != null) {
1296
+ return inclusions[filter[0]].push(filter[1]);
1297
+ } else {
1298
+ return inclusions[filter[0]] = [filter[1]];
1299
+ }
1300
+ }
1301
+ });
1302
+ subopts.filter = function(record) {
1303
+ var excludedItems, ref7;
1304
+ if (!opts.filter(record)) {
1305
+ return false;
1306
+ }
1307
+ for (k in exclusions) {
1308
+ excludedItems = exclusions[k];
1309
+ if (ref7 = "" + record[k], indexOf.call(excludedItems, ref7) >= 0) {
1310
+ return false;
1311
+ }
1312
+ }
1313
+ return true;
1314
+ };
1315
+ pivotTable.pivot(input, subopts);
1316
+ pivotUIOptions = $.extend(opts, {
1317
+ cols: subopts.cols,
1318
+ rows: subopts.rows,
1319
+ vals: vals,
1320
+ exclusions: exclusions,
1321
+ inclusions: inclusions,
1322
+ inclusionsInfo: inclusions,
1323
+ aggregatorName: aggregator.val(),
1324
+ rendererName: renderer.val()
1325
+ });
1326
+ _this.data("pivotUIOptions", pivotUIOptions);
1327
+ if (opts.autoSortUnusedAttrs) {
1328
+ unusedAttrsContainer = _this.find("td.pvtUnused.pvtAxisContainer");
1329
+ $(unusedAttrsContainer).children("li").sort(function(a, b) {
1330
+ return naturalSort($(a).text(), $(b).text());
1331
+ }).appendTo(unusedAttrsContainer);
1332
+ }
1333
+ pivotTable.css("opacity", 1);
1334
+ if (opts.onRefresh != null) {
1335
+ return opts.onRefresh(pivotUIOptions);
1336
+ }
1337
+ };
1338
+ })(this);
1339
+ refresh = (function(_this) {
1340
+ return function() {
1341
+ pivotTable.css("opacity", 0.5);
1342
+ return setTimeout(refreshDelayed, 10);
1343
+ };
1344
+ })(this);
1345
+ refresh();
1346
+ this.find(".pvtAxisContainer").sortable({
1347
+ update: function(e, ui) {
1348
+ if (ui.sender == null) {
1349
+ return refresh();
1350
+ }
1351
+ },
1352
+ connectWith: this.find(".pvtAxisContainer"),
1353
+ items: 'li',
1354
+ placeholder: 'pvtPlaceholder'
1355
+ });
1356
+ } catch (_error) {
1357
+ e = _error;
1358
+ if (typeof console !== "undefined" && console !== null) {
1359
+ console.error(e.stack);
1360
+ }
1361
+ this.html(opts.localeStrings.uiRenderError);
1362
+ }
1363
+ return this;
1364
+ };
1365
+
1366
+ /*
1367
+ Heatmap post-processing
1368
+ */
1369
+ $.fn.heatmap = function(scope) {
1370
+ var colorGen, heatmapper, i, j, l, n, numCols, numRows, ref, ref1;
1371
+ if (scope == null) {
1372
+ scope = "heatmap";
1373
+ }
1374
+ numRows = this.data("numrows");
1375
+ numCols = this.data("numcols");
1376
+ colorGen = function(color, min, max) {
1377
+ var hexGen;
1378
+ hexGen = (function() {
1379
+ switch (color) {
1380
+ case "red":
1381
+ return function(hex) {
1382
+ return "ff" + hex + hex;
1383
+ };
1384
+ case "green":
1385
+ return function(hex) {
1386
+ return hex + "ff" + hex;
1387
+ };
1388
+ case "blue":
1389
+ return function(hex) {
1390
+ return "" + hex + hex + "ff";
1391
+ };
1392
+ }
1393
+ })();
1394
+ return function(x) {
1395
+ var hex, intensity;
1396
+ intensity = 255 - Math.round(255 * (x - min) / (max - min));
1397
+ hex = intensity.toString(16).split(".")[0];
1398
+ if (hex.length === 1) {
1399
+ hex = 0 + hex;
1400
+ }
1401
+ return hexGen(hex);
1402
+ };
1403
+ };
1404
+ heatmapper = (function(_this) {
1405
+ return function(scope, color) {
1406
+ var colorFor, forEachCell, values;
1407
+ forEachCell = function(f) {
1408
+ return _this.find(scope).each(function() {
1409
+ var x;
1410
+ x = $(this).data("value");
1411
+ if ((x != null) && isFinite(x)) {
1412
+ return f(x, $(this));
1413
+ }
1414
+ });
1415
+ };
1416
+ values = [];
1417
+ forEachCell(function(x) {
1418
+ return values.push(x);
1419
+ });
1420
+ colorFor = colorGen(color, Math.min.apply(Math, values), Math.max.apply(Math, values));
1421
+ return forEachCell(function(x, elem) {
1422
+ return elem.css("background-color", "#" + colorFor(x));
1423
+ });
1424
+ };
1425
+ })(this);
1426
+ switch (scope) {
1427
+ case "heatmap":
1428
+ heatmapper(".pvtVal", "red");
1429
+ break;
1430
+ case "rowheatmap":
1431
+ for (i = l = 0, ref = numRows; 0 <= ref ? l < ref : l > ref; i = 0 <= ref ? ++l : --l) {
1432
+ heatmapper(".pvtVal.row" + i, "red");
1433
+ }
1434
+ break;
1435
+ case "colheatmap":
1436
+ for (j = n = 0, ref1 = numCols; 0 <= ref1 ? n < ref1 : n > ref1; j = 0 <= ref1 ? ++n : --n) {
1437
+ heatmapper(".pvtVal.col" + j, "red");
1438
+ }
1439
+ }
1440
+ heatmapper(".pvtTotal.rowTotal", "red");
1441
+ heatmapper(".pvtTotal.colTotal", "red");
1442
+ return this;
1443
+ };
1444
+
1445
+ /*
1446
+ Barchart post-processing
1447
+ */
1448
+ return $.fn.barchart = function() {
1449
+ var barcharter, i, l, numCols, numRows, ref;
1450
+ numRows = this.data("numrows");
1451
+ numCols = this.data("numcols");
1452
+ barcharter = (function(_this) {
1453
+ return function(scope) {
1454
+ var forEachCell, max, scaler, values;
1455
+ forEachCell = function(f) {
1456
+ return _this.find(scope).each(function() {
1457
+ var x;
1458
+ x = $(this).data("value");
1459
+ if ((x != null) && isFinite(x)) {
1460
+ return f(x, $(this));
1461
+ }
1462
+ });
1463
+ };
1464
+ values = [];
1465
+ forEachCell(function(x) {
1466
+ return values.push(x);
1467
+ });
1468
+ max = Math.max.apply(Math, values);
1469
+ scaler = function(x) {
1470
+ return 100 * x / (1.4 * max);
1471
+ };
1472
+ return forEachCell(function(x, elem) {
1473
+ var text, wrapper;
1474
+ text = elem.text();
1475
+ wrapper = $("<div>").css({
1476
+ "position": "relative",
1477
+ "height": "55px"
1478
+ });
1479
+ wrapper.append($("<div>").css({
1480
+ "position": "absolute",
1481
+ "bottom": 0,
1482
+ "left": 0,
1483
+ "right": 0,
1484
+ "height": scaler(x) + "%",
1485
+ "background-color": "gray"
1486
+ }));
1487
+ wrapper.append($("<div>").text(text).css({
1488
+ "position": "relative",
1489
+ "padding-left": "5px",
1490
+ "padding-right": "5px"
1491
+ }));
1492
+ return elem.css({
1493
+ "padding": 0,
1494
+ "padding-top": "5px",
1495
+ "text-align": "center"
1496
+ }).html(wrapper);
1497
+ });
1498
+ };
1499
+ })(this);
1500
+ for (i = l = 0, ref = numRows; 0 <= ref ? l < ref : l > ref; i = 0 <= ref ? ++l : --l) {
1501
+ barcharter(".pvtVal.row" + i);
1502
+ }
1503
+ barcharter(".pvtTotal.colTotal");
1504
+ return this;
1505
+ };
1506
+ });
1507
+
1508
+ }).call(this);
1509
+
1510
+ //# sourceMappingURL=pivot.js.map