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,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);