postrest 0.0.3 → 0.0.5

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 (234) hide show
  1. checksums.yaml +4 -4
  2. data/lib/app.rb +1 -1
  3. data/public/index.htm +116 -0
  4. data/public/node_modules/pivottable/CONTRIBUTING.md +19 -0
  5. data/public/node_modules/pivottable/LICENSE.md +9 -0
  6. data/public/node_modules/pivottable/ReadMe.md +155 -0
  7. data/public/node_modules/pivottable/bower.json +31 -0
  8. data/public/node_modules/pivottable/c3_renderers.coffee +155 -0
  9. data/public/node_modules/pivottable/d3_renderers.coffee +73 -0
  10. data/public/node_modules/pivottable/dist/c3_renderers.js +256 -0
  11. data/public/node_modules/pivottable/dist/c3_renderers.js.map +1 -0
  12. data/public/node_modules/pivottable/dist/c3_renderers.min.js +2 -0
  13. data/public/node_modules/pivottable/dist/c3_renderers.min.js.map +1 -0
  14. data/public/node_modules/pivottable/dist/d3_renderers.js +105 -0
  15. data/public/node_modules/pivottable/dist/d3_renderers.js.map +1 -0
  16. data/public/node_modules/pivottable/dist/d3_renderers.min.js +2 -0
  17. data/public/node_modules/pivottable/dist/d3_renderers.min.js.map +1 -0
  18. data/public/node_modules/pivottable/dist/export_renderers.js +80 -0
  19. data/public/node_modules/pivottable/dist/export_renderers.js.map +1 -0
  20. data/public/node_modules/pivottable/dist/export_renderers.min.js +2 -0
  21. data/public/node_modules/pivottable/dist/export_renderers.min.js.map +1 -0
  22. data/public/node_modules/pivottable/dist/gchart_renderers.js +183 -0
  23. data/public/node_modules/pivottable/dist/gchart_renderers.js.map +1 -0
  24. data/public/node_modules/pivottable/dist/gchart_renderers.min.js +2 -0
  25. data/public/node_modules/pivottable/dist/gchart_renderers.min.js.map +1 -0
  26. data/public/node_modules/pivottable/dist/pivot.css +97 -0
  27. data/public/node_modules/pivottable/dist/pivot.es.js +78 -0
  28. data/public/node_modules/pivottable/dist/pivot.es.js.map +1 -0
  29. data/public/node_modules/pivottable/dist/pivot.es.min.js +2 -0
  30. data/public/node_modules/pivottable/dist/pivot.es.min.js.map +1 -0
  31. data/public/node_modules/pivottable/dist/pivot.fr.js +78 -0
  32. data/public/node_modules/pivottable/dist/pivot.fr.js.map +1 -0
  33. data/public/node_modules/pivottable/dist/pivot.fr.min.js +2 -0
  34. data/public/node_modules/pivottable/dist/pivot.fr.min.js.map +1 -0
  35. data/public/node_modules/pivottable/dist/pivot.js +1511 -0
  36. data/public/node_modules/pivottable/dist/pivot.js.map +1 -0
  37. data/public/node_modules/pivottable/dist/pivot.min.css +1 -0
  38. data/public/node_modules/pivottable/dist/pivot.min.js +2 -0
  39. data/public/node_modules/pivottable/dist/pivot.min.js.map +1 -0
  40. data/public/node_modules/pivottable/dist/pivot.nl.js +78 -0
  41. data/public/node_modules/pivottable/dist/pivot.nl.js.map +1 -0
  42. data/public/node_modules/pivottable/dist/pivot.nl.min.js +2 -0
  43. data/public/node_modules/pivottable/dist/pivot.nl.min.js.map +1 -0
  44. data/public/node_modules/pivottable/dist/pivot.pt.js +104 -0
  45. data/public/node_modules/pivottable/dist/pivot.pt.js.map +1 -0
  46. data/public/node_modules/pivottable/dist/pivot.pt.min.js +2 -0
  47. data/public/node_modules/pivottable/dist/pivot.pt.min.js.map +1 -0
  48. data/public/node_modules/pivottable/dist/pivot.ru.js +78 -0
  49. data/public/node_modules/pivottable/dist/pivot.ru.js.map +1 -0
  50. data/public/node_modules/pivottable/dist/pivot.ru.min.js +2 -0
  51. data/public/node_modules/pivottable/dist/pivot.ru.min.js.map +1 -0
  52. data/public/node_modules/pivottable/dist/pivot.tr.js +104 -0
  53. data/public/node_modules/pivottable/dist/pivot.tr.js.map +1 -0
  54. data/public/node_modules/pivottable/dist/pivot.tr.min.js +2 -0
  55. data/public/node_modules/pivottable/dist/pivot.tr.min.js.map +1 -0
  56. data/public/node_modules/pivottable/dist/tips_data.min.js +247 -0
  57. data/public/node_modules/pivottable/examples/c3.html +61 -0
  58. data/public/node_modules/pivottable/examples/d3.html +49 -0
  59. data/public/node_modules/pivottable/examples/fully_loaded.html +80 -0
  60. data/public/node_modules/pivottable/examples/gchart.html +53 -0
  61. data/public/node_modules/pivottable/examples/gh-fork-ribbon.css +140 -0
  62. data/public/node_modules/pivottable/examples/gh-fork-ribbon.ie.css +78 -0
  63. data/public/node_modules/pivottable/examples/index.html +85 -0
  64. data/public/node_modules/pivottable/examples/local.html +74 -0
  65. data/public/node_modules/pivottable/examples/montreal_2014.csv +366 -0
  66. data/public/node_modules/pivottable/examples/montreal_2014.html +106 -0
  67. data/public/node_modules/pivottable/examples/mps.csv +309 -0
  68. data/public/node_modules/pivottable/examples/mps.html +45 -0
  69. data/public/node_modules/pivottable/examples/mps.json +1 -0
  70. data/public/node_modules/pivottable/examples/mps_agg.html +44 -0
  71. data/public/node_modules/pivottable/examples/mps_csv.html +42 -0
  72. data/public/node_modules/pivottable/examples/mps_export.html +44 -0
  73. data/public/node_modules/pivottable/examples/mps_fr.html +40 -0
  74. data/public/node_modules/pivottable/examples/mps_prepop.html +42 -0
  75. data/public/node_modules/pivottable/examples/onrefresh.html +52 -0
  76. data/public/node_modules/pivottable/examples/rcsvs.html +87 -0
  77. data/public/node_modules/pivottable/examples/scatter.html +53 -0
  78. data/public/node_modules/pivottable/examples/show_code.js +17 -0
  79. data/public/node_modules/pivottable/examples/simple.html +41 -0
  80. data/public/node_modules/pivottable/examples/simple_agg.html +51 -0
  81. data/public/node_modules/pivottable/examples/simple_function.html +57 -0
  82. data/public/node_modules/pivottable/examples/simple_ui.html +42 -0
  83. data/public/node_modules/pivottable/examples/simple_ui_from_table.html +60 -0
  84. data/public/node_modules/pivottable/export_renderers.coffee +57 -0
  85. data/public/node_modules/pivottable/gchart_renderers.coffee +111 -0
  86. data/public/node_modules/pivottable/gulpFile.js +95 -0
  87. data/public/node_modules/pivottable/images/animation.gif +0 -0
  88. data/public/node_modules/pivottable/images/filters.png +0 -0
  89. data/public/node_modules/pivottable/images/gender_age_bins.png +0 -0
  90. data/public/node_modules/pivottable/images/gender_imbalance.png +0 -0
  91. data/public/node_modules/pivottable/images/gender_imbalance_instructions.png +0 -0
  92. data/public/node_modules/pivottable/images/initial_state.png +0 -0
  93. data/public/node_modules/pivottable/images/province_x_party_heatmap.png +0 -0
  94. data/public/node_modules/pivottable/images/province_x_party_heatmap_instructions.png +0 -0
  95. data/public/node_modules/pivottable/images/simple.png +0 -0
  96. data/public/node_modules/pivottable/images/simple_ui.png +0 -0
  97. data/public/node_modules/pivottable/images/whats_what.png +0 -0
  98. data/public/node_modules/pivottable/index.html +14 -0
  99. data/public/node_modules/pivottable/node_modules/jquery/AUTHORS.txt +278 -0
  100. data/public/node_modules/pivottable/node_modules/jquery/LICENSE.txt +36 -0
  101. data/public/node_modules/pivottable/node_modules/jquery/README.md +65 -0
  102. data/public/node_modules/pivottable/node_modules/jquery/bower.json +14 -0
  103. data/public/node_modules/pivottable/node_modules/jquery/dist/jquery.js +9842 -0
  104. data/public/node_modules/pivottable/node_modules/jquery/dist/jquery.min.js +4 -0
  105. data/public/node_modules/pivottable/node_modules/jquery/dist/jquery.min.map +1 -0
  106. data/public/node_modules/pivottable/node_modules/jquery/dist/jquery.slim.js +7877 -0
  107. data/public/node_modules/pivottable/node_modules/jquery/dist/jquery.slim.min.js +4 -0
  108. data/public/node_modules/pivottable/node_modules/jquery/dist/jquery.slim.min.map +1 -0
  109. data/public/node_modules/pivottable/node_modules/jquery/package.json +122 -0
  110. data/public/node_modules/pivottable/node_modules/jquery/sizzle/LICENSE.txt +36 -0
  111. data/public/node_modules/pivottable/node_modules/jquery/sizzle/dist/sizzle.js +2143 -0
  112. data/public/node_modules/pivottable/node_modules/jquery/sizzle/dist/sizzle.min.js +3 -0
  113. data/public/node_modules/pivottable/node_modules/jquery/sizzle/dist/sizzle.min.map +1 -0
  114. data/public/node_modules/pivottable/node_modules/jquery/src/ajax.js +845 -0
  115. data/public/node_modules/pivottable/node_modules/jquery/src/ajax/jsonp.js +100 -0
  116. data/public/node_modules/pivottable/node_modules/jquery/src/ajax/load.js +83 -0
  117. data/public/node_modules/pivottable/node_modules/jquery/src/ajax/parseJSON.js +13 -0
  118. data/public/node_modules/pivottable/node_modules/jquery/src/ajax/parseXML.js +27 -0
  119. data/public/node_modules/pivottable/node_modules/jquery/src/ajax/script.js +68 -0
  120. data/public/node_modules/pivottable/node_modules/jquery/src/ajax/var/location.js +3 -0
  121. data/public/node_modules/pivottable/node_modules/jquery/src/ajax/var/nonce.js +5 -0
  122. data/public/node_modules/pivottable/node_modules/jquery/src/ajax/var/rquery.js +3 -0
  123. data/public/node_modules/pivottable/node_modules/jquery/src/ajax/xhr.js +167 -0
  124. data/public/node_modules/pivottable/node_modules/jquery/src/attributes.js +11 -0
  125. data/public/node_modules/pivottable/node_modules/jquery/src/attributes/attr.js +142 -0
  126. data/public/node_modules/pivottable/node_modules/jquery/src/attributes/classes.js +177 -0
  127. data/public/node_modules/pivottable/node_modules/jquery/src/attributes/prop.js +125 -0
  128. data/public/node_modules/pivottable/node_modules/jquery/src/attributes/support.js +36 -0
  129. data/public/node_modules/pivottable/node_modules/jquery/src/attributes/val.js +177 -0
  130. data/public/node_modules/pivottable/node_modules/jquery/src/callbacks.js +232 -0
  131. data/public/node_modules/pivottable/node_modules/jquery/src/core.js +494 -0
  132. data/public/node_modules/pivottable/node_modules/jquery/src/core/DOMEval.js +14 -0
  133. data/public/node_modules/pivottable/node_modules/jquery/src/core/access.js +65 -0
  134. data/public/node_modules/pivottable/node_modules/jquery/src/core/init.js +134 -0
  135. data/public/node_modules/pivottable/node_modules/jquery/src/core/parseHTML.js +41 -0
  136. data/public/node_modules/pivottable/node_modules/jquery/src/core/ready.js +103 -0
  137. data/public/node_modules/pivottable/node_modules/jquery/src/core/support.js +18 -0
  138. data/public/node_modules/pivottable/node_modules/jquery/src/core/var/rsingleTag.js +5 -0
  139. data/public/node_modules/pivottable/node_modules/jquery/src/css.js +515 -0
  140. data/public/node_modules/pivottable/node_modules/jquery/src/css/addGetHookIf.js +24 -0
  141. data/public/node_modules/pivottable/node_modules/jquery/src/css/adjustCSS.js +65 -0
  142. data/public/node_modules/pivottable/node_modules/jquery/src/css/curCSS.js +60 -0
  143. data/public/node_modules/pivottable/node_modules/jquery/src/css/defaultDisplay.js +72 -0
  144. data/public/node_modules/pivottable/node_modules/jquery/src/css/hiddenVisibleSelectors.js +18 -0
  145. data/public/node_modules/pivottable/node_modules/jquery/src/css/showHide.js +48 -0
  146. data/public/node_modules/pivottable/node_modules/jquery/src/css/support.js +121 -0
  147. data/public/node_modules/pivottable/node_modules/jquery/src/css/var/cssExpand.js +3 -0
  148. data/public/node_modules/pivottable/node_modules/jquery/src/css/var/getStyles.js +15 -0
  149. data/public/node_modules/pivottable/node_modules/jquery/src/css/var/isHidden.js +16 -0
  150. data/public/node_modules/pivottable/node_modules/jquery/src/css/var/rmargin.js +3 -0
  151. data/public/node_modules/pivottable/node_modules/jquery/src/css/var/rnumnonpx.js +5 -0
  152. data/public/node_modules/pivottable/node_modules/jquery/src/css/var/swap.js +24 -0
  153. data/public/node_modules/pivottable/node_modules/jquery/src/data.js +187 -0
  154. data/public/node_modules/pivottable/node_modules/jquery/src/data/Data.js +200 -0
  155. data/public/node_modules/pivottable/node_modules/jquery/src/data/accepts.js +20 -0
  156. data/public/node_modules/pivottable/node_modules/jquery/src/data/support.js +23 -0
  157. data/public/node_modules/pivottable/node_modules/jquery/src/data/var/acceptData.js +18 -0
  158. data/public/node_modules/pivottable/node_modules/jquery/src/data/var/dataPriv.js +5 -0
  159. data/public/node_modules/pivottable/node_modules/jquery/src/data/var/dataUser.js +5 -0
  160. data/public/node_modules/pivottable/node_modules/jquery/src/deferred.js +158 -0
  161. data/public/node_modules/pivottable/node_modules/jquery/src/deferred/exceptionHook.js +19 -0
  162. data/public/node_modules/pivottable/node_modules/jquery/src/deprecated.js +32 -0
  163. data/public/node_modules/pivottable/node_modules/jquery/src/dimensions.js +54 -0
  164. data/public/node_modules/pivottable/node_modules/jquery/src/effects.js +629 -0
  165. data/public/node_modules/pivottable/node_modules/jquery/src/effects/Tween.js +121 -0
  166. data/public/node_modules/pivottable/node_modules/jquery/src/effects/animatedSelector.js +13 -0
  167. data/public/node_modules/pivottable/node_modules/jquery/src/effects/support.js +58 -0
  168. data/public/node_modules/pivottable/node_modules/jquery/src/event.js +710 -0
  169. data/public/node_modules/pivottable/node_modules/jquery/src/event/ajax.js +20 -0
  170. data/public/node_modules/pivottable/node_modules/jquery/src/event/alias.js +27 -0
  171. data/public/node_modules/pivottable/node_modules/jquery/src/event/focusin.js +53 -0
  172. data/public/node_modules/pivottable/node_modules/jquery/src/event/support.js +9 -0
  173. data/public/node_modules/pivottable/node_modules/jquery/src/event/trigger.js +199 -0
  174. data/public/node_modules/pivottable/node_modules/jquery/src/exports/amd.js +24 -0
  175. data/public/node_modules/pivottable/node_modules/jquery/src/exports/global.js +26 -0
  176. data/public/node_modules/pivottable/node_modules/jquery/src/intro.js +44 -0
  177. data/public/node_modules/pivottable/node_modules/jquery/src/jquery.js +37 -0
  178. data/public/node_modules/pivottable/node_modules/jquery/src/manipulation.js +481 -0
  179. data/public/node_modules/pivottable/node_modules/jquery/src/manipulation/_evalUrl.js +20 -0
  180. data/public/node_modules/pivottable/node_modules/jquery/src/manipulation/buildFragment.js +102 -0
  181. data/public/node_modules/pivottable/node_modules/jquery/src/manipulation/createSafeFragment.js +20 -0
  182. data/public/node_modules/pivottable/node_modules/jquery/src/manipulation/getAll.js +21 -0
  183. data/public/node_modules/pivottable/node_modules/jquery/src/manipulation/setGlobalEval.js +20 -0
  184. data/public/node_modules/pivottable/node_modules/jquery/src/manipulation/support.js +33 -0
  185. data/public/node_modules/pivottable/node_modules/jquery/src/manipulation/var/nodeNames.js +5 -0
  186. data/public/node_modules/pivottable/node_modules/jquery/src/manipulation/var/rcheckableType.js +3 -0
  187. data/public/node_modules/pivottable/node_modules/jquery/src/manipulation/var/rleadingWhitespace.js +3 -0
  188. data/public/node_modules/pivottable/node_modules/jquery/src/manipulation/var/rscriptType.js +3 -0
  189. data/public/node_modules/pivottable/node_modules/jquery/src/manipulation/var/rtagName.js +3 -0
  190. data/public/node_modules/pivottable/node_modules/jquery/src/manipulation/wrapMap.js +27 -0
  191. data/public/node_modules/pivottable/node_modules/jquery/src/offset.js +218 -0
  192. data/public/node_modules/pivottable/node_modules/jquery/src/outro.js +2 -0
  193. data/public/node_modules/pivottable/node_modules/jquery/src/queue.js +143 -0
  194. data/public/node_modules/pivottable/node_modules/jquery/src/queue/delay.js +22 -0
  195. data/public/node_modules/pivottable/node_modules/jquery/src/selector-native.js +211 -0
  196. data/public/node_modules/pivottable/node_modules/jquery/src/selector-sizzle.js +14 -0
  197. data/public/node_modules/pivottable/node_modules/jquery/src/selector.js +1 -0
  198. data/public/node_modules/pivottable/node_modules/jquery/src/serialize.js +125 -0
  199. data/public/node_modules/pivottable/node_modules/jquery/src/support.js +63 -0
  200. data/public/node_modules/pivottable/node_modules/jquery/src/traversing.js +175 -0
  201. data/public/node_modules/pivottable/node_modules/jquery/src/traversing/findFilter.js +100 -0
  202. data/public/node_modules/pivottable/node_modules/jquery/src/traversing/var/dir.js +20 -0
  203. data/public/node_modules/pivottable/node_modules/jquery/src/traversing/var/rneedsContext.js +6 -0
  204. data/public/node_modules/pivottable/node_modules/jquery/src/traversing/var/siblings.js +15 -0
  205. data/public/node_modules/pivottable/node_modules/jquery/src/var/arr.js +3 -0
  206. data/public/node_modules/pivottable/node_modules/jquery/src/var/class2type.js +5 -0
  207. data/public/node_modules/pivottable/node_modules/jquery/src/var/concat.js +5 -0
  208. data/public/node_modules/pivottable/node_modules/jquery/src/var/deletedIds.js +3 -0
  209. data/public/node_modules/pivottable/node_modules/jquery/src/var/document.js +3 -0
  210. data/public/node_modules/pivottable/node_modules/jquery/src/var/documentElement.js +5 -0
  211. data/public/node_modules/pivottable/node_modules/jquery/src/var/hasOwn.js +5 -0
  212. data/public/node_modules/pivottable/node_modules/jquery/src/var/indexOf.js +5 -0
  213. data/public/node_modules/pivottable/node_modules/jquery/src/var/pnum.js +3 -0
  214. data/public/node_modules/pivottable/node_modules/jquery/src/var/push.js +5 -0
  215. data/public/node_modules/pivottable/node_modules/jquery/src/var/rcssNum.js +7 -0
  216. data/public/node_modules/pivottable/node_modules/jquery/src/var/rnotwhite.js +3 -0
  217. data/public/node_modules/pivottable/node_modules/jquery/src/var/slice.js +5 -0
  218. data/public/node_modules/pivottable/node_modules/jquery/src/var/support.js +5 -0
  219. data/public/node_modules/pivottable/node_modules/jquery/src/var/toString.js +5 -0
  220. data/public/node_modules/pivottable/node_modules/jquery/src/wrap.js +79 -0
  221. data/public/node_modules/pivottable/package.json +70 -0
  222. data/public/node_modules/pivottable/pivot.coffee +957 -0
  223. data/public/node_modules/pivottable/pivot.es.coffee +57 -0
  224. data/public/node_modules/pivottable/pivot.fr.coffee +57 -0
  225. data/public/node_modules/pivottable/pivot.nl.coffee +55 -0
  226. data/public/node_modules/pivottable/pivot.pt.coffee +80 -0
  227. data/public/node_modules/pivottable/pivot.ru.coffee +56 -0
  228. data/public/node_modules/pivottable/pivot.tr.coffee +80 -0
  229. data/public/node_modules/pivottable/pivottable.jquery.json +33 -0
  230. data/public/node_modules/pivottable/tests/boot.js +152 -0
  231. data/public/node_modules/pivottable/tests/index.html +35 -0
  232. data/public/node_modules/pivottable/tests/pivot_spec.coffee +458 -0
  233. data/public/vendor.js +5 -0
  234. metadata +232 -1
