publish_my_data 0.0.32 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (182) hide show
  1. data/app/assets/images/publish_my_data/small-spinner.gif +0 -0
  2. data/app/assets/images/publish_my_data/sort-asc.gif +0 -0
  3. data/app/assets/images/publish_my_data/sort-desc.gif +0 -0
  4. data/app/assets/javascripts/bootstrap/affix.js +126 -0
  5. data/app/assets/javascripts/bootstrap/alert.js +98 -0
  6. data/app/assets/javascripts/bootstrap/button.js +109 -0
  7. data/app/assets/javascripts/bootstrap/carousel.js +217 -0
  8. data/app/assets/javascripts/bootstrap/collapse.js +179 -0
  9. data/app/assets/javascripts/bootstrap/dropdown.js +154 -0
  10. data/app/assets/javascripts/bootstrap/modal.js +246 -0
  11. data/app/assets/javascripts/bootstrap/popover.js +117 -0
  12. data/app/assets/javascripts/bootstrap/scrollspy.js +158 -0
  13. data/app/assets/javascripts/bootstrap/tab.js +135 -0
  14. data/app/assets/javascripts/bootstrap/tooltip.js +386 -0
  15. data/app/assets/javascripts/bootstrap/transition.js +56 -0
  16. data/app/assets/javascripts/publish_my_data/grid/10_data-loader.js +142 -0
  17. data/app/assets/javascripts/publish_my_data/grid/20_cube-grid.js +512 -0
  18. data/app/assets/javascripts/publish_my_data/grid/30_cube-dimension.js +77 -0
  19. data/app/assets/javascripts/publish_my_data/grid/40_cube-dimension-dropdown.js +87 -0
  20. data/app/assets/javascripts/publish_my_data/grid/45_cube-dimension-label.js +58 -0
  21. data/app/assets/javascripts/publish_my_data/grid/50_cube-dimensions-controls.js +336 -0
  22. data/app/assets/javascripts/publish_my_data/grid/60_dataset_cube_grid.js +187 -0
  23. data/app/assets/javascripts/publish_my_data/grid/70_sparql_results_grid.js +135 -0
  24. data/app/assets/javascripts/publish_my_data/select_text.js +27 -0
  25. data/app/assets/javascripts/publish_my_data.js +3 -0
  26. data/app/assets/javascripts/slick_grid/10_event-drag.js +402 -0
  27. data/app/assets/javascripts/slick_grid/20_slick-core.js +458 -0
  28. data/app/assets/javascripts/slick_grid/30_slick-grid.js +3295 -0
  29. data/app/assets/stylesheets/bootstrap/_alerts.scss +67 -0
  30. data/app/assets/stylesheets/bootstrap/_badges.scss +51 -0
  31. data/app/assets/stylesheets/bootstrap/_breadcrumbs.scss +23 -0
  32. data/app/assets/stylesheets/bootstrap/_button-groups.scss +248 -0
  33. data/app/assets/stylesheets/bootstrap/_buttons.scss +160 -0
  34. data/app/assets/stylesheets/bootstrap/_carousel.scss +209 -0
  35. data/app/assets/stylesheets/bootstrap/_close.scss +33 -0
  36. data/app/assets/stylesheets/bootstrap/_code.scss +56 -0
  37. data/app/assets/stylesheets/bootstrap/_component-animations.scss +29 -0
  38. data/app/assets/stylesheets/bootstrap/_dropdowns.scss +194 -0
  39. data/app/assets/stylesheets/bootstrap/_forms.scss +350 -0
  40. data/app/assets/stylesheets/bootstrap/_glyphicons.scss +232 -0
  41. data/app/assets/stylesheets/bootstrap/_grid.scss +346 -0
  42. data/app/assets/stylesheets/bootstrap/_input-groups.scss +127 -0
  43. data/app/assets/stylesheets/bootstrap/_jumbotron.scss +40 -0
  44. data/app/assets/stylesheets/bootstrap/_labels.scss +58 -0
  45. data/app/assets/stylesheets/bootstrap/_list-group.scss +88 -0
  46. data/app/assets/stylesheets/bootstrap/_media.scss +56 -0
  47. data/app/assets/stylesheets/bootstrap/_mixins.scss +728 -0
  48. data/app/assets/stylesheets/bootstrap/_modals.scss +145 -0
  49. data/app/assets/stylesheets/bootstrap/_navbar.scss +625 -0
  50. data/app/assets/stylesheets/bootstrap/_navs.scss +229 -0
  51. data/app/assets/stylesheets/bootstrap/_normalize.scss +396 -0
  52. data/app/assets/stylesheets/bootstrap/_pager.scss +55 -0
  53. data/app/assets/stylesheets/bootstrap/_pagination.scss +83 -0
  54. data/app/assets/stylesheets/bootstrap/_panels.scss +148 -0
  55. data/app/assets/stylesheets/bootstrap/_popovers.scss +133 -0
  56. data/app/assets/stylesheets/bootstrap/_print.scss +100 -0
  57. data/app/assets/stylesheets/bootstrap/_progress-bars.scss +95 -0
  58. data/app/assets/stylesheets/bootstrap/_responsive-utilities.scss +209 -0
  59. data/app/assets/stylesheets/bootstrap/_scaffolding.scss +130 -0
  60. data/app/assets/stylesheets/bootstrap/_tables.scss +236 -0
  61. data/app/assets/stylesheets/bootstrap/_theme.scss +232 -0
  62. data/app/assets/stylesheets/bootstrap/_thumbnails.scss +31 -0
  63. data/app/assets/stylesheets/bootstrap/_tooltip.scss +95 -0
  64. data/app/assets/stylesheets/bootstrap/_type.scss +238 -0
  65. data/app/assets/stylesheets/bootstrap/_utilities.scss +42 -0
  66. data/app/assets/stylesheets/bootstrap/_variables.scss +620 -0
  67. data/app/assets/stylesheets/bootstrap/_wells.scss +29 -0
  68. data/app/assets/stylesheets/bootstrap/bootstrap.scss +59 -0
  69. data/app/assets/stylesheets/publish_my_data/core.scss +244 -0
  70. data/app/assets/stylesheets/publish_my_data/data_grid.scss +103 -0
  71. data/app/assets/stylesheets/publish_my_data/variables.scss +1 -0
  72. data/app/assets/stylesheets/{publish_my_data.css → publish_my_data.scss} +13 -2
  73. data/app/assets/stylesheets/slick_grid/slick_grid.scss +155 -0
  74. data/app/assets/stylesheets/slick_grid/slick_grid_default_theme.scss +97 -0
  75. data/app/controllers/concerns/publish_my_data/data_cube.rb +42 -0
  76. data/app/controllers/publish_my_data/data_cube/dimensions_controller.rb +58 -0
  77. data/app/controllers/publish_my_data/data_cube/observations_controller.rb +54 -0
  78. data/app/controllers/publish_my_data/datasets_controller.rb +0 -11
  79. data/app/controllers/publish_my_data/example_resources_controller.rb +11 -0
  80. data/app/controllers/publish_my_data/home_controller.rb +4 -0
  81. data/app/controllers/publish_my_data/information_resources_controller.rb +0 -13
  82. data/app/helpers/publish_my_data/application_helper.rb +66 -0
  83. data/app/helpers/publish_my_data/crumb_helper.rb +61 -0
  84. data/app/helpers/publish_my_data/datasets_helper.rb +31 -0
  85. data/app/helpers/publish_my_data/resources_helper.rb +24 -0
  86. data/app/models/concerns/publish_my_data/cube_results.rb +51 -0
  87. data/app/models/concerns/publish_my_data/dataset_powers.rb +13 -0
  88. data/app/models/publish_my_data/data_cube/cube.rb +358 -0
  89. data/app/models/publish_my_data/data_cube/dimension.rb +58 -0
  90. data/app/models/publish_my_data/vocabulary.rb +0 -4
  91. data/app/views/layouts/publish_my_data/application.html.haml +18 -0
  92. data/app/views/layouts/publish_my_data/error.html.haml +21 -0
  93. data/app/views/publish_my_data/classes/show.html.haml +28 -0
  94. data/app/views/publish_my_data/concept_schemes/show.html.haml +79 -0
  95. data/app/views/publish_my_data/concepts/show.html.haml +28 -0
  96. data/app/views/publish_my_data/data_cube/_controls.html.haml +19 -0
  97. data/app/views/publish_my_data/data_cube/_grid.html.haml +37 -0
  98. data/app/views/publish_my_data/datasets/_example_resources.html.haml +47 -0
  99. data/app/views/publish_my_data/datasets/_types_table.html.erb +33 -0
  100. data/app/views/publish_my_data/datasets/index.html.haml +32 -0
  101. data/app/views/publish_my_data/datasets/show.html.haml +186 -0
  102. data/app/views/publish_my_data/errors/not_found.html.haml +18 -0
  103. data/app/views/publish_my_data/errors/response_too_large.html.haml +16 -0
  104. data/app/views/publish_my_data/errors/timeout.html.haml +16 -0
  105. data/app/views/publish_my_data/errors/uncaught.html.haml +16 -0
  106. data/app/views/publish_my_data/example_resources/index.js.erb +1 -0
  107. data/app/views/publish_my_data/home/accessibility.html.haml +1 -0
  108. data/app/views/publish_my_data/home/docs.html.haml +1 -0
  109. data/app/views/publish_my_data/home/home.html.haml +5 -0
  110. data/app/views/publish_my_data/home/privacy.html.haml +1 -0
  111. data/app/views/publish_my_data/ontologies/show.html.haml +100 -0
  112. data/app/views/publish_my_data/properties/show.html.haml +28 -0
  113. data/app/views/publish_my_data/resources/_resource_data.html.haml +16 -0
  114. data/app/views/publish_my_data/resources/_sparql_section.html.haml +22 -0
  115. data/app/views/publish_my_data/resources/index.html.haml +37 -0
  116. data/app/views/publish_my_data/resources/show.html.haml +36 -0
  117. data/app/views/publish_my_data/shared/_browser_warning.html.haml +4 -0
  118. data/app/views/publish_my_data/shared/_deprecation_notice.html.haml +8 -0
  119. data/app/views/publish_my_data/shared/_footer.html.haml +11 -0
  120. data/app/views/publish_my_data/shared/_google_analytics.html.haml +11 -0
  121. data/app/views/publish_my_data/shared/_logo.html.haml +1 -0
  122. data/app/views/publish_my_data/shared/_meta_title.html.haml +2 -0
  123. data/app/views/publish_my_data/sparql/_form.html.haml +28 -0
  124. data/app/views/publish_my_data/sparql/_formats_dropdown.html.haml +11 -0
  125. data/app/views/publish_my_data/sparql/endpoint.html.haml +125 -0
  126. data/app/views/publish_my_data/sparql/formats_dropdowns/_ask.html.haml +7 -0
  127. data/app/views/publish_my_data/sparql/formats_dropdowns/_construct.html.haml +7 -0
  128. data/app/views/publish_my_data/sparql/formats_dropdowns/_describe.html.haml +1 -0
  129. data/app/views/publish_my_data/sparql/formats_dropdowns/_select.html.haml +9 -0
  130. data/app/views/publish_my_data/themes/index.html.haml +30 -0
  131. data/app/views/publish_my_data/themes/show.html.haml +43 -0
  132. data/config/routes.rb +20 -5
  133. data/lib/publish_my_data/version.rb +1 -1
  134. data/lib/publish_my_data.rb +7 -12
  135. data/spec/controllers/publish_my_data/datasets_controller_spec.rb +0 -75
  136. data/spec/controllers/publish_my_data/information_resources_controller_spec.rb +2 -11
  137. data/spec/dummy/config/environments/development.rb +0 -4
  138. data/spec/dummy/config/environments/test.rb +0 -4
  139. data/spec/dummy/log/test.log +62962 -0
  140. data/spec/dummy/tmp/cache/sass/e509ccd4d793d2c162d70125e9f3656b6c28f357/(__TEMPLATE__)c +0 -0
  141. data/spec/features/running_a_sparql_query_spec.rb +1 -1
  142. data/spec/features/uri_dereferencing_spec.rb +1 -1
  143. metadata +200 -58
  144. data/app/controllers/concerns/publish_my_data/data_download.rb +0 -22
  145. data/app/controllers/publish_my_data/vocabularies_controller.rb +0 -18
  146. data/app/views/layouts/publish_my_data/application.html.erb +0 -13
  147. data/app/views/layouts/publish_my_data/error.html.erb +0 -13
  148. data/app/views/publish_my_data/classes/show.html.erb +0 -3
  149. data/app/views/publish_my_data/concept_schemes/_concepts.html.erb +0 -18
  150. data/app/views/publish_my_data/concept_schemes/show.html.erb +0 -11
  151. data/app/views/publish_my_data/concepts/show.html.erb +0 -3
  152. data/app/views/publish_my_data/datasets/index.html.erb +0 -20
  153. data/app/views/publish_my_data/datasets/show.html.erb +0 -18
  154. data/app/views/publish_my_data/errors/not_found.html.erb +0 -1
  155. data/app/views/publish_my_data/errors/response_too_large.html.erb +0 -1
  156. data/app/views/publish_my_data/errors/timeout.html.erb +0 -1
  157. data/app/views/publish_my_data/errors/uncaught.html.erb +0 -6
  158. data/app/views/publish_my_data/ontologies/show.html.erb +0 -17
  159. data/app/views/publish_my_data/properties/show.html.erb +0 -3
  160. data/app/views/publish_my_data/resources/_predicates_table.html.erb +0 -30
  161. data/app/views/publish_my_data/resources/_predicates_table_head.html.erb +0 -6
  162. data/app/views/publish_my_data/resources/_resource_formats.html.erb +0 -4
  163. data/app/views/publish_my_data/resources/_summaries.html.erb +0 -18
  164. data/app/views/publish_my_data/resources/_uri_and_label.html.erb +0 -3
  165. data/app/views/publish_my_data/resources/index.html.erb +0 -40
  166. data/app/views/publish_my_data/resources/show.html.erb +0 -3
  167. data/app/views/publish_my_data/sparql/_ask_formats.html.erb +0 -3
  168. data/app/views/publish_my_data/sparql/_construct_formats.html.erb +0 -3
  169. data/app/views/publish_my_data/sparql/_describe_formats.html.erb +0 -1
  170. data/app/views/publish_my_data/sparql/_error_message.html.erb +0 -3
  171. data/app/views/publish_my_data/sparql/_form.html.erb +0 -4
  172. data/app/views/publish_my_data/sparql/_formats.html.erb +0 -6
  173. data/app/views/publish_my_data/sparql/_pagination.html.erb +0 -6
  174. data/app/views/publish_my_data/sparql/_results.html.erb +0 -5
  175. data/app/views/publish_my_data/sparql/_results_data.html.erb +0 -4
  176. data/app/views/publish_my_data/sparql/_select_formats.html.erb +0 -3
  177. data/app/views/publish_my_data/sparql/endpoint.html.erb +0 -10
  178. data/app/views/publish_my_data/themes/index.html.erb +0 -13
  179. data/app/views/publish_my_data/themes/show.html.erb +0 -15
  180. data/config/initializers/20_s3_setup.rb +0 -4
  181. data/spec/controllers/publish_my_data/vocabularies_controller_spec.rb +0 -14
  182. data/spec/support/data_download.rb +0 -60
