rails_pivot_table_js 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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,356 @@
1
+ //
2
+ // NReco PivotTable Extensions
3
+ // Author: Vitaliy Fedorchenko
4
+ //
5
+ // Copyright (c) nrecosite.com - All Rights Reserved
6
+ // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
7
+ // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
8
+ // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
9
+ // PARTICULAR PURPOSE.
10
+ //
11
+ (function () {
12
+ var $;
13
+
14
+ $ = jQuery;
15
+
16
+ var applyDrillDownHandler = function (wrapper, pvtData, tElem) {
17
+ if (!wrapper.options.drillDownHandler)
18
+ return;
19
+ $(tElem).addClass('pvtValDrillDown').on("click", "td.pvtVal,td.pvtTotal", function () {
20
+ var cssClasses = $(this).attr('class').split(' ');
21
+ var colIdx = -1, rowIdx = -1;
22
+ if ($.inArray("pvtVal", cssClasses) >= 0) {
23
+ $.each(cssClasses, function () {
24
+ if (this.indexOf('row') == 0) rowIdx = parseInt(this.substring(3));
25
+ if (this.indexOf('col') == 0) colIdx = parseInt(this.substring(3));
26
+ });
27
+ }
28
+ if ($.inArray("rowTotal", cssClasses) >= 0) {
29
+ var dataFor = $(this).attr('data-for');
30
+ rowIdx = parseInt(dataFor.substring(3));
31
+ }
32
+ if ($.inArray("colTotal", cssClasses) >= 0) {
33
+ var dataFor = $(this).attr('data-for');
34
+ colIdx = parseInt(dataFor.substring(3));
35
+ }
36
+ var dataFilter = {};
37
+ if (colIdx >= 0) {
38
+ for (var cAttrIdx = 0; cAttrIdx < pvtData.colAttrs.length; cAttrIdx++) {
39
+ var colKeys = pvtData.getColKeys();
40
+ var cValues = colKeys[colIdx];
41
+ dataFilter[pvtData.colAttrs[cAttrIdx]] = cValues[cAttrIdx];
42
+ }
43
+ }
44
+ if (rowIdx >= 0) {
45
+ for (var rAttrIdx = 0; rAttrIdx < pvtData.rowAttrs.length; rAttrIdx++) {
46
+ var rowKeys = pvtData.getRowKeys();
47
+ var rValues = rowKeys[rowIdx];
48
+ dataFilter[pvtData.rowAttrs[rAttrIdx]] = rValues[rAttrIdx];
49
+ }
50
+ }
51
+ wrapper.options.drillDownHandler(dataFilter);
52
+ });
53
+ };
54
+
55
+ var sortDataByCol = function (pvtData, sortByColIdx, ascDesc) {
56
+ var sortRowVals = [];
57
+ var rowKey, colKey, aggregator, i;
58
+
59
+ pvtData.sorted = false; // flush row/col order
60
+ var rowKeys = pvtData.getRowKeys();
61
+ var colKeys = pvtData.getColKeys();
62
+
63
+ for (i in rowKeys) {
64
+ rowKey = rowKeys[i];
65
+ colKey = sortByColIdx != null ? colKeys[sortByColIdx] : [];
66
+ aggregator = pvtData.getAggregator(rowKey, colKey);
67
+ sortRowVals.push({ val: aggregator.value(), key: rowKey });
68
+ }
69
+ sortRowVals.sort(function (a, b) {
70
+ return ascDesc * $.pivotUtilities.naturalSort(a.val, b.val);
71
+ });
72
+ pvtData.rowKeys = [];
73
+ for (i = 0; i < sortRowVals.length; i++)
74
+ pvtData.rowKeys.push(sortRowVals[i].key);
75
+ pvtData.sorted = true;
76
+ };
77
+
78
+ var sortDataByRow = function (pvtData, sortByRowIdx, ascDesc) {
79
+ var sortColVals = [];
80
+ var rowKey, colKey, aggregator, i;
81
+
82
+ pvtData.sorted = false; // flush row/col order
83
+ var rowKeys = pvtData.getRowKeys();
84
+ var colKeys = pvtData.getColKeys();
85
+
86
+ for (i in colKeys) {
87
+ colKey = colKeys[i];
88
+ rowKey = sortByRowIdx != null ? rowKeys[sortByRowIdx] : [];
89
+ aggregator = pvtData.getAggregator(rowKey, colKey);
90
+ sortColVals.push({ val: aggregator.value(), key: colKey });
91
+ }
92
+ sortColVals.sort(function (a, b) {
93
+ return ascDesc * $.pivotUtilities.naturalSort(a.val, b.val);
94
+ });
95
+ pvtData.colKeys = [];
96
+ for (i = 0; i < sortColVals.length; i++)
97
+ pvtData.colKeys.push(sortColVals[i].key);
98
+ pvtData.sorted = true;
99
+ };
100
+
101
+ var applySortHandler = function (wrapper, pvtData, opts, tElem, refreshTable) {
102
+ var applyAscDescClass = function ($elem, direction) {
103
+ $elem.addClass(direction == "desc" ? "pvtSortDesc" : "pvtSortAsc");
104
+ };
105
+ var applySort = function (keys, labels, optSortKey, doSort) {
106
+ labels.click(function () {
107
+ var $lbl = $(this);
108
+ var keyIdx = $lbl.data('key_index');
109
+ var key = keys[keyIdx];
110
+
111
+ if ($lbl.hasClass("pvtSortAsc")) {
112
+ doSort(pvtData, keyIdx, -1);
113
+ opts.sort = {direction: "desc"};
114
+ opts.sort[optSortKey] = key;
115
+ } else if ($lbl.hasClass("pvtSortDesc")) {
116
+ pvtData.sorted = false;
117
+ opts.sort = null;
118
+ } else {
119
+ doSort(pvtData, keyIdx, 1);
120
+ opts.sort = {direction: "asc"};
121
+ opts.sort[optSortKey] = key;
122
+ }
123
+ refreshTable();
124
+ }).each(function () {
125
+ if (opts.sort && opts.sort[optSortKey]) {
126
+ var $lbl = $(this);
127
+ var key = keys[$lbl.data('key_index')];
128
+ if (key.join('_') == opts.sort[optSortKey].join('_')) {
129
+ applyAscDescClass($lbl, opts.sort.direction);
130
+ }
131
+ }
132
+ });
133
+ };
134
+ var markSortableLabels = function (keys, $labels) {
135
+ var i = 0;
136
+ $labels.each(function () {
137
+ var $lbl = $(this);
138
+ var lblText = $.trim( $lbl.text() );
139
+ var k = keys[i];
140
+ if (k!=null && k.length>0 && k[k.length - 1] == lblText) {
141
+ $lbl.addClass("pvtSortable").data('key_index', i);
142
+ i++;
143
+ return;
144
+ }
145
+ });
146
+ };
147
+ var colKeys = pvtData.getColKeys();
148
+ markSortableLabels(colKeys, $(tElem).find('.pvtColLabel[colspan="1"]'));
149
+ applySort(colKeys, $(tElem).find('.pvtColLabel.pvtSortable[colspan="1"]'), "column_key", sortDataByCol);
150
+
151
+ var rowKeys = pvtData.getRowKeys();
152
+ markSortableLabels(rowKeys, $(tElem).find('.pvtRowLabel[rowspan="1"]'));
153
+ applySort(rowKeys, $(tElem).find('.pvtRowLabel.pvtSortable[rowspan="1"]'), "row_key", sortDataByRow);
154
+
155
+ // sort by label
156
+ if (wrapper.options.sortByLabelEnabled) {
157
+ $(tElem).find('.pvtAxisLabel').each(function () {
158
+ var $axisLbl = $(this);
159
+ var axisName = $.trim($axisLbl.text());
160
+ var isColAxis = $axisLbl.parent().find('.pvtColLabel').length > 0;
161
+ $axisLbl.data('axis_name', axisName);
162
+ $axisLbl.addClass(isColAxis ? "pvtSortableCol" : "pvtSortableRow");
163
+ if (!opts.sort
164
+ || (isColAxis && (!opts.sort.row_key && !opts.sort.row_totals))
165
+ || (!isColAxis && (!opts.sort.column_key && !opts.sort.col_totals))) {
166
+ applyAscDescClass($axisLbl, opts.sort && opts.sort.labels && opts.sort.labels[axisName] == "desc" ? "desc" : "asc");
167
+ }
168
+ }).click(function () {
169
+ var $axisLbl = $(this);
170
+ var axisName = $axisLbl.data('axis_name');
171
+ var isColAxis = $axisLbl.hasClass('pvtSortableCol');
172
+ if (!opts.sort)
173
+ opts.sort = {};
174
+ if (!opts.sort.labels)
175
+ opts.sort.labels = {};
176
+ if ($axisLbl.hasClass("pvtSortAsc")) {
177
+ //doSort(pvtData, keyIdx, -1);
178
+ opts.sort.labels[axisName] = "desc";
179
+ } else {
180
+ opts.sort.labels[axisName] = "asc";
181
+ }
182
+ pvtData.sorted = false;
183
+ // reset by val
184
+ if (isColAxis) {
185
+ opts.sort.row_key = null;
186
+ opts.sort.row_totals = false;
187
+ } else {
188
+ opts.sort.column_key = null;
189
+ opts.sort.col_totals = false;
190
+ }
191
+ refreshTable();
192
+ });
193
+ }
194
+
195
+ $(tElem).find('tr:last .pvtTotalLabel').addClass("pvtTotalColSortable").click(function () {
196
+ var $lbl = $(this);
197
+ if ($lbl.hasClass("pvtSortAsc")) {
198
+ sortDataByRow(pvtData, null, -1);
199
+ opts.sort = { direction: "desc", row_totals: true };
200
+ } else if ($lbl.hasClass("pvtSortDesc")) {
201
+ pvtData.sorted = false;
202
+ opts.sort = null;
203
+ } else {
204
+ sortDataByRow(pvtData, null, 1);
205
+ opts.sort = { direction: "asc", row_totals: true };
206
+ }
207
+ refreshTable();
208
+ }).each(function () {
209
+ var $lbl = $(this);
210
+ if (opts.sort && opts.sort.row_totals) {
211
+ applyAscDescClass($lbl, opts.sort.direction);
212
+ }
213
+ });
214
+
215
+ $(tElem).find('tr:first .pvtTotalLabel').addClass("pvtTotalRowSortable").click(function () {
216
+ var $lbl = $(this);
217
+ if ($lbl.hasClass("pvtSortAsc")) {
218
+ sortDataByCol(pvtData, null, -1);
219
+ opts.sort = { direction: "desc", col_totals: true };
220
+ } else if ($lbl.hasClass("pvtSortDesc")) {
221
+ pvtData.sorted = false;
222
+ opts.sort = null;
223
+ } else {
224
+ sortDataByCol(pvtData, null, 1);
225
+ opts.sort = { direction: "asc", col_totals: true };
226
+ }
227
+ refreshTable();
228
+ }).each(function () {
229
+ var $lbl = $(this);
230
+ if (opts.sort && opts.sort.col_totals) {
231
+ applyAscDescClass($lbl, opts.sort.direction);
232
+ }
233
+ });
234
+
235
+ };
236
+ var preparePivotData = function (pvtData) {
237
+ var i, j, aggregator;
238
+ var colKeys = pvtData.getColKeys();
239
+ var rowKeys = pvtData.getRowKeys();
240
+ var data = [];
241
+ var totalsRow = [];
242
+ var totalsCol = [];
243
+ for (i in rowKeys) {
244
+ data[i] = [];
245
+ for (j in colKeys) {
246
+ aggregator = pvtData.getAggregator(rowKeys[i], colKeys[j]);
247
+ data[i][j] = aggregator.value();
248
+ }
249
+ totalsCol[i] = pvtData.getAggregator(rowKeys[i], []).value();
250
+ }
251
+ for (j in colKeys) {
252
+ totalsRow[j] = pvtData.getAggregator([], colKeys[j]).value();
253
+ }
254
+ var grandTotalAggregator = pvtData.getAggregator([], []);
255
+ return {
256
+ columnKeys: colKeys,
257
+ columnAttrs : pvtData.colAttrs,
258
+ rowKeys: rowKeys,
259
+ rowAttrs : pvtData.rowAttrs,
260
+ matrix: data,
261
+ totals: { row: totalsRow, column : totalsCol, grandTotal : grandTotalAggregator.value() }
262
+ };
263
+ };
264
+
265
+ window.NRecoPivotTableExtensions = function (options) {
266
+ this.options = $.extend(NRecoPivotTableExtensions.defaults, options);
267
+ };
268
+
269
+ window.NRecoPivotTableExtensions.prototype.sortDataByOpts = function (pvtData, opts) {
270
+ // apply label sort direction modifiers
271
+ if (!pvtData.__origSorters) {
272
+ pvtData.__origSorters = pvtData.sorters;
273
+ pvtData.sorters = function (attr) {
274
+ var comparer = pvtData.__origSorters ? pvtData.__origSorters(attr) : null;
275
+ if (!comparer)
276
+ comparer = $.pivotUtilities.naturalSort;
277
+ if (opts && opts.sort && opts.sort.labels && opts.sort.labels[attr] == "desc") {
278
+ return function (a, b) {
279
+ return -comparer(a, b);
280
+ };
281
+ }
282
+ return comparer;
283
+ };
284
+ }
285
+
286
+ pvtData.sorted = false;
287
+ if (opts && opts.sort) {
288
+ // sort by value
289
+ var ascDesc = opts.sort.direction == "desc" ? -1 : 1;
290
+ if (opts.sort.column_key) {
291
+ var colKeys = pvtData.getColKeys();
292
+ var sortByKeyStr = opts.sort.column_key.join('_');
293
+ for (var i in colKeys)
294
+ if (sortByKeyStr == colKeys[i].join('_')) {
295
+ sortDataByCol(pvtData, i, ascDesc);
296
+ }
297
+ } else if (opts.sort.row_key) {
298
+ var rowKeys = pvtData.getRowKeys();
299
+ var sortByKeyStr = opts.sort.row_key.join('_');
300
+ for (var i in rowKeys)
301
+ if (sortByKeyStr == rowKeys[i].join('_')) {
302
+ sortDataByRow(pvtData, i, ascDesc);
303
+ }
304
+ } else if (opts.sort.row_totals) {
305
+ sortDataByRow(pvtData, null, ascDesc);
306
+ } else if (opts.sort.col_totals) {
307
+ sortDataByCol(pvtData, null, ascDesc);
308
+ }
309
+ }
310
+ };
311
+
312
+ window.NRecoPivotTableExtensions.prototype.wrapTableRenderer = function (tableRenderer) {
313
+ var wrapper = this;
314
+ return function (pvtData, opts) {
315
+ var tElem, refreshTable, wrapTable;
316
+
317
+ wrapper.sortDataByOpts(pvtData, opts);
318
+ tElem = tableRenderer(pvtData, opts);
319
+ wrapTable = function ($t) {
320
+ if (wrapper.options.wrapWith) {
321
+ var $w = $(wrapper.options.wrapWith);
322
+ $w.append($t);
323
+ $t = $w;
324
+ }
325
+ return $t;
326
+ };
327
+ refreshTable = function () {
328
+ var newTbl = tableRenderer(pvtData, opts);
329
+ applyDrillDownHandler(wrapper,pvtData,newTbl);
330
+ applySortHandler(wrapper, pvtData, opts, newTbl, refreshTable);
331
+ $(tElem).replaceWith(newTbl);
332
+ tElem = newTbl;
333
+ };
334
+ applyDrillDownHandler(wrapper, pvtData, tElem);
335
+ applySortHandler(wrapper, pvtData, opts, tElem, refreshTable);
336
+ return wrapTable(tElem);
337
+ };
338
+ };
339
+
340
+ window.NRecoPivotTableExtensions.prototype.wrapPivotExportRenderer = function (renderer) {
341
+ var wrapper = this;
342
+ return function (pvtData, opts) {
343
+ wrapper.sortDataByOpts(pvtData, opts);
344
+ var elem = renderer(pvtData, opts);
345
+ $(elem).addClass("pivotExportData").data("getPivotExportData", function () { return preparePivotData(pvtData); });
346
+ return elem;
347
+ };
348
+ };
349
+
350
+ window.NRecoPivotTableExtensions.defaults = {
351
+ drillDownHandler: null,
352
+ wrapWith: null,
353
+ sortByLabelEnabled : true
354
+ };
355
+
356
+ }).call(this);