@@ -0,0 +1,7 @@
1
+ define( [
2
+ "../var/pnum"
3
+ ], function( pnum ) {
4
+
5
+ return new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" );
6
+
7
+ } );
@@ -0,0 +1,3 @@
1
+ define( function() {
2
+ return ( /\S+/g );
3
+ } );
@@ -0,0 +1,5 @@
1
+ define( [
2
+ "./arr"
3
+ ], function( arr ) {
4
+ return arr.slice;
5
+ } );
@@ -0,0 +1,5 @@
1
+ define( function() {
2
+
3
+ // All support tests are defined in their respective modules.
4
+ return {};
5
+ } );
@@ -0,0 +1,5 @@
1
+ define( [
2
+ "./class2type"
3
+ ], function( class2type ) {
4
+ return class2type.toString;
5
+ } );
@@ -0,0 +1,79 @@
1
+ define( [
2
+ "./core",
3
+ "./core/init",
4
+ "./manipulation", // clone
5
+ "./traversing" // parent, contents
6
+ ], function( jQuery ) {
7
+
8
+ jQuery.fn.extend( {
9
+ wrapAll: function( html ) {
10
+ var wrap;
11
+
12
+ if ( jQuery.isFunction( html ) ) {
13
+ return this.each( function( i ) {
14
+ jQuery( this ).wrapAll( html.call( this, i ) );
15
+ } );
16
+ }
17
+
18
+ if ( this[ 0 ] ) {
19
+
20
+ // The elements to wrap the target around
21
+ wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );
22
+
23
+ if ( this[ 0 ].parentNode ) {
24
+ wrap.insertBefore( this[ 0 ] );
25
+ }
26
+
27
+ wrap.map( function() {
28
+ var elem = this;
29
+
30
+ while ( elem.firstElementChild ) {
31
+ elem = elem.firstElementChild;
32
+ }
33
+
34
+ return elem;
35
+ } ).append( this );
36
+ }
37
+
38
+ return this;
39
+ },
40
+
41
+ wrapInner: function( html ) {
42
+ if ( jQuery.isFunction( html ) ) {
43
+ return this.each( function( i ) {
44
+ jQuery( this ).wrapInner( html.call( this, i ) );
45
+ } );
46
+ }
47
+
48
+ return this.each( function() {
49
+ var self = jQuery( this ),
50
+ contents = self.contents();
51
+
52
+ if ( contents.length ) {
53
+ contents.wrapAll( html );
54
+
55
+ } else {
56
+ self.append( html );
57
+ }
58
+ } );
59
+ },
60
+
61
+ wrap: function( html ) {
62
+ var isFunction = jQuery.isFunction( html );
63
+
64
+ return this.each( function( i ) {
65
+ jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html );
66
+ } );
67
+ },
68
+
69
+ unwrap: function() {
70
+ return this.parent().each( function() {
71
+ if ( !jQuery.nodeName( this, "body" ) ) {
72
+ jQuery( this ).replaceWith( this.childNodes );
73
+ }
74
+ } ).end();
75
+ }
76
+ } );
77
+
78
+ return jQuery;
79
+ } );
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "pivottable",
3
+ "version": "2.0.2",
4
+ "description": "Javascript Pivot Table (aka Pivot Grid, Pivot Chart, Cross-Tab) implementation with drag'n'drop",
5
+ "main": "dist/pivot.js",
6
+ "keywords": [
7
+ "pivot",
8
+ "crosstab",
9
+ "grid",
10
+ "table",
11
+ "pivottable",
12
+ "pivotgrid",
13
+ "pivotchart",
14
+ "jquery",
15
+ "jquery-plugin"
16
+ ],
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git://github.com/nicolaskruchten/pivottable.git"
20
+ },
21
+ "author": {
22
+ "name": "Nicolas Kruchten"
23
+ },
24
+ "license": "MIT",
25
+ "bugs": {
26
+ "url": "https://github.com/nicolaskruchten/pivottable/issues"
27
+ },
28
+ "homepage": "https://github.com/nicolaskruchten/pivottable",
29
+ "dependencies": {
30
+ "jquery": ">=1.9.0"
31
+ },
32
+ "devDependencies": {
33
+ "gulp-coffee": "^2.2.0",
34
+ "gulp-uglify": "^1.0.2",
35
+ "gulp-sourcemaps": "^1.2.8",
36
+ "gulp": "^3.8.10",
37
+ "run-sequence": "^1.0.2",
38
+ "gulp-tag-version": "^1.2.1",
39
+ "gulp-git": "^0.5.5",
40
+ "gulp-bump": "^0.1.11",
41
+ "gulp-filter": "^1.0.2",
42
+ "gulp-util": "^3.0.1",
43
+ "gulp-rename": "^1.2.0",
44
+ "gulp-minify-css": "^0.3.11",
45
+ "gulp-concat": "^2.4.2"
46
+ },
47
+ "gitHead": "a2f694fc3011471a7fe4d300c9f4b6c6edf1cffe",
48
+ "_id": "pivottable@2.0.2",
49
+ "scripts": {},
50
+ "_shasum": "901dea3a4a37fca6db4e1b658364bce803cf9380",
51
+ "_from": "pivottable@*",
52
+ "_npmVersion": "2.11.3",
53
+ "_nodeVersion": "0.12.7",
54
+ "_npmUser": {
55
+ "name": "nicolaskruchten",
56
+ "email": "nicolas@kruchten.com"
57
+ },
58
+ "dist": {
59
+ "shasum": "901dea3a4a37fca6db4e1b658364bce803cf9380",
60
+ "tarball": "https://registry.npmjs.org/pivottable/-/pivottable-2.0.2.tgz"
61
+ },
62
+ "maintainers": [
63
+ {
64
+ "name": "nicolaskruchten",
65
+ "email": "nicolas@kruchten.com"
66
+ }
67
+ ],
68
+ "directories": {},
69
+ "_resolved": "https://registry.npmjs.org/pivottable/-/pivottable-2.0.2.tgz"
70
+ }
@@ -0,0 +1,957 @@
1
+ callWithJQuery = (pivotModule) ->
2
+ if typeof exports is "object" and typeof module is "object" # CommonJS
3
+ pivotModule require("jquery")
4
+ else if typeof define is "function" and define.amd # AMD
5
+ define ["jquery"], pivotModule
6
+ # Plain browser env
7
+ else
8
+ pivotModule jQuery
9
+
10
+ callWithJQuery ($) ->
11
+
12
+ ###
13
+ Utilities
14
+ ###
15
+
16
+ addSeparators = (nStr, thousandsSep, decimalSep) ->
17
+ nStr += ''
18
+ x = nStr.split('.')
19
+ x1 = x[0]
20
+ x2 = if x.length > 1 then decimalSep + x[1] else ''
21
+ rgx = /(\d+)(\d{3})/
22
+ x1 = x1.replace(rgx, '$1' + thousandsSep + '$2') while rgx.test(x1)
23
+ return x1 + x2
24
+
25
+ numberFormat = (opts) ->
26
+ defaults =
27
+ digitsAfterDecimal: 2, scaler: 1,
28
+ thousandsSep: ",", decimalSep: "."
29
+ prefix: "", suffix: ""
30
+ showZero: false
31
+ opts = $.extend defaults, opts
32
+ (x) ->
33
+ return "" if isNaN(x) or not isFinite(x)
34
+ return "" if x == 0 and not opts.showZero
35
+ result = addSeparators (opts.scaler*x).toFixed(opts.digitsAfterDecimal), opts.thousandsSep, opts.decimalSep
36
+ return ""+opts.prefix+result+opts.suffix
37
+
38
+ #aggregator templates default to US number formatting but this is overrideable
39
+ usFmt = numberFormat()
40
+ usFmtInt = numberFormat(digitsAfterDecimal: 0)
41
+ usFmtPct = numberFormat(digitsAfterDecimal:1, scaler: 100, suffix: "%")
42
+
43
+ aggregatorTemplates =
44
+ count: (formatter=usFmtInt) -> () -> (data, rowKey, colKey) ->
45
+ count: 0
46
+ push: -> @count++
47
+ value: -> @count
48
+ format: formatter
49
+
50
+ countUnique: (formatter=usFmtInt) -> ([attr]) -> (data, rowKey, colKey) ->
51
+ uniq: []
52
+ push: (record) -> @uniq.push(record[attr]) if record[attr] not in @uniq
53
+ value: -> @uniq.length
54
+ format: formatter
55
+ numInputs: if attr? then 0 else 1
56
+
57
+ listUnique: (sep) -> ([attr]) -> (data, rowKey, colKey) ->
58
+ uniq: []
59
+ push: (record) -> @uniq.push(record[attr]) if record[attr] not in @uniq
60
+ value: -> @uniq.join sep
61
+ format: (x) -> x
62
+ numInputs: if attr? then 0 else 1
63
+
64
+ sum: (formatter=usFmt) -> ([attr]) -> (data, rowKey, colKey) ->
65
+ sum: 0
66
+ push: (record) -> @sum += parseFloat(record[attr]) if not isNaN parseFloat(record[attr])
67
+ value: -> @sum
68
+ format: formatter
69
+ numInputs: if attr? then 0 else 1
70
+
71
+ min: (formatter=usFmt) -> ([attr]) -> (data, rowKey, colKey) ->
72
+ val: null
73
+ push: (record) ->
74
+ x = parseFloat(record[attr])
75
+ if not isNaN x then @val = Math.min(x, @val ? x)
76
+ value: -> @val
77
+ format: formatter
78
+ numInputs: if attr? then 0 else 1
79
+
80
+ max: (formatter=usFmt) -> ([attr]) -> (data, rowKey, colKey) ->
81
+ val: null
82
+ push: (record) ->
83
+ x = parseFloat(record[attr])
84
+ if not isNaN x then @val = Math.max(x, @val ? x)
85
+ value: -> @val
86
+ format: formatter
87
+ numInputs: if attr? then 0 else 1
88
+
89
+ average: (formatter=usFmt) -> ([attr]) -> (data, rowKey, colKey) ->
90
+ sum: 0
91
+ len: 0
92
+ push: (record) ->
93
+ if not isNaN parseFloat(record[attr])
94
+ @sum += parseFloat(record[attr])
95
+ @len++
96
+ value: -> @sum/@len
97
+ format: formatter
98
+ numInputs: if attr? then 0 else 1
99
+
100
+ sumOverSum: (formatter=usFmt) -> ([num, denom]) -> (data, rowKey, colKey) ->
101
+ sumNum: 0
102
+ sumDenom: 0
103
+ push: (record) ->
104
+ @sumNum += parseFloat(record[num]) if not isNaN parseFloat(record[num])
105
+ @sumDenom += parseFloat(record[denom]) if not isNaN parseFloat(record[denom])
106
+ value: -> @sumNum/@sumDenom
107
+ format: formatter
108
+ numInputs: if num? and denom? then 0 else 2
109
+
110
+ sumOverSumBound80: (upper=true, formatter=usFmt) -> ([num, denom]) -> (data, rowKey, colKey) ->
111
+ sumNum: 0
112
+ sumDenom: 0
113
+ push: (record) ->
114
+ @sumNum += parseFloat(record[num]) if not isNaN parseFloat(record[num])
115
+ @sumDenom += parseFloat(record[denom]) if not isNaN parseFloat(record[denom])
116
+ value: ->
117
+ sign = if upper then 1 else -1
118
+ (0.821187207574908/@sumDenom + @sumNum/@sumDenom + 1.2815515655446004*sign*
119
+ Math.sqrt(0.410593603787454/ (@sumDenom*@sumDenom) + (@sumNum*(1 - @sumNum/ @sumDenom))/ (@sumDenom*@sumDenom)))/
120
+ (1 + 1.642374415149816/@sumDenom)
121
+ format: formatter
122
+ numInputs: if num? and denom? then 0 else 2
123
+
124
+ fractionOf: (wrapped, type="total", formatter=usFmtPct) -> (x...) -> (data, rowKey, colKey) ->
125
+ selector: {total:[[],[]],row:[rowKey,[]],col:[[],colKey]}[type]
126
+ inner: wrapped(x...)(data, rowKey, colKey)
127
+ push: (record) -> @inner.push record
128
+ format: formatter
129
+ value: -> @inner.value() / data.getAggregator(@selector...).inner.value()
130
+ numInputs: wrapped(x...)().numInputs
131
+
132
+ #default aggregators & renderers use US naming and number formatting
133
+ aggregators = do (tpl = aggregatorTemplates) ->
134
+ "Count": tpl.count(usFmtInt)
135
+ "Count Unique Values": tpl.countUnique(usFmtInt)
136
+ "List Unique Values": tpl.listUnique(", ")
137
+ "Sum": tpl.sum(usFmt)
138
+ "Integer Sum": tpl.sum(usFmtInt)
139
+ "Average": tpl.average(usFmt)
140
+ "Minimum": tpl.min(usFmt)
141
+ "Maximum": tpl.max(usFmt)
142
+ "Sum over Sum": tpl.sumOverSum(usFmt)
143
+ "80% Upper Bound": tpl.sumOverSumBound80(true, usFmt)
144
+ "80% Lower Bound": tpl.sumOverSumBound80(false, usFmt)
145
+ "Sum as Fraction of Total": tpl.fractionOf(tpl.sum(), "total", usFmtPct)
146
+ "Sum as Fraction of Rows": tpl.fractionOf(tpl.sum(), "row", usFmtPct)
147
+ "Sum as Fraction of Columns": tpl.fractionOf(tpl.sum(), "col", usFmtPct)
148
+ "Count as Fraction of Total": tpl.fractionOf(tpl.count(), "total", usFmtPct)
149
+ "Count as Fraction of Rows": tpl.fractionOf(tpl.count(), "row", usFmtPct)
150
+ "Count as Fraction of Columns": tpl.fractionOf(tpl.count(), "col", usFmtPct)
151
+
152
+ renderers =
153
+ "Table": (pvtData, opts) -> pivotTableRenderer(pvtData, opts)
154
+ "Table Barchart": (pvtData, opts) -> $(pivotTableRenderer(pvtData, opts)).barchart()
155
+ "Heatmap": (pvtData, opts) -> $(pivotTableRenderer(pvtData, opts)).heatmap()
156
+ "Row Heatmap": (pvtData, opts) -> $(pivotTableRenderer(pvtData, opts)).heatmap("rowheatmap")
157
+ "Col Heatmap": (pvtData, opts) -> $(pivotTableRenderer(pvtData, opts)).heatmap("colheatmap")
158
+
159
+ locales =
160
+ en:
161
+ aggregators: aggregators
162
+ renderers: renderers
163
+ localeStrings:
164
+ renderError: "An error occurred rendering the PivotTable results."
165
+ computeError: "An error occurred computing the PivotTable results."
166
+ uiRenderError: "An error occurred rendering the PivotTable UI."
167
+ selectAll: "Select All"
168
+ selectNone: "Select None"
169
+ tooMany: "(too many to list)"
170
+ filterResults: "Filter results"
171
+ totals: "Totals" #for table renderer
172
+ vs: "vs" #for gchart renderer
173
+ by: "by" #for gchart renderer
174
+
175
+ #dateFormat deriver l10n requires month and day names to be passed in directly
176
+ mthNamesEn = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]
177
+ dayNamesEn = ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"]
178
+ zeroPad = (number) -> ("0"+number).substr(-2,2)
179
+
180
+ derivers =
181
+ bin: (col, binWidth) -> (record) -> record[col] - record[col] % binWidth
182
+ dateFormat: (col, formatString, utcOutput=false, mthNames=mthNamesEn, dayNames=dayNamesEn) ->
183
+ utc = if utcOutput then "UTC" else ""
184
+ (record) -> #thanks http://stackoverflow.com/a/12213072/112871
185
+ date = new Date(Date.parse(record[col]))
186
+ if isNaN(date) then return ""
187
+ formatString.replace /%(.)/g, (m, p) ->
188
+ switch p
189
+ when "y" then date["get#{utc}FullYear"]()
190
+ when "m" then zeroPad(date["get#{utc}Month"]()+1)
191
+ when "n" then mthNames[date["get#{utc}Month"]()]
192
+ when "d" then zeroPad(date["get#{utc}Date"]())
193
+ when "w" then dayNames[date["get#{utc}Day"]()]
194
+ when "x" then date["get#{utc}Day"]()
195
+ when "H" then zeroPad(date["get#{utc}Hours"]())
196
+ when "M" then zeroPad(date["get#{utc}Minutes"]())
197
+ when "S" then zeroPad(date["get#{utc}Seconds"]())
198
+ else "%" + p
199
+
200
+ naturalSort = (as, bs) => #thanks http://stackoverflow.com/a/4373421/112871
201
+ rx = /(\d+)|(\D+)/g
202
+ rd = /\d/
203
+ rz = /^0/
204
+ if typeof as is "number" or typeof bs is "number"
205
+ return 1 if isNaN(as)
206
+ return -1 if isNaN(bs)
207
+ return as - bs
208
+ a = String(as).toLowerCase()
209
+ b = String(bs).toLowerCase()
210
+ return 0 if a is b
211
+ return (if a > b then 1 else -1) unless rd.test(a) and rd.test(b)
212
+ a = a.match(rx)
213
+ b = b.match(rx)
214
+ while a.length and b.length
215
+ a1 = a.shift()
216
+ b1 = b.shift()
217
+ if a1 isnt b1
218
+ if rd.test(a1) and rd.test(b1)
219
+ return a1.replace(rz, ".0") - b1.replace(rz, ".0")
220
+ else
221
+ return (if a1 > b1 then 1 else -1)
222
+ a.length - b.length
223
+
224
+ sortAs = (order) ->
225
+ mapping = {}
226
+ for i, x of order
227
+ mapping[x] = i
228
+ (a, b) ->
229
+ if mapping[a]? and mapping[b]?
230
+ return mapping[a] - mapping[b]
231
+ else if mapping[a]?
232
+ return -1
233
+ else if mapping[b]?
234
+ return 1
235
+ else
236
+ return naturalSort(a,b)
237
+
238
+ getSort = (sorters, attr) ->
239
+ sort = sorters(attr)
240
+ if $.isFunction(sort)
241
+ return sort
242
+ else
243
+ return naturalSort
244
+
245
+ ###
246
+ Data Model class
247
+ ###
248
+
249
+ class PivotData
250
+ constructor: (input, opts) ->
251
+ @aggregator = opts.aggregator
252
+ @aggregatorName = opts.aggregatorName
253
+ @colAttrs = opts.cols
254
+ @rowAttrs = opts.rows
255
+ @valAttrs = opts.vals
256
+ @sorters = opts.sorters
257
+ @tree = {}
258
+ @rowKeys = []
259
+ @colKeys = []
260
+ @rowTotals = {}
261
+ @colTotals = {}
262
+ @allTotal = @aggregator(this, [], [])
263
+ @sorted = false
264
+
265
+ # iterate through input, accumulating data for cells
266
+ PivotData.forEachRecord input, opts.derivedAttributes, (record) =>
267
+ @processRecord(record) if opts.filter(record)
268
+
269
+ #can handle arrays or jQuery selections of tables
270
+ @forEachRecord = (input, derivedAttributes, f) ->
271
+ if $.isEmptyObject derivedAttributes
272
+ addRecord = f
273
+ else
274
+ addRecord = (record) ->
275
+ record[k] = v(record) ? record[k] for k, v of derivedAttributes
276
+ f(record)
277
+
278
+ #if it's a function, have it call us back
279
+ if $.isFunction(input)
280
+ input(addRecord)
281
+ else if $.isArray(input)
282
+ if $.isArray(input[0]) #array of arrays
283
+ for own i, compactRecord of input when i > 0
284
+ record = {}
285
+ record[k] = compactRecord[j] for own j, k of input[0]
286
+ addRecord(record)
287
+ else #array of objects
288
+ addRecord(record) for record in input
289
+ else if input instanceof jQuery
290
+ tblCols = []
291
+ $("thead > tr > th", input).each (i) -> tblCols.push $(this).text()
292
+ $("tbody > tr", input).each (i) ->
293
+ record = {}
294
+ $("td", this).each (j) -> record[tblCols[j]] = $(this).text()
295
+ addRecord(record)
296
+ else
297
+ throw new Error("unknown input format")
298
+
299
+ #converts to [{attr:val, attr:val},{attr:val, attr:val}] using method above
300
+ @convertToArray = (input) ->
301
+ result = []
302
+ PivotData.forEachRecord input, {}, (record) -> result.push record
303
+ return result
304
+
305
+ arrSort: (attrs) =>
306
+ sortersArr = (getSort(@sorters, a) for a in attrs)
307
+ (a,b) ->
308
+ for own i, sorter of sortersArr
309
+ comparison = sorter(a[i], b[i])
310
+ return comparison if comparison != 0
311
+ return 0
312
+
313
+ sortKeys: () =>
314
+ if not @sorted
315
+ @sorted = true
316
+ @rowKeys.sort @arrSort(@rowAttrs)
317
+ @colKeys.sort @arrSort(@colAttrs)
318
+
319
+ getColKeys: () =>
320
+ @sortKeys()
321
+ return @colKeys
322
+
323
+ getRowKeys: () =>
324
+ @sortKeys()
325
+ return @rowKeys
326
+
327
+ processRecord: (record) -> #this code is called in a tight loop
328
+ colKey = []
329
+ rowKey = []
330
+ colKey.push record[x] ? "null" for x in @colAttrs
331
+ rowKey.push record[x] ? "null" for x in @rowAttrs
332
+ flatRowKey = rowKey.join(String.fromCharCode(0))
333
+ flatColKey = colKey.join(String.fromCharCode(0))
334
+
335
+ @allTotal.push record
336
+
337
+ if rowKey.length != 0
338
+ if not @rowTotals[flatRowKey]
339
+ @rowKeys.push rowKey
340
+ @rowTotals[flatRowKey] = @aggregator(this, rowKey, [])
341
+ @rowTotals[flatRowKey].push record
342
+
343
+ if colKey.length != 0
344
+ if not @colTotals[flatColKey]
345
+ @colKeys.push colKey
346
+ @colTotals[flatColKey] = @aggregator(this, [], colKey)
347
+ @colTotals[flatColKey].push record
348
+
349
+ if colKey.length != 0 and rowKey.length != 0
350
+ if not @tree[flatRowKey]
351
+ @tree[flatRowKey] = {}
352
+ if not @tree[flatRowKey][flatColKey]
353
+ @tree[flatRowKey][flatColKey] = @aggregator(this, rowKey, colKey)
354
+ @tree[flatRowKey][flatColKey].push record
355
+
356
+ getAggregator: (rowKey, colKey) =>
357
+ flatRowKey = rowKey.join(String.fromCharCode(0))
358
+ flatColKey = colKey.join(String.fromCharCode(0))
359
+ if rowKey.length == 0 and colKey.length == 0
360
+ agg = @allTotal
361
+ else if rowKey.length == 0
362
+ agg = @colTotals[flatColKey]
363
+ else if colKey.length == 0
364
+ agg = @rowTotals[flatRowKey]
365
+ else
366
+ agg = @tree[flatRowKey][flatColKey]
367
+ return agg ? {value: (-> null), format: -> ""}
368
+
369
+ #expose these to the outside world
370
+ $.pivotUtilities = {aggregatorTemplates, aggregators, renderers, derivers, locales,
371
+ naturalSort, numberFormat, sortAs, PivotData}
372
+
373
+ ###
374
+ Default Renderer for hierarchical table layout
375
+ ###
376
+
377
+ pivotTableRenderer = (pivotData, opts) ->
378
+
379
+ defaults =
380
+ localeStrings:
381
+ totals: "Totals"
382
+
383
+ opts = $.extend defaults, opts
384
+
385
+ colAttrs = pivotData.colAttrs
386
+ rowAttrs = pivotData.rowAttrs
387
+ rowKeys = pivotData.getRowKeys()
388
+ colKeys = pivotData.getColKeys()
389
+
390
+ #now actually build the output
391
+ result = document.createElement("table")
392
+ result.className = "pvtTable"
393
+
394
+ #helper function for setting row/col-span in pivotTableRenderer
395
+ spanSize = (arr, i, j) ->
396
+ if i != 0
397
+ noDraw = true
398
+ for x in [0..j]
399
+ if arr[i-1][x] != arr[i][x]
400
+ noDraw = false
401
+ if noDraw
402
+ return -1 #do not draw cell
403
+ len = 0
404
+ while i+len < arr.length
405
+ stop = false
406
+ for x in [0..j]
407
+ stop = true if arr[i][x] != arr[i+len][x]
408
+ break if stop
409
+ len++
410
+ return len
411
+
412
+ #the first few rows are for col headers
413
+ for own j, c of colAttrs
414
+ tr = document.createElement("tr")
415
+ if parseInt(j) == 0 and rowAttrs.length != 0
416
+ th = document.createElement("th")
417
+ th.setAttribute("colspan", rowAttrs.length)
418
+ th.setAttribute("rowspan", colAttrs.length)
419
+ tr.appendChild th
420
+ th = document.createElement("th")
421
+ th.className = "pvtAxisLabel"
422
+ th.textContent = c
423
+ tr.appendChild th
424
+ for own i, colKey of colKeys
425
+ x = spanSize(colKeys, parseInt(i), parseInt(j))
426
+ if x != -1
427
+ th = document.createElement("th")
428
+ th.className = "pvtColLabel"
429
+ th.textContent = colKey[j]
430
+ th.setAttribute("colspan", x)
431
+ if parseInt(j) == colAttrs.length-1 and rowAttrs.length != 0
432
+ th.setAttribute("rowspan", 2)
433
+ tr.appendChild th
434
+ if parseInt(j) == 0
435
+ th = document.createElement("th")
436
+ th.className = "pvtTotalLabel"
437
+ th.innerHTML = opts.localeStrings.totals
438
+ th.setAttribute("rowspan", colAttrs.length + (if rowAttrs.length ==0 then 0 else 1))
439
+ tr.appendChild th
440
+ result.appendChild tr
441
+
442
+ #then a row for row header headers
443
+ if rowAttrs.length !=0
444
+ tr = document.createElement("tr")
445
+ for own i, r of rowAttrs
446
+ th = document.createElement("th")
447
+ th.className = "pvtAxisLabel"
448
+ th.textContent = r
449
+ tr.appendChild th
450
+ th = document.createElement("th")
451
+ if colAttrs.length ==0
452
+ th.className = "pvtTotalLabel"
453
+ th.innerHTML = opts.localeStrings.totals
454
+ tr.appendChild th
455
+ result.appendChild tr
456
+
457
+ #now the actual data rows, with their row headers and totals
458
+ for own i, rowKey of rowKeys
459
+ tr = document.createElement("tr")
460
+ for own j, txt of rowKey
461
+ x = spanSize(rowKeys, parseInt(i), parseInt(j))
462
+ if x != -1
463
+ th = document.createElement("th")
464
+ th.className = "pvtRowLabel"
465
+ th.textContent = txt
466
+ th.setAttribute("rowspan", x)
467
+ if parseInt(j) == rowAttrs.length-1 and colAttrs.length !=0
468
+ th.setAttribute("colspan",2)
469
+ tr.appendChild th
470
+ for own j, colKey of colKeys #this is the tight loop
471
+ aggregator = pivotData.getAggregator(rowKey, colKey)
472
+ val = aggregator.value()
473
+ td = document.createElement("td")
474
+ td.className = "pvtVal row#{i} col#{j}"
475
+ td.textContent = aggregator.format(val)
476
+ td.setAttribute("data-value", val)
477
+ tr.appendChild td
478
+
479
+ totalAggregator = pivotData.getAggregator(rowKey, [])
480
+ val = totalAggregator.value()
481
+ td = document.createElement("td")
482
+ td.className = "pvtTotal rowTotal"
483
+ td.textContent = totalAggregator.format(val)
484
+ td.setAttribute("data-value", val)
485
+ td.setAttribute("data-for", "row"+i)
486
+ tr.appendChild td
487
+ result.appendChild tr
488
+
489
+ #finally, the row for col totals, and a grand total
490
+ tr = document.createElement("tr")
491
+ th = document.createElement("th")
492
+ th.className = "pvtTotalLabel"
493
+ th.innerHTML = opts.localeStrings.totals
494
+ th.setAttribute("colspan", rowAttrs.length + (if colAttrs.length == 0 then 0 else 1))
495
+ tr.appendChild th
496
+ for own j, colKey of colKeys
497
+ totalAggregator = pivotData.getAggregator([], colKey)
498
+ val = totalAggregator.value()
499
+ td = document.createElement("td")
500
+ td.className = "pvtTotal colTotal"
501
+ td.textContent = totalAggregator.format(val)
502
+ td.setAttribute("data-value", val)
503
+ td.setAttribute("data-for", "col"+j)
504
+ tr.appendChild td
505
+ totalAggregator = pivotData.getAggregator([], [])
506
+ val = totalAggregator.value()
507
+ td = document.createElement("td")
508
+ td.className = "pvtGrandTotal"
509
+ td.textContent = totalAggregator.format(val)
510
+ td.setAttribute("data-value", val)
511
+ tr.appendChild td
512
+ result.appendChild tr
513
+
514
+ #squirrel this away for later
515
+ result.setAttribute("data-numrows", rowKeys.length)
516
+ result.setAttribute("data-numcols", colKeys.length)
517
+
518
+ return result
519
+
520
+ ###
521
+ Pivot Table core: create PivotData object and call Renderer on it
522
+ ###
523
+
524
+ $.fn.pivot = (input, opts) ->
525
+ defaults =
526
+ cols : []
527
+ rows: []
528
+ vals: []
529
+ filter: -> true
530
+ aggregator: aggregatorTemplates.count()()
531
+ aggregatorName: "Count"
532
+ sorters: ->
533
+ derivedAttributes: {},
534
+ renderer: pivotTableRenderer
535
+ rendererOptions: null
536
+ localeStrings: locales.en.localeStrings
537
+
538
+ opts = $.extend defaults, opts
539
+
540
+ result = null
541
+ try
542
+ pivotData = new PivotData(input, opts)
543
+ try
544
+ result = opts.renderer(pivotData, opts.rendererOptions)
545
+ catch e
546
+ console.error(e.stack) if console?
547
+ result = $("<span>").html opts.localeStrings.renderError
548
+ catch e
549
+ console.error(e.stack) if console?
550
+ result = $("<span>").html opts.localeStrings.computeError
551
+
552
+ x = this[0]
553
+ x.removeChild(x.lastChild) while x.hasChildNodes()
554
+ return @append result
555
+
556
+
557
+ ###
558
+ Pivot Table UI: calls Pivot Table core above with options set by user
559
+ ###
560
+
561
+ $.fn.pivotUI = (input, inputOpts, overwrite = false, locale="en") ->
562
+ if not locales[locale]?
563
+ locale = "en"
564
+ defaults =
565
+ derivedAttributes: {}
566
+ aggregators: locales[locale].aggregators
567
+ renderers: locales[locale].renderers
568
+ hiddenAttributes: []
569
+ menuLimit: 200
570
+ cols: [], rows: [], vals: []
571
+ exclusions: {}
572
+ inclusions: {}
573
+ unusedAttrsVertical: 85
574
+ autoSortUnusedAttrs: false
575
+ rendererOptions: localeStrings: locales[locale].localeStrings
576
+ onRefresh: null
577
+ filter: -> true
578
+ sorters: ->
579
+ localeStrings: locales[locale].localeStrings
580
+
581
+ existingOpts = @data "pivotUIOptions"
582
+ if not existingOpts? or overwrite
583
+ opts = $.extend defaults, inputOpts
584
+ else
585
+ opts = existingOpts
586
+
587
+ try
588
+ #cache the input in some useful form
589
+ input = PivotData.convertToArray(input)
590
+ tblCols = (k for own k of input[0])
591
+ tblCols.push c for own c of opts.derivedAttributes when (c not in tblCols)
592
+
593
+ #figure out the cardinality and some stats
594
+ axisValues = {}
595
+ axisValues[x] = {} for x in tblCols
596
+
597
+ PivotData.forEachRecord input, opts.derivedAttributes, (record) ->
598
+ for own k, v of record when opts.filter(record)
599
+ v ?= "null"
600
+ axisValues[k][v] ?= 0
601
+ axisValues[k][v]++
602
+
603
+ #start building the output
604
+ uiTable = $("<table>", "class": "pvtUi").attr("cellpadding", 5)
605
+
606
+ #renderer control
607
+ rendererControl = $("<td>")
608
+
609
+ renderer = $("<select>")
610
+ .addClass('pvtRenderer')
611
+ .appendTo(rendererControl)
612
+ .bind "change", -> refresh() #capture reference
613
+ for own x of opts.renderers
614
+ $("<option>").val(x).html(x).appendTo(renderer)
615
+
616
+
617
+ #axis list, including the double-click menu
618
+ colList = $("<td>").addClass('pvtAxisContainer pvtUnused')
619
+ shownAttributes = (c for c in tblCols when c not in opts.hiddenAttributes)
620
+
621
+ unusedAttrsVerticalAutoOverride = false
622
+ if opts.unusedAttrsVertical == "auto"
623
+ unusedAttrsVerticalAutoCutoff = 120 # legacy support
624
+ else
625
+ unusedAttrsVerticalAutoCutoff = parseInt opts.unusedAttrsVertical
626
+
627
+ if not isNaN(unusedAttrsVerticalAutoCutoff)
628
+ attrLength = 0
629
+ attrLength += a.length for a in shownAttributes
630
+ unusedAttrsVerticalAutoOverride = attrLength > unusedAttrsVerticalAutoCutoff
631
+
632
+ if opts.unusedAttrsVertical == true or unusedAttrsVerticalAutoOverride
633
+ colList.addClass('pvtVertList')
634
+ else
635
+ colList.addClass('pvtHorizList')
636
+
637
+ for own i, c of shownAttributes
638
+ do (c) ->
639
+ keys = (k for k of axisValues[c])
640
+ hasExcludedItem = false
641
+ valueList = $("<div>").addClass('pvtFilterBox').hide()
642
+
643
+ valueList.append $("<h4>").text("#{c} (#{keys.length})")
644
+ if keys.length > opts.menuLimit
645
+ valueList.append $("<p>").html(opts.localeStrings.tooMany)
646
+ else
647
+ btns = $("<p>").appendTo(valueList)
648
+ btns.append $("<button>", {type:"button"}).html(opts.localeStrings.selectAll).bind "click", ->
649
+ valueList.find("input:visible").prop "checked", true
650
+ btns.append $("<button>", {type:"button"}).html(opts.localeStrings.selectNone).bind "click", ->
651
+ valueList.find("input:visible").prop "checked", false
652
+ btns.append $("<br>")
653
+ btns.append $("<input>", {type: "text", placeholder: opts.localeStrings.filterResults, class: "pvtSearch"}).bind "keyup", ->
654
+ filter = $(this).val().toLowerCase()
655
+ valueList.find('.pvtCheckContainer p').each ->
656
+ testString = $(this).text().toLowerCase().indexOf(filter)
657
+ if testString isnt -1
658
+ $(this).show()
659
+ else
660
+ $(this).hide()
661
+
662
+ checkContainer = $("<div>").addClass("pvtCheckContainer").appendTo(valueList)
663
+
664
+ for k in keys.sort(getSort(opts.sorters, c))
665
+ v = axisValues[c][k]
666
+ filterItem = $("<label>")
667
+ filterItemExcluded = false
668
+ if opts.inclusions[c]
669
+ filterItemExcluded = (k not in opts.inclusions[c])
670
+ else if opts.exclusions[c]
671
+ filterItemExcluded = (k in opts.exclusions[c])
672
+ hasExcludedItem ||= filterItemExcluded
673
+ $("<input>")
674
+ .attr("type", "checkbox").addClass('pvtFilter')
675
+ .attr("checked", !filterItemExcluded).data("filter", [c,k])
676
+ .appendTo filterItem
677
+ filterItem.append $("<span>").text k
678
+ filterItem.append $("<span>").text " ("+v+")"
679
+ checkContainer.append $("<p>").append(filterItem)
680
+
681
+ updateFilter = ->
682
+ unselectedCount = valueList.find("[type='checkbox']").length -
683
+ valueList.find("[type='checkbox']:checked").length
684
+ if unselectedCount > 0
685
+ attrElem.addClass "pvtFilteredAttribute"
686
+ else
687
+ attrElem.removeClass "pvtFilteredAttribute"
688
+ if keys.length > opts.menuLimit
689
+ valueList.toggle()
690
+ else
691
+ valueList.toggle(0, refresh)
692
+
693
+ $("<p>").appendTo(valueList)
694
+ .append $("<button>", {type:"button"}).text("OK").bind "click", updateFilter
695
+
696
+ showFilterList = (e) ->
697
+ {left: clickLeft, top: clickTop, } = $(e.currentTarget).position()
698
+ valueList.css(left: clickLeft+10, top: clickTop+10).toggle()
699
+ valueList.find('.pvtSearch').val('')
700
+ valueList.find('.pvtCheckContainer p').show()
701
+
702
+ triangleLink = $("<span>").addClass('pvtTriangle').html(" &#x25BE;")
703
+ .bind "click", showFilterList
704
+
705
+ attrElem = $("<li>").addClass("axis_#{i}")
706
+ .append $("<span>").addClass('pvtAttr').text(c).data("attrName", c).append(triangleLink)
707
+ attrElem.addClass('pvtFilteredAttribute') if hasExcludedItem
708
+ colList.append(attrElem).append(valueList)
709
+
710
+ attrElem.bind "dblclick", showFilterList
711
+
712
+ tr1 = $("<tr>").appendTo(uiTable)
713
+
714
+ #aggregator menu and value area
715
+
716
+ aggregator = $("<select>").addClass('pvtAggregator')
717
+ .bind "change", -> refresh() #capture reference
718
+ for own x of opts.aggregators
719
+ aggregator.append $("<option>").val(x).html(x)
720
+
721
+ $("<td>").addClass('pvtVals')
722
+ .appendTo(tr1)
723
+ .append(aggregator)
724
+ .append($("<br>"))
725
+
726
+ #column axes
727
+ $("<td>").addClass('pvtAxisContainer pvtHorizList pvtCols').appendTo(tr1)
728
+
729
+ tr2 = $("<tr>").appendTo(uiTable)
730
+
731
+ #row axes
732
+ tr2.append $("<td>").addClass('pvtAxisContainer pvtRows').attr("valign", "top")
733
+
734
+ #the actual pivot table container
735
+ pivotTable = $("<td>")
736
+ .attr("valign", "top")
737
+ .addClass('pvtRendererArea')
738
+ .appendTo(tr2)
739
+
740
+ #finally the renderer dropdown and unused attribs are inserted at the requested location
741
+ if opts.unusedAttrsVertical == true or unusedAttrsVerticalAutoOverride
742
+ uiTable.find('tr:nth-child(1)').prepend rendererControl
743
+ uiTable.find('tr:nth-child(2)').prepend colList
744
+ else
745
+ uiTable.prepend $("<tr>").append(rendererControl).append(colList)
746
+
747
+ #render the UI in its default state
748
+ @html uiTable
749
+
750
+ #set up the UI initial state as requested by moving elements around
751
+
752
+ for x in opts.cols
753
+ @find(".pvtCols").append @find(".axis_#{$.inArray(x, shownAttributes)}")
754
+ for x in opts.rows
755
+ @find(".pvtRows").append @find(".axis_#{$.inArray(x, shownAttributes)}")
756
+ if opts.aggregatorName?
757
+ @find(".pvtAggregator").val opts.aggregatorName
758
+ if opts.rendererName?
759
+ @find(".pvtRenderer").val opts.rendererName
760
+
761
+ initialRender = true
762
+
763
+ #set up for refreshing
764
+ refreshDelayed = =>
765
+ subopts =
766
+ derivedAttributes: opts.derivedAttributes
767
+ localeStrings: opts.localeStrings
768
+ rendererOptions: opts.rendererOptions
769
+ sorters: opts.sorters
770
+ cols: [], rows: []
771
+
772
+ numInputsToProcess = opts.aggregators[aggregator.val()]([])().numInputs ? 0
773
+ vals = []
774
+ @find(".pvtRows li span.pvtAttr").each -> subopts.rows.push $(this).data("attrName")
775
+ @find(".pvtCols li span.pvtAttr").each -> subopts.cols.push $(this).data("attrName")
776
+ @find(".pvtVals select.pvtAttrDropdown").each ->
777
+ if numInputsToProcess == 0
778
+ $(this).remove()
779
+ else
780
+ numInputsToProcess--
781
+ vals.push $(this).val() if $(this).val() != ""
782
+
783
+ if numInputsToProcess != 0
784
+ pvtVals = @find(".pvtVals")
785
+ for x in [0...numInputsToProcess]
786
+ newDropdown = $("<select>")
787
+ .addClass('pvtAttrDropdown')
788
+ .append($("<option>"))
789
+ .bind "change", -> refresh()
790
+ for attr in shownAttributes
791
+ newDropdown.append($("<option>").val(attr).text(attr))
792
+ pvtVals.append(newDropdown)
793
+
794
+ if initialRender
795
+ vals = opts.vals
796
+ i = 0
797
+ @find(".pvtVals select.pvtAttrDropdown").each ->
798
+ $(this).val vals[i]
799
+ i++
800
+ initialRender = false
801
+
802
+ subopts.aggregatorName = aggregator.val()
803
+ subopts.vals = vals
804
+ subopts.aggregator = opts.aggregators[aggregator.val()](vals)
805
+ subopts.renderer = opts.renderers[renderer.val()]
806
+
807
+ #construct filter here
808
+ exclusions = {}
809
+ @find('input.pvtFilter').not(':checked').each ->
810
+ filter = $(this).data("filter")
811
+ if exclusions[filter[0]]?
812
+ exclusions[filter[0]].push( filter[1] )
813
+ else
814
+ exclusions[filter[0]] = [ filter[1] ]
815
+ #include inclusions when exclusions present
816
+ inclusions = {}
817
+ @find('input.pvtFilter:checked').each ->
818
+ filter = $(this).data("filter")
819
+ if exclusions[filter[0]]?
820
+ if inclusions[filter[0]]?
821
+ inclusions[filter[0]].push( filter[1] )
822
+ else
823
+ inclusions[filter[0]] = [ filter[1] ]
824
+
825
+ subopts.filter = (record) ->
826
+ return false if not opts.filter(record)
827
+ for k,excludedItems of exclusions
828
+ return false if ""+record[k] in excludedItems
829
+ return true
830
+
831
+ pivotTable.pivot(input,subopts)
832
+ pivotUIOptions = $.extend opts,
833
+ cols: subopts.cols
834
+ rows: subopts.rows
835
+ vals: vals
836
+ exclusions: exclusions
837
+ inclusions: inclusions
838
+ inclusionsInfo: inclusions #duplicated for backwards-compatibility
839
+ aggregatorName: aggregator.val()
840
+ rendererName: renderer.val()
841
+
842
+ @data "pivotUIOptions", pivotUIOptions
843
+
844
+ # if requested make sure unused columns are in alphabetical order
845
+ if opts.autoSortUnusedAttrs
846
+ unusedAttrsContainer = @find("td.pvtUnused.pvtAxisContainer")
847
+ $(unusedAttrsContainer).children("li")
848
+ .sort((a, b) => naturalSort($(a).text(), $(b).text()))
849
+ .appendTo unusedAttrsContainer
850
+
851
+ pivotTable.css("opacity", 1)
852
+ opts.onRefresh(pivotUIOptions) if opts.onRefresh?
853
+
854
+ refresh = =>
855
+ pivotTable.css("opacity", 0.5)
856
+ setTimeout refreshDelayed, 10
857
+
858
+ #the very first refresh will actually display the table
859
+ refresh()
860
+
861
+ @find(".pvtAxisContainer").sortable
862
+ update: (e, ui) -> refresh() if not ui.sender?
863
+ connectWith: @find(".pvtAxisContainer")
864
+ items: 'li'
865
+ placeholder: 'pvtPlaceholder'
866
+ catch e
867
+ console.error(e.stack) if console?
868
+ @html opts.localeStrings.uiRenderError
869
+ return this
870
+
871
+ ###
872
+ Heatmap post-processing
873
+ ###
874
+
875
+ $.fn.heatmap = (scope = "heatmap") ->
876
+ numRows = @data "numrows"
877
+ numCols = @data "numcols"
878
+
879
+ colorGen = (color, min, max) ->
880
+ hexGen = switch color
881
+ when "red" then (hex) -> "ff#{hex}#{hex}"
882
+ when "green" then (hex) -> "#{hex}ff#{hex}"
883
+ when "blue" then (hex) -> "#{hex}#{hex}ff"
884
+
885
+ return (x) ->
886
+ intensity = 255 - Math.round 255*(x-min)/(max-min)
887
+ hex = intensity.toString(16).split(".")[0]
888
+ hex = 0+hex if hex.length == 1
889
+ return hexGen(hex)
890
+
891
+ heatmapper = (scope, color) =>
892
+ forEachCell = (f) =>
893
+ @find(scope).each ->
894
+ x = $(this).data("value")
895
+ f(x, $(this)) if x? and isFinite(x)
896
+
897
+ values = []
898
+ forEachCell (x) -> values.push x
899
+ colorFor = colorGen color, Math.min(values...), Math.max(values...)
900
+ forEachCell (x, elem) -> elem.css "background-color", "#" + colorFor(x)
901
+
902
+ switch scope
903
+ when "heatmap"
904
+ heatmapper ".pvtVal", "red"
905
+ when "rowheatmap"
906
+ heatmapper ".pvtVal.row#{i}", "red" for i in [0...numRows]
907
+ when "colheatmap"
908
+ heatmapper ".pvtVal.col#{j}", "red" for j in [0...numCols]
909
+
910
+ heatmapper ".pvtTotal.rowTotal", "red"
911
+ heatmapper ".pvtTotal.colTotal", "red"
912
+
913
+ return this
914
+
915
+ ###
916
+ Barchart post-processing
917
+ ###
918
+
919
+ $.fn.barchart = ->
920
+ numRows = @data "numrows"
921
+ numCols = @data "numcols"
922
+
923
+ barcharter = (scope) =>
924
+ forEachCell = (f) =>
925
+ @find(scope).each ->
926
+ x = $(this).data("value")
927
+ f(x, $(this)) if x? and isFinite(x)
928
+
929
+ values = []
930
+ forEachCell (x) -> values.push x
931
+ max = Math.max(values...)
932
+ scaler = (x) -> 100*x/(1.4*max)
933
+ forEachCell (x, elem) ->
934
+ text = elem.text()
935
+ wrapper = $("<div>").css
936
+ "position": "relative"
937
+ "height": "55px"
938
+ wrapper.append $("<div>").css
939
+ "position": "absolute"
940
+ "bottom": 0
941
+ "left": 0
942
+ "right": 0
943
+ "height": scaler(x) + "%"
944
+ "background-color": "gray"
945
+ wrapper.append $("<div>").text(text).css
946
+ "position":"relative"
947
+ "padding-left":"5px"
948
+ "padding-right":"5px"
949
+
950
+ elem.css("padding": 0,"padding-top": "5px", "text-align": "center").html wrapper
951
+
952
+ barcharter ".pvtVal.row#{i}" for i in [0...numRows]
953
+ barcharter ".pvtTotal.colTotal"
954
+
955
+ return this
956
+
957
+