@@ -0,0 +1,56 @@
1
+ /* ========================================================================
2
+ * Bootstrap: transition.js v3.0.0
3
+ * http://twbs.github.com/bootstrap/javascript.html#transitions
4
+ * ========================================================================
5
+ * Copyright 2013 Twitter, Inc.
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the "License");
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ * ======================================================================== */
19
+
20
+
21
+ +function ($) { "use strict";
22
+
23
+ // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
24
+ // ============================================================
25
+
26
+ function transitionEnd() {
27
+ var el = document.createElement('bootstrap')
28
+
29
+ var transEndEventNames = {
30
+ 'WebkitTransition' : 'webkitTransitionEnd'
31
+ , 'MozTransition' : 'transitionend'
32
+ , 'OTransition' : 'oTransitionEnd otransitionend'
33
+ , 'transition' : 'transitionend'
34
+ }
35
+
36
+ for (var name in transEndEventNames) {
37
+ if (el.style[name] !== undefined) {
38
+ return { end: transEndEventNames[name] }
39
+ }
40
+ }
41
+ }
42
+
43
+ // http://blog.alexmaccaw.com/css-transitions
44
+ $.fn.emulateTransitionEnd = function (duration) {
45
+ var called = false, $el = this
46
+ $(this).one($.support.transition.end, function () { called = true })
47
+ var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
48
+ setTimeout(callback, duration)
49
+ return this
50
+ }
51
+
52
+ $(function () {
53
+ $.support.transition = transitionEnd()
54
+ })
55
+
56
+ }(window.jQuery);
@@ -0,0 +1,142 @@
1
+ (function ($) {
2
+
3
+ function DataLoader(totalCount, pageSize) {
4
+
5
+ var self = this;
6
+ var pageSize = pageSize;
7
+ var data = {length: 0}; // the data rows, which we'll fill in, plus an extra property for total length
8
+ var pagesToLoad = {};
9
+ var loadingPages = 0; // number of pages currently being loaded by loader.
10
+
11
+ // events
12
+ //////////////////
13
+
14
+ var onDataLoading = new Slick.Event();
15
+ var onDataLoaded = new Slick.Event();
16
+ var onPageLoading = new Slick.Event();
17
+ var onPageLoaded = new Slick.Event();
18
+ var onReady = new Slick.Event();
19
+ var onBusy = new Slick.Event();
20
+
21
+ // some setup
22
+
23
+ // subscribe to some grid and loader events.
24
+ onPageLoading.subscribe(function (e, args) {
25
+ if (loadingPages == 0) {
26
+ onBusy.notify();
27
+ }
28
+ loadingPages ++;
29
+ });
30
+
31
+ onPageLoaded.subscribe(function (e, args) {
32
+ loadingPages --;
33
+ if(loadingPages == 0) {
34
+ onReady.notify();
35
+ }
36
+ });
37
+
38
+
39
+ // private funcs
40
+ //////////////////
41
+ function updateTotalCount(newTotalCount) {
42
+ totalCount = newTotalCount;
43
+ }
44
+
45
+ function getData() {
46
+ return data;
47
+ }
48
+
49
+ function clear() {
50
+ for (var key in data) {
51
+ delete data[key];
52
+ }
53
+ data.length = totalCount;
54
+ pagesToLoad = {};
55
+ }
56
+
57
+ // From and to are 0-based row indices.
58
+ // LoaderFunction should be a function that takes a zero-based page index, and call setPageOfData with the data.
59
+ // Raises onDataLoading event, and onPageLoading events.
60
+ // Works out what pages it needs to load, then calls the loaderFunction provided for each one.
61
+ function ensureData(from, to, loaderFunction){
62
+
63
+ data.length = totalCount;
64
+
65
+ if (from < 0) {
66
+ from = 0;
67
+ }
68
+ if (to > data.length-1) {
69
+ to = data.length -1;
70
+ }
71
+
72
+ // tell the world we're trying to load.
73
+ onDataLoading.notify({from: from, to: to});
74
+
75
+ var fromPage = Math.floor(from / pageSize);
76
+ var toPage = Math.floor(to / pageSize);
77
+
78
+ for (var page = fromPage; page <= toPage; page++ ){
79
+ if (pagesToLoad[page] == undefined) {
80
+ pagesToLoad[page] = null;
81
+ }
82
+ }
83
+
84
+ // do a bunch of queries to get the data for the range.
85
+ for (var page = fromPage; page <= toPage; page++ ){
86
+ if (pagesToLoad[page] == null) {
87
+ onPageLoading.notify({page: page});
88
+ loaderFunction.call(self, page);
89
+ }
90
+ }
91
+ }
92
+
93
+ // given a page index, and an array of row data, set the data for the page.
94
+ // Raises onPageLoaded and onDataLoaded events.
95
+ function setPageOfData(page, rows) {
96
+
97
+ pagesToLoad[page] = true; // set the page as loaded.
98
+ var noOfRows = rows.length;
99
+ var thisPageFrom = page * pageSize;
100
+ var thisPageTo = thisPageFrom + noOfRows -1;
101
+
102
+ // fill the results in in data.
103
+ for (var i = 0; i < noOfRows; i++) {
104
+
105
+ // assign the row of results;
106
+ data[thisPageFrom + i] = rows[i];
107
+
108
+ // set row num (1-based)
109
+ var rowNum = thisPageFrom + i + 1;
110
+ data[thisPageFrom + i]["__row_num"] = rowNum;
111
+ }
112
+
113
+ onPageLoaded.notify({page: page});
114
+ onDataLoaded.notify({from: thisPageFrom, to: thisPageTo});
115
+ }
116
+
117
+ // public api.
118
+ //////////////////
119
+
120
+ return {
121
+
122
+ "data": data
123
+
124
+ // methods
125
+ , "updateTotalCount": updateTotalCount
126
+ , "clear": clear
127
+ , "ensureData": ensureData
128
+ , "setPageOfData": setPageOfData
129
+
130
+ // events
131
+ , "onDataLoading": onDataLoading
132
+ , "onDataLoaded": onDataLoaded
133
+ , "onPageLoading": onPageLoading
134
+ , "onPageLoaded": onPageLoaded
135
+ , "onReady": onReady
136
+ , "onBusy": onBusy
137
+ };
138
+ }
139
+
140
+ // Swirrl.DataLoader
141
+ $.extend(true, window, { Swirrl: { DataLoader: DataLoader }});
142
+ })(jQuery);
@@ -0,0 +1,512 @@
1
+ (function ($) {
2
+
3
+ // add key counting to old browsers.
4
+ // https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys
5
+ if (!Object.keys) {
6
+ Object.keys = (function () {
7
+ var hasOwnProperty = Object.prototype.hasOwnProperty,
8
+ hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
9
+ dontEnums = [
10
+ 'toString',
11
+ 'toLocaleString',
12
+ 'valueOf',
13
+ 'hasOwnProperty',
14
+ 'isPrototypeOf',
15
+ 'propertyIsEnumerable',
16
+ 'constructor'
17
+ ],
18
+ dontEnumsLength = dontEnums.length;
19
+
20
+ return function (obj) {
21
+ if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object');
22
+
23
+ var result = [];
24
+
25
+ for (var prop in obj) {
26
+ if (hasOwnProperty.call(obj, prop)) result.push(prop);
27
+ }
28
+
29
+ if (hasDontEnumBug) {
30
+ for (var i=0; i < dontEnumsLength; i++) {
31
+ if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]);
32
+ }
33
+ }
34
+ return result;
35
+ }
36
+ })()
37
+ };
38
+
39
+ // constructor
40
+ function CubeGrid(elementSelector, siteDomain, datasetSlug, pageSize) {
41
+
42
+ // some constants.
43
+ //////////////////
44
+
45
+ var SLICKGRIDOPTIONS = {
46
+ enableCellNavigation: false
47
+ , enableColumnReorder: false
48
+ , syncColumnCellResize: true
49
+ , rowHeight: 24
50
+ }
51
+
52
+ , ROWNUMBERSCOLUMNWIDTH = 60
53
+ , FIRSTCOLUMNWIDTH = 280
54
+ , COLUMNWIDTH = 200
55
+ ;
56
+
57
+ // object-level vars.
58
+ //////////////////
59
+
60
+ var loader = null
61
+ , slickGrid = null
62
+ , urlBase = "http://" + siteDomain + "/data/" + datasetSlug + "/cube"
63
+ , cubeDimensions = null // an array of cubeDimension objects.
64
+ , rowsDimension = null
65
+ , lockedDimensions = {}
66
+ , columnsDimension = null
67
+ , gridSize = null
68
+ , gridColumns = null
69
+ , orderByColumn = null // order by rows by default
70
+ , orderDesc = false // order asc by default
71
+ ;
72
+
73
+ // events
74
+ //////////////////
75
+
76
+ var onCubeDimensionsReady = new Slick.Event()
77
+ , onGridSizeReady = new Slick.Event()
78
+ , onGridColumnsReady = new Slick.Event()
79
+ , onGridGettingData = new Slick.Event()
80
+ , onGridReady = new Slick.Event()
81
+ , onGridInitialized = new Slick.Event()
82
+ , onAjaxError = new Slick.Event()
83
+ ;
84
+
85
+ // some setup.
86
+ ///////////////
87
+
88
+ // we will construct the slick grid once we have enough information.
89
+
90
+ function initGridWhenReady() {
91
+
92
+ function readyHandler(e, args) {
93
+ if (gridPrerequisitesReady()) {
94
+ initGrid();
95
+
96
+ // only do this once.
97
+ onGridSizeReady.unsubscribe(readyHandler);
98
+ onGridColumnsReady.unsubscribe(readyHandler);
99
+ }
100
+ }
101
+
102
+ onGridSizeReady.subscribe(readyHandler);
103
+ onGridColumnsReady.subscribe(readyHandler);
104
+ }
105
+
106
+ initGridWhenReady();
107
+
108
+ // private funcs
109
+ //////////////////
110
+
111
+ function checkLockedDimensions() {
112
+
113
+ if(cubeDimensions) {
114
+ // there should be exactly 2 less locked dimensions than dimensions
115
+ return !!((cubeDimensions.length -2) == Object.keys(lockedDimensions).length);
116
+ } else {
117
+ alert('no dimensions exist');
118
+ return false;
119
+ }
120
+ }
121
+
122
+ function gridPrerequisitesReady(){
123
+ var ready = !!(gridSize && gridColumns && checkLockedDimensions());
124
+ return ready;
125
+ }
126
+
127
+ function clear() {
128
+ // clear out the display
129
+ $(elementSelector).empty();
130
+
131
+ // reset some stuff dimensions.
132
+ rowsDimension = null
133
+ lockedDimensions = {}
134
+ columnsDimension = null
135
+ gridSize = null
136
+ gridColumns = null
137
+ orderByColumn = null // order by rows by default
138
+ orderDesc = false // order asc by default
139
+ }
140
+
141
+ function initGrid() {
142
+ // when we've got grid size, columns, and the lockedDimensions we can construct the grid
143
+ if(!checkLockedDimensions()) {
144
+ alert('missing locked dimensions');
145
+ return;
146
+ }
147
+
148
+ // construct the grid with a loader.
149
+ loader = new Swirrl.DataLoader(gridSize, pageSize);
150
+ slickGrid = new Slick.Grid(elementSelector, loader.data, gridColumns, SLICKGRIDOPTIONS);
151
+ slickGrid.setSortColumn(rowsDimension.uri, true); // start it off being sorted by row dimension, asc
152
+
153
+ // now subscribe to some events:
154
+ ////////////////////////////////
155
+
156
+ // high level busy and ready events:
157
+ loader.onReady.subscribe(function() {
158
+ onGridReady.notify();
159
+ });
160
+
161
+ loader.onBusy.subscribe(function() {
162
+ onGridGettingData.notify();
163
+ });
164
+
165
+ // when a bunch of rows are loaded,
166
+ // re-render them.
167
+ loader.onDataLoaded.subscribe(function (e, args) {
168
+ for (var i = args.from; i <= args.to; i++) {
169
+ slickGrid.invalidateRow(i); // causes the appropriate rows to redraw.
170
+ }
171
+ slickGrid.updateRowCount(); // uses data.length
172
+ slickGrid.render();
173
+ });
174
+
175
+ // When the viewport changes, ensure the loader has the relevent data.
176
+ // (when scrolling stops for 200ms)
177
+ var viewportChangedTimer;
178
+ slickGrid.onViewportChanged.subscribe(function (e, args) {
179
+ clearTimeout(viewportChangedTimer);
180
+
181
+ viewportChangedTimer = setTimeout( function() {
182
+ loader.ensureData(slickGrid.getViewport().top, slickGrid.getViewport().bottom, dataLoaderFunction);
183
+ }, 200); // 200ms delay.
184
+ });
185
+
186
+ // Sorting behaviour:
187
+ slickGrid.onSort.subscribe(function (e, args) {
188
+
189
+ // hack to avoid sorting when clicking on links in col headers
190
+ // (by setting sort back to what it was before click).
191
+ if ($(e.target).hasClass('cell-link')) {
192
+ if(orderByColumn == null) {
193
+ slickGrid.setSortColumn(rowsDimension.uri, (!orderDesc));
194
+ } else {
195
+ slickGrid.setSortColumn(orderByColumn, (!orderDesc));
196
+ }
197
+ return false; // and do nothing else
198
+ }
199
+
200
+ // work out the column and order to sort by
201
+ if (args.sortCol.field == rowsDimension.uri) {
202
+ orderByColumn = null;
203
+ } else {
204
+ orderByColumn = args.sortCol.field;
205
+ }
206
+ orderDesc = args.sortAsc ? false : true;
207
+
208
+ // tell the loader to re-get the data.
209
+ loader.clear();
210
+ slickGrid.setData(loader.data, true);
211
+ loader.ensureData(slickGrid.getViewport().top, slickGrid.getViewport().bottom, dataLoaderFunction);
212
+ showCSVDownloadLink();
213
+ });
214
+
215
+ // finally, ensure the loader has the right data,
216
+ // to initialise the first 'page' of results
217
+ //////////////////
218
+ loader.ensureData(slickGrid.getViewport().top, slickGrid.getViewport().bottom, dataLoaderFunction);
219
+
220
+ // and set that we're initialized
221
+ onGridInitialized.notify();
222
+ }
223
+
224
+ // the function that the loader uses to get the data
225
+ function dataLoaderFunction(page) {
226
+
227
+ function processResponseData(responseData) {
228
+ var start = new Date();
229
+
230
+ var processedData = [];
231
+
232
+ for( var i=0; i < responseData.length; i++ ) {
233
+ var row = responseData[i];
234
+
235
+ var processedRow = {};
236
+
237
+ for (var key in row) {
238
+ // for all keys except the row values or row labels...
239
+ if (!(key == rowsDimension.uri || key == "rowlabel" ) ){
240
+ var obsUri = row[key]["obs"];
241
+ var obsVal = row[key]["val"];
242
+ processedRow[key] = buildUriLink(obsUri, (obsVal || "").toString());
243
+ }
244
+ }
245
+
246
+ // set the value of the row-dimension column
247
+ var rowUri = row[rowsDimension.uri];
248
+ var rowLabel = row["rowlabel"];
249
+ processedRow[rowsDimension.uri] = buildUriLink(rowUri, (rowLabel || rowUri));
250
+
251
+ processedData.push(processedRow);
252
+ }
253
+ return processedData;
254
+ }
255
+
256
+ var url = buildObservationsUrl('json', page);
257
+
258
+ var req = $.ajax({
259
+ dataType: 'json',
260
+ url: url,
261
+ success: function(responseData, _, jqXHR) {
262
+ loader.setPageOfData(jqXHR.page, processResponseData(responseData));
263
+ },
264
+ error: function( jqXHR, _, _ ) {
265
+ onAjaxError.notify({status: jqXHR.status});
266
+ }
267
+ });
268
+
269
+ req.page = page; // add a page property onto the jqXHR obj
270
+
271
+ }
272
+
273
+
274
+ function buildUriLink(uri, text) {
275
+ var url = uri;
276
+
277
+ // if string doesn't start with this domain, use the resource= style
278
+ if(url.indexOf('http://' + siteDomain) != 0) {
279
+ url = 'http://' + siteDomain + '/resource?uri=' + encodeURIComponent(uri);
280
+ }
281
+ return "<a class='cell-link' target='_blank' href='" + url + "'>" + text + "</a>";
282
+ }
283
+
284
+ function getCubeDimensions() {
285
+ return cubeDimensions;
286
+ }
287
+
288
+ function getDimensionWithUri(uri) {
289
+ var dim = null;
290
+ $.each(cubeDimensions, function(i, d) {
291
+ if (d.uri == uri) {
292
+ dim = d;
293
+ return false;
294
+ }
295
+ });
296
+ return dim;
297
+ }
298
+
299
+ // memoized lookup of all cube dimensions.
300
+ function getAllDimensionsAsync(){
301
+
302
+ if (!cubeDimensions) {
303
+ cubeDimensions = []; //this is the object-level var.
304
+ $.ajax({
305
+ dataType: 'json',
306
+ url: urlBase + "/dimensions.json",
307
+ success: function(responseData, textStatus, jqXHR) {
308
+ $.each(responseData, function(i, dimension) {
309
+ cubeDimension = new Swirrl.CubeDimension(dimension.uri, dimension.label, urlBase);
310
+ cubeDimension.onAjaxError.subscribe(function (e, args) {
311
+ // bubble up ajax errors to the grid.
312
+ onAjaxError.notify({status: jqXHR.status});
313
+ });
314
+ cubeDimensions.push(cubeDimension);
315
+ });
316
+ onCubeDimensionsReady.notify({cubeDimensions: cubeDimensions});
317
+ },
318
+ error: function( jqXHR, _, _ ) {
319
+ onAjaxError.notify({status: jqXHR.status});
320
+ }
321
+ });
322
+ } else {
323
+ onCubeDimensionsReady.notify({cubeDimensions: cubeDimensions});
324
+ }
325
+ }
326
+
327
+
328
+ function getSlickGrid() {
329
+ return slickGrid;
330
+ }
331
+
332
+ // set the rows dimension to the cubeDimension object passed in.
333
+ function setRowsDimension(cubeDimension) {
334
+ rowsDimension = cubeDimension;
335
+
336
+ var sizeReadyHandler = function(e, args) {
337
+ // this is the Size of this dimension
338
+ gridSize = args.size;
339
+ onGridSizeReady.notify({gridSize: gridSize});
340
+ rowsDimension.onSizeReady.unsubscribe(sizeReadyHandler); // only do it once.
341
+ }
342
+
343
+ rowsDimension.onSizeReady.subscribe(sizeReadyHandler);
344
+ rowsDimension.getSizeAsync();
345
+ }
346
+
347
+ function getRowsDimension() {
348
+ return rowsDimension;
349
+ }
350
+
351
+ function setGridColumns(cols) {
352
+
353
+ function rawFormatter(row, cell, value, columnDef, dataContext) {
354
+ return value;
355
+ }
356
+
357
+ // start with ids...
358
+ gridColumns = [{id: '__row_num', field: '__row_num', name: '#', width: ROWNUMBERSCOLUMNWIDTH, cssClass: 'row-num' }];
359
+
360
+ // and rows...
361
+ gridColumns.push({id: rowsDimension.uri, name: buildUriLink(rowsDimension.uri, rowsDimension.label || rowsDimension.uri), field: rowsDimension.uri, width: FIRSTCOLUMNWIDTH, sortable:true, formatter: rawFormatter });
362
+
363
+ // finally, all the columns.
364
+ $.each(cols, function(i, col) {
365
+ gridColumns.push({id: col.uri, name: buildUriLink(col.uri, col.label || col.uri), field: col.uri, width: COLUMNWIDTH, sortable:true, formatter: rawFormatter });
366
+ });
367
+
368
+ return gridColumns;
369
+ }
370
+
371
+ // set the columns dimension to the cubeDimension object passed in.
372
+ function setColumnsDimension(cubeDimension) {
373
+ columnsDimension = cubeDimension;
374
+
375
+ var onValuesReadyHandler = function(e, args) {
376
+ // this is the list of columns.
377
+ var cols = args.values;
378
+ setGridColumns(cols);
379
+ onGridColumnsReady.notify({gridColumns: gridColumns});
380
+
381
+ // unsubscribe: we only want to do this once.
382
+ columnsDimension.onValuesReady.unsubscribe(onValuesReadyHandler);
383
+ }
384
+
385
+ columnsDimension.onValuesReady.subscribe(onValuesReadyHandler);
386
+ columnsDimension.getValuesAsync();
387
+ }
388
+
389
+ function getColumnsDimension() {
390
+ return columnsDimension;
391
+ }
392
+
393
+ function setLockedDimensionValue(dimensionUri, value) {
394
+ lockedDimensions[dimensionUri] = value;
395
+ }
396
+
397
+ function getLockedDimensionValue(dimensionUri) {
398
+ return lockedDimensions[dimensionUri];
399
+ }
400
+
401
+ // retuns an array of cubeDimension objects.
402
+ function getLockedDimensionObjects() {
403
+ var retVal = [];
404
+
405
+ if (checkLockedDimensions()) {
406
+
407
+ var retVal;
408
+ for (var lockedDimensionUri in lockedDimensions) {
409
+ // find the right cube Dimension
410
+ $.each(cubeDimensions, function(i, cubeDim) {
411
+ if(cubeDim.uri == lockedDimensionUri) {
412
+ retVal.push(cubeDim);
413
+ }
414
+ });
415
+ }
416
+ }
417
+
418
+ return retVal;
419
+ }
420
+
421
+ // if page passed as null, get whole result set.
422
+ function buildObservationsUrl(format, page) {
423
+ var url = urlBase + "/observations." + format;
424
+
425
+ url += "?rows_dimension=" + encodeURIComponent(rowsDimension.uri);
426
+ url += "&columns_dimension=" + encodeURIComponent(columnsDimension.uri);
427
+
428
+ if (page!=null) { url += "&per_page=" + pageSize.toString(); }
429
+ if (page!=null) { url += "&page=" + (page+1).toString(); } // we use 1-based pages on server
430
+ if (orderDesc) { url += "&order_desc=true"; }
431
+ if (orderByColumn) { url += "&order_by_column=" + encodeURIComponent(orderByColumn); }
432
+
433
+ for (var lockedDimension in lockedDimensions) {
434
+ var dimensionVal = lockedDimensions[lockedDimension];
435
+ url += "&" + encodeURIComponent(lockedDimension) + "=" + encodeURIComponent(dimensionVal);
436
+ }
437
+
438
+ return url;
439
+ }
440
+
441
+ function showCSVDownloadLink() {
442
+ // call hide first, so can call it repeatedly.
443
+ hideCSVDownloadLink();
444
+
445
+ var url = buildObservationsUrl('csv', null);
446
+
447
+ $(".grid-footer i.icon-download").show();
448
+
449
+ var theIcon = $("<i></i>");
450
+ theIcon.addClass("icon-download");
451
+
452
+ var theLink = $("<a></a>");
453
+ theLink.addClass("download-csv");
454
+ theLink.attr("href", url);
455
+
456
+ theLink.append(theIcon);
457
+ theLink.append(" Download results as CSV");
458
+
459
+ $(".grid-footer .footer-content").append(theLink);
460
+ }
461
+
462
+ function hideCSVDownloadLink() {
463
+ $(".grid-footer .footer-content a.download-csv").remove();
464
+ }
465
+
466
+ // public api.
467
+ //////////////////
468
+ return {
469
+
470
+ // methods
471
+ //////////////////
472
+ "getSlickGrid": getSlickGrid
473
+ , "clear": clear
474
+
475
+ , "getAllDimensionsAsync": getAllDimensionsAsync // raises cubeDimensionsReady when cubeDimensions ready
476
+
477
+ , "setRowsDimension": setRowsDimension
478
+ , "getRowsDimension": getRowsDimension
479
+
480
+ , "setColumnsDimension": setColumnsDimension
481
+ , "getColumnsDimension": getColumnsDimension
482
+
483
+ , "setLockedDimensionValue": setLockedDimensionValue
484
+ , "getLockedDimensionValue": getLockedDimensionValue
485
+ , "getLockedDimensionObjects": getLockedDimensionObjects
486
+
487
+ , "checkLockedDimensions": checkLockedDimensions
488
+ , "getCubeDimensions": getCubeDimensions
489
+ , "getDimensionWithUri": getDimensionWithUri
490
+
491
+ , "showCSVDownloadLink": showCSVDownloadLink
492
+ , "hideCSVDownloadLink": hideCSVDownloadLink
493
+
494
+
495
+ , "initGridWhenReady": initGridWhenReady // re-initialises grid from currently set dims when all the pre-reqs have arrived.
496
+
497
+ // events
498
+ //////////////////
499
+ , "onCubeDimensionsReady": onCubeDimensionsReady
500
+ , "onGridSizeReady": onGridSizeReady
501
+ , "onGridColumnsReady": onGridColumnsReady
502
+
503
+ , "onGridGettingData": onGridGettingData
504
+ , "onGridReady": onGridReady
505
+ , "onGridInitialized": onGridInitialized
506
+ , "onAjaxError": onAjaxError
507
+ }
508
+ }
509
+
510
+ // Swirrl.CubeGrid
511
+ $.extend(true, window, { Swirrl: { CubeGrid: CubeGrid }});
512
+ })(jQuery)