blob: 2dfb3686cd89cfd1ad44aebcf46ef7001be1d0f5 [file] [log] [blame]
Tyler Scottcdfcde82015-09-14 16:13:29 -06001//Run when the document loads AND we have the config loaded.
Tyler Scott66a965d2016-02-29 15:41:33 -07002(function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -06003 "use strict";
4 var config;
Tyler Scott384f37a2016-05-05 16:09:05 -06005 var conversions;
Tyler Scott7ae6be02016-06-22 15:29:26 -06006
7 Promise.all([new Promise(function(resolve, reject) {
8 $.ajax('config.json').done(function(data) {
Tyler Scott66a965d2016-02-29 15:41:33 -07009 config = data;
10 resolve();
11 }).fail(function() {
12 console.error("Failed to get config.");
13 ga('send', 'event', 'error', 'config');
14 reject();
15 });
Tyler Scott7ae6be02016-06-22 15:29:26 -060016 }), new Promise(function(resolve, reject) {
Tyler Scott66a965d2016-02-29 15:41:33 -070017 var timeout = setTimeout(function() {
18 console.error("Document never loaded? Something bad has happened!");
19 reject();
20 }, 10000);
21 $(function() {
22 clearTimeout(timeout);
23 resolve();
24 });
Tyler Scott7ae6be02016-06-22 15:29:26 -060025 }), new Promise(function(resolve, reject) {
Tyler Scott384f37a2016-05-05 16:09:05 -060026 $.getJSON('../conversions.json').done(function(data) {
27 conversions = data;
28 resolve();
Tyler Scott7ae6be02016-06-22 15:29:26 -060029 }).fail(function() {
Tyler Scott384f37a2016-05-05 16:09:05 -060030 console.error("Failed to get conversions.");
31 ga('send', 'event', 'error', 'config');
32 //reject(); We will continue anyways. We don't need this functionality.
33 conversions = {};
34 resolve();
35 });
Tyler Scott7ae6be02016-06-22 15:29:26 -060036 })]).then(function() {
Tyler Scott66a965d2016-02-29 15:41:33 -070037 var getParameterByName = function(name) {
38 name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
39 var regex = new RegExp("[\\?&]" + name + "=([^&#]*)");
40 var results = regex.exec(location.search);
Tyler Scott7ae6be02016-06-22 15:29:26 -060041 return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
Tyler Scott66a965d2016-02-29 15:41:33 -070042 }
Tyler Scott2118a412015-10-29 15:17:05 -060043 //Overwrite config if present. Any failure will just cause this to be skipped.
Tyler Scott66a965d2016-02-29 15:41:33 -070044 try {
Tyler Scott2118a412015-10-29 15:17:05 -060045 var configParam = JSON.parse(getParameterByName('config'));
46 config = jQuery.extend(true, config, configParam);
Tyler Scott66a965d2016-02-29 15:41:33 -070047 } catch (e) {
Tyler Scott2118a412015-10-29 15:17:05 -060048 console.warn("Failure in config overwrite, skipping.", e);
49 }
Tyler Scott7ae6be02016-06-22 15:29:26 -060050 new Atmos(config,conversions);
Tyler Scott66a965d2016-02-29 15:41:33 -070051 }, function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -060052 console.error("Failed to initialize!");
53 ga('send', 'event', 'error', 'init');
54 });
Tyler Scottcdfcde82015-09-14 16:13:29 -060055
Tyler Scott7ae6be02016-06-22 15:29:26 -060056})();
Tyler Scott66a965d2016-02-29 15:41:33 -070057var Atmos = (function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -060058 "use strict";
Tyler Scottcdfcde82015-09-14 16:13:29 -060059 var closeButton = '<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>';
Tyler Scott66a965d2016-02-29 15:41:33 -070060 var guid = function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -060061 var d = new Date().getTime();
62 var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
Tyler Scott66a965d2016-02-29 15:41:33 -070063 var r = (d + Math.random() * 16) % 16 | 0;
64 d = Math.floor(d / 16);
65 return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
Tyler Scottcdfcde82015-09-14 16:13:29 -060066 });
67 return uuid;
Tyler Scott66a965d2016-02-29 15:41:33 -070068 }
Tyler Scottcdfcde82015-09-14 16:13:29 -060069 /**
70 * Atmos
71 * @version 2.0
Tyler Scott66a965d2016-02-29 15:41:33 -070072
Tyler Scottcdfcde82015-09-14 16:13:29 -060073 * Configures an Atmos object. This manages the atmos interface.
Tyler Scott66a965d2016-02-29 15:41:33 -070074
Tyler Scottcdfcde82015-09-14 16:13:29 -060075 * @constructor
76 * @param {string} catalog - NDN path
77 * @param {Object} config - Object of configuration options for a Face.
78 */
Tyler Scott384f37a2016-05-05 16:09:05 -060079 var Atmos = function(config, conversions) {
Tyler Scottcdfcde82015-09-14 16:13:29 -060080 //Internal variables.
81 this.results = [];
82 this.resultCount = Infinity;
Tyler Scott66a965d2016-02-29 15:41:33 -070083 this.name = null ;
Tyler Scottcdfcde82015-09-14 16:13:29 -060084 this.page = 0;
85 this.resultsPerPage = 25;
86 this.retrievedSegments = 0;
87
88 //Config/init
89 this.config = config;
Tyler Scott384f37a2016-05-05 16:09:05 -060090 this.conversions = conversions;
Tyler Scottcdfcde82015-09-14 16:13:29 -060091
92 this.catalog = config['global']['catalogPrefix'];
Chengyu Fan7b978f82015-12-09 17:03:23 -070093 this.catalogPrefix = new Name(this.catalog);
Tyler Scottcdfcde82015-09-14 16:13:29 -060094 this.face = new Face(config['global']['faceConfig']);
95
96 //Easy access dom variables
97 this.categories = $('#side-menu');
98 this.resultTable = $('#resultTable');
99 this.filters = $('#filters');
100 this.searchInput = $('#search');
101 this.searchBar = $('#searchBar');
102 this.searchButton = $('#searchButton');
103 this.resultMenu = $('.resultMenu');
104 this.alerts = $('#alerts');
105 this.requestForm = $('#requestForm');
106
107 var scope = this;
Tyler Scott66a965d2016-02-29 15:41:33 -0700108 $('.requestSelectedButton').click(function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600109 ga('send', 'event', 'button', 'click', 'request');
110 scope.request(scope.resultTable.find('.resultSelector:checked:not([disabled])').parent().parent());
111 });
Tyler Scottcdfcde82015-09-14 16:13:29 -0600112 this.filterSetup();
113
114 //Init autocomplete
Tyler Scott66a965d2016-02-29 15:41:33 -0700115 this.searchInput.autoComplete(function(field, callback) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600116 ga('send', 'event', 'search', 'autocomplete');
Tyler Scott66a965d2016-02-29 15:41:33 -0700117 scope.autoComplete(field, function(data) {
Tyler Scott94458992015-09-24 14:16:28 -0700118 var list = data.next;
119 var last = data.lastComponent === true;
Tyler Scott66a965d2016-02-29 15:41:33 -0700120 callback(list.map(function(element) {
Chengyu Fan96130f92016-12-23 17:56:01 -0700121 return field + element.name + (last ? "/" : "");
Tyler Scott66a965d2016-02-29 15:41:33 -0700122 //Don't add trailing slash for last component.
Tyler Scottcdfcde82015-09-14 16:13:29 -0600123 }));
124 });
125 });
126
127 //Handle search
Tyler Scott66a965d2016-02-29 15:41:33 -0700128 this.searchBar.submit(function(e) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600129 ga('send', 'event', 'search', 'submit');
130 e.preventDefault();
Tyler Scott66a965d2016-02-29 15:41:33 -0700131 if (scope.searchInput.val().length === 0) {
132 if (!scope.searchBar.hasClass('has-error')) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600133 scope.searchBar.addClass('has-error').append('<span class="help-block">Search path is required!</span>');
134 }
135 return;
136 } else {
Tyler Scott66a965d2016-02-29 15:41:33 -0700137 scope.searchBar.removeClass('has-error').find('.help-block').fadeOut(function() {
138 $(this).remove()
139 });
Tyler Scottcdfcde82015-09-14 16:13:29 -0600140 }
141 scope.pathSearch();
142 });
143
Tyler Scott66a965d2016-02-29 15:41:33 -0700144 this.searchButton.click(function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600145 console.log("Search Button Pressed");
146 ga('send', 'event', 'button', 'click', 'search');
147 scope.search();
148 });
149
150 //Result navigation handlers
Tyler Scott66a965d2016-02-29 15:41:33 -0700151 this.resultMenu.find('.next').click(function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600152 ga('send', 'event', 'button', 'click', 'next');
Tyler Scott66a965d2016-02-29 15:41:33 -0700153 if (!$(this).hasClass('disabled')) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600154 scope.getResults(scope.page + 1);
155 }
156 });
Tyler Scott7ae6be02016-06-22 15:29:26 -0600157
Tyler Scott66a965d2016-02-29 15:41:33 -0700158 this.resultMenu.find('.previous').click(function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600159 ga('send', 'event', 'button', 'click', 'previous');
Tyler Scott66a965d2016-02-29 15:41:33 -0700160 if (!$(this).hasClass('disabled')) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600161 scope.getResults(scope.page - 1);
162 }
163 });
Tyler Scott7ae6be02016-06-22 15:29:26 -0600164
Tyler Scott66a965d2016-02-29 15:41:33 -0700165 this.resultMenu.find('.clearResults').click(function() {
Tyler Scotte8dac702015-10-13 14:33:25 -0600166 ga('send', 'event', 'button', 'click', 'resultClear');
167 scope.clearResults();
Tyler Scott66a965d2016-02-29 15:41:33 -0700168 $('#results').fadeOut(function() {
Tyler Scotte8dac702015-10-13 14:33:25 -0600169 $(this).addClass('hidden');
170 });
171 });
Tyler Scottcdfcde82015-09-14 16:13:29 -0600172
173 //Change the number of results per page handler
Tyler Scott66a965d2016-02-29 15:41:33 -0700174 var rpps = $('.resultsPerPageSelector').click(function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600175 var t = $(this);
Tyler Scott66a965d2016-02-29 15:41:33 -0700176 if (t.hasClass('active')) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600177 return;
178 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600179 rpps.find('.active').removeClass('active');
180 t.addClass('active');
181 scope.resultsPerPage = Number(t.text());
Tyler Scott66a965d2016-02-29 15:41:33 -0700182 scope.getResults(0);
183 //Force return to page 1;
Tyler Scottcdfcde82015-09-14 16:13:29 -0600184 });
185
186 //Init tree search
Tyler Scott66a965d2016-02-29 15:41:33 -0700187 $('#treeSearch div').treeExplorer(function(path, callback) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600188 console.log("Tree Explorer request", path);
189 ga('send', 'event', 'tree', 'request');
Tyler Scott66a965d2016-02-29 15:41:33 -0700190 scope.autoComplete(path, function(data) {
Tyler Scottb59e6de2015-09-18 14:46:30 -0600191 var list = data.next;
192 var last = (data.lastComponent === true);
Tyler Scottbb42ed22015-10-21 17:02:56 -0600193 if (last) {
194 console.log("Redirecting last element request to a search.");
195 scope.clearResults();
Tyler Scott66a965d2016-02-29 15:41:33 -0700196 scope.query(scope.catalog, {
197 '??': path
Tyler Scott7ae6be02016-06-22 15:29:26 -0600198 }, function(interest, data) {
Tyler Scottbb42ed22015-10-21 17:02:56 -0600199 console.log("Search response", interest, data);
Chengyu Fan7b978f82015-12-09 17:03:23 -0700200 scope.name = interest.getName();
Tyler Scottbb42ed22015-10-21 17:02:56 -0600201 scope.getResults(0);
Tyler Scott66a965d2016-02-29 15:41:33 -0700202 }, function(interest) {
Tyler Scottbb42ed22015-10-21 17:02:56 -0600203 console.warn("Failed to retrieve final component.", interest, path);
204 scope.createAlert("Failed to request final component. " + path + " See console for details.");
205 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700206 return;
207 //Don't call the callback
Tyler Scottbb42ed22015-10-21 17:02:56 -0600208 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600209 console.log("Autocomplete response", list);
Tyler Scott66a965d2016-02-29 15:41:33 -0700210 callback(list.map(function(element) {
Chengyu Fan96130f92016-12-23 17:56:01 -0700211 return (path == "/" ? "/" : "") + element.name + "/";
Tyler Scottcdfcde82015-09-14 16:13:29 -0600212 }));
Chengyu Fan7b978f82015-12-09 17:03:23 -0700213 });
Tyler Scottcdfcde82015-09-14 16:13:29 -0600214 });
215
Tyler Scott66a965d2016-02-29 15:41:33 -0700216 $('#treeSearch').on('click', '.treeSearch', function() {
Tyler Scottb59e6de2015-09-18 14:46:30 -0600217 var t = $(this);
Tyler Scottb59e6de2015-09-18 14:46:30 -0600218 scope.clearResults();
Tyler Scottb59e6de2015-09-18 14:46:30 -0600219 var path = t.parent().parent().attr('id');
Tyler Scottbb42ed22015-10-21 17:02:56 -0600220 console.log("Tree search:", path);
Tyler Scott66a965d2016-02-29 15:41:33 -0700221 scope.query(scope.catalog, {
222 '??': path
Tyler Scott7ae6be02016-06-22 15:29:26 -0600223 }, function(interest, data) {
Tyler Scott66a965d2016-02-29 15:41:33 -0700224 //Success
Tyler Scottb59e6de2015-09-18 14:46:30 -0600225 console.log("Tree search response", interest, data);
Chengyu Fan7b978f82015-12-09 17:03:23 -0700226 scope.name = interest.getName();
Tyler Scottb59e6de2015-09-18 14:46:30 -0600227 scope.getResults(0);
Tyler Scott7ae6be02016-06-22 15:29:26 -0600228 }, function(interest) {
Tyler Scott66a965d2016-02-29 15:41:33 -0700229 //Failure
Tyler Scottb59e6de2015-09-18 14:46:30 -0600230 console.warn("Request failed! Timeout", interest);
Tyler Scott66a965d2016-02-29 15:41:33 -0700231 scope.createAlert("Request timed out.\"" + interest.getName().toUri() + "\" See console for details.");
Tyler Scottb59e6de2015-09-18 14:46:30 -0600232 });
Tyler Scottb59e6de2015-09-18 14:46:30 -0600233 });
234
Tyler Scottcdfcde82015-09-14 16:13:29 -0600235 this.setupRequestForm();
Tyler Scott48f92cd2015-10-16 18:31:20 -0600236 this.resultTable.popover({
Tyler Scott66a965d2016-02-29 15:41:33 -0700237 selector: ".metaDataLink",
238 content: function() {
Tyler Scottf95a97c2016-06-21 12:09:22 -0600239 $('.metaDataLink').not(this).popover('destroy');
Tyler Scott48f92cd2015-10-16 18:31:20 -0600240 return scope.getMetaData(this);
241 },
242 title: "Metadata",
243 html: true,
244 trigger: 'click',
245 placement: 'bottom'
246 });
247
Tyler Scott66a965d2016-02-29 15:41:33 -0700248 this.resultTable.on('click', '.metaDataLink', function(e) {
Tyler Scott48f92cd2015-10-16 18:31:20 -0600249 //This prevents the page from scrolling when you click on a name.
250 e.preventDefault();
251 });
252
Tyler Scott66a965d2016-02-29 15:41:33 -0700253 this.resultTable.on('click', '.subsetButton', function() {
Tyler Scottf355e452015-11-06 21:35:14 -0700254 var metaData = $(this).siblings('pre').text();
255 var exp = /netcdf ([\w-]+)/;
256 var match = exp.exec(metaData);
Tyler Scott66a965d2016-02-29 15:41:33 -0700257 var filename = match[0].replace(/netcdf /, '') + '.nc';
258 scope.request(null , filename);
Tyler Scottf355e452015-11-06 21:35:14 -0700259 });
260
Tyler Scottf95a97c2016-06-21 12:09:22 -0600261 //Allow the title to change the tab
Tyler Scott7ae6be02016-06-22 15:29:26 -0600262 $('#brand-title').click(function() {
Tyler Scottf95a97c2016-06-21 12:09:22 -0600263 //Correct active class on tabs.
Tyler Scott7ae6be02016-06-22 15:29:26 -0600264 $('#path-search-tab').removeClass('active');
265 $('#tree-search-tab').removeClass('active');
Tyler Scottf95a97c2016-06-21 12:09:22 -0600266 $('#search-tab').addClass('active');
267 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700268 }
Tyler Scott66a965d2016-02-29 15:41:33 -0700269 Atmos.prototype.clearResults = function() {
270 this.results = [];
271 //Drop any old results.
Tyler Scottcdfcde82015-09-14 16:13:29 -0600272 this.retrievedSegments = 0;
273 this.resultCount = Infinity;
274 this.page = 0;
275 this.resultTable.empty();
Tyler Scott66a965d2016-02-29 15:41:33 -0700276 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600277
Tyler Scott66a965d2016-02-29 15:41:33 -0700278 Atmos.prototype.pathSearch = function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600279 var value = this.searchInput.val();
Tyler Scottcdfcde82015-09-14 16:13:29 -0600280 this.clearResults();
Tyler Scottcdfcde82015-09-14 16:13:29 -0600281 var scope = this;
Tyler Scott66a965d2016-02-29 15:41:33 -0700282 this.query(this.catalog, {
283 "??": value
Tyler Scott7ae6be02016-06-22 15:29:26 -0600284 }, function(interest, data) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600285 console.log("Query response:", interest, data);
Tyler Scott66a965d2016-02-29 15:41:33 -0700286 scope.name = interest.getName();
Tyler Scottcdfcde82015-09-14 16:13:29 -0600287 scope.getResults(0);
Tyler Scott7ae6be02016-06-22 15:29:26 -0600288 }, function(interest) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600289 console.warn("Request failed! Timeout", interest);
290 scope.createAlert("Request timed out. \"" + interest.getName().toUri() + "\" See console for details.");
291 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700292 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600293
Tyler Scott66a965d2016-02-29 15:41:33 -0700294 Atmos.prototype.search = function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600295 var filters = this.getFilters();
Tyler Scottcdfcde82015-09-14 16:13:29 -0600296 console.log("Search started!", this.searchInput.val(), filters);
Tyler Scottcdfcde82015-09-14 16:13:29 -0600297 console.log("Initiating query");
Tyler Scottcdfcde82015-09-14 16:13:29 -0600298 this.clearResults();
Tyler Scottcdfcde82015-09-14 16:13:29 -0600299 var scope = this;
Tyler Scott7ae6be02016-06-22 15:29:26 -0600300 this.query(this.catalog, filters, function(interest, data) {
Tyler Scott66a965d2016-02-29 15:41:33 -0700301 //Response function
Tyler Scottcdfcde82015-09-14 16:13:29 -0600302 console.log("Query Response:", interest, data);
Chengyu Fan7b978f82015-12-09 17:03:23 -0700303 scope.name = interest.getName();
Tyler Scottcdfcde82015-09-14 16:13:29 -0600304 scope.getResults(0);
Tyler Scott66a965d2016-02-29 15:41:33 -0700305 }, function(interest) {
306 //Timeout function
Tyler Scottd980a292015-10-13 15:16:34 -0600307 console.warn("Request failed after 3 attempts!", interest);
308 scope.createAlert("Request failed after 3 attempts. \"" + interest.getName().toUri() + "\" See console for details.");
Tyler Scottcdfcde82015-09-14 16:13:29 -0600309 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700310 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600311
Tyler Scott66a965d2016-02-29 15:41:33 -0700312 Atmos.prototype.autoComplete = function(field, callback) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600313 var scope = this;
Tyler Scott66a965d2016-02-29 15:41:33 -0700314 var result = {};
Tyler Scott66a965d2016-02-29 15:41:33 -0700315 const getAll = function(interest, data) {
Tyler Scott66a965d2016-02-29 15:41:33 -0700316 if (data.getContent().length !== 0) {
317 var resp = JSON.parse(data.getContent().toString().replace(/[\n\0]/g, ""));
318 if (result.next) {
319 result.next = result.next.concat(resp.next);
320 } else {
321 result = resp;
Tyler Scottd61bf832015-11-30 16:36:17 -0700322 }
Tyler Scott66a965d2016-02-29 15:41:33 -0700323 } else {
324 callback(result);
325 }
Tyler Scott66a965d2016-02-29 15:41:33 -0700326 var name = data.getName();
327 var segment = name.components[name.getComponentCount() - 1];
Tyler Scott7ae6be02016-06-22 15:29:26 -0600328 if (segment.toSegment() !== data.getMetaInfo().getFinalBlockId().toSegment()) {
329 name = name.getPrefix(-1);
330 //Remove segment
Tyler Scott66a965d2016-02-29 15:41:33 -0700331 name.appendSegment(segment.toSegment() + 1);
332 scope.expressInterest(name, getAll, function() {
333 console.warn("Autocomplete timed out, results may be incomplete.");
334 callback(result);
335 //Return if we get a timeout.
336 });
337 } else {
338 callback(result);
339 }
Tyler Scott66a965d2016-02-29 15:41:33 -0700340 }
Tyler Scott66a965d2016-02-29 15:41:33 -0700341 this.query(this.catalog, {
342 "?": field
343 }, getAll);
Tyler Scott66a965d2016-02-29 15:41:33 -0700344 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600345
346 Atmos.prototype.showResults = function(resultIndex) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600347 var results = this.results.slice(this.resultsPerPage * resultIndex, this.resultsPerPage * (resultIndex + 1));
Tyler Scott7ae6be02016-06-22 15:29:26 -0600348 var resultDOM = $(results.reduce(function(prev, current) {
Tyler Scotta55f0912016-08-09 22:25:28 +0000349 prev.push('<tr><td><input class="resultSelector" type="checkbox"></td><td class="popover-container">');
350 if (current.has_metadata){
351 prev.push('<a href="#" class="metaDataLink">');
352 }
353 prev.push(current.name);
354 if (current.has_metadata){
355 prev.push('</a>');
356 }
357 prev.push('</td></tr>');
Tyler Scott66a965d2016-02-29 15:41:33 -0700358 return prev;
Tyler Scott7ae6be02016-06-22 15:29:26 -0600359 }, ['<tr><th><input id="resultSelectAll" type="checkbox"> Select All</th><th>Name</th></tr>']).join(''));
Tyler Scott66a965d2016-02-29 15:41:33 -0700360 resultDOM.find('#resultSelectAll').click(function() {
361 if ($(this).is(':checked')) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600362 resultDOM.find('.resultSelector:not([disabled])').prop('checked', true);
363 } else {
364 resultDOM.find('.resultSelector:not([disabled])').prop('checked', false);
365 }
366 });
Tyler Scottcdfcde82015-09-14 16:13:29 -0600367 this.resultTable.hide().empty().append(resultDOM).slideDown('slow');
Tyler Scottcdfcde82015-09-14 16:13:29 -0600368 this.resultMenu.find('.pageNumber').text(resultIndex + 1);
369 this.resultMenu.find('.pageLength').text(this.resultsPerPage * resultIndex + results.length);
Tyler Scottcdfcde82015-09-14 16:13:29 -0600370 if (this.resultsPerPage * (resultIndex + 1) >= this.resultCount) {
371 this.resultMenu.find('.next').addClass('disabled');
Tyler Scott66a965d2016-02-29 15:41:33 -0700372 } else if (resultIndex === 0) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600373 this.resultMenu.find('.next').removeClass('disabled');
374 }
Tyler Scott66a965d2016-02-29 15:41:33 -0700375 if (resultIndex === 0) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600376 this.resultMenu.find('.previous').addClass('disabled');
377 } else if (resultIndex === 1) {
378 this.resultMenu.find('.previous').removeClass('disabled');
379 }
Tyler Scottf912dea2016-08-09 21:50:34 +0000380 $('body').animate({
381 scrollTop: $("#results").offset().top
382 }, 500);
Tyler Scott66a965d2016-02-29 15:41:33 -0700383 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600384
Tyler Scott66a965d2016-02-29 15:41:33 -0700385 Atmos.prototype.getResults = function(index) {
Tyler Scott7ae6be02016-06-22 15:29:26 -0600386
Chengyu Fan7b978f82015-12-09 17:03:23 -0700387 var scope = this;
Tyler Scottcdfcde82015-09-14 16:13:29 -0600388
Tyler Scott66a965d2016-02-29 15:41:33 -0700389 if ($('#results').hasClass('hidden')) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600390 $('#results').removeClass('hidden').slideDown();
391 }
392
Tyler Scott66a965d2016-02-29 15:41:33 -0700393 if ((scope.results.length === scope.resultCount) || (scope.resultsPerPage * (index + 1) < scope.results.length)) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600394 //console.log("We already have index", index);
Chengyu Fan7b978f82015-12-09 17:03:23 -0700395 scope.page = index;
396 scope.showResults(index);
Tyler Scottcdfcde82015-09-14 16:13:29 -0600397 return;
398 }
399
Tyler Scott66a965d2016-02-29 15:41:33 -0700400 if (scope.name === null ) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600401 console.error("This shouldn't be reached! We are getting results before a search has occured!");
402 throw new Error("Illegal State");
403 }
404
Chengyu Fan7b978f82015-12-09 17:03:23 -0700405 var interestName = new Name(scope.name);
Chengyu Fan7b978f82015-12-09 17:03:23 -0700406 // Interest name should be /<catalog-prefix>/query/<query-param>/<version>/<#seq>
407 if (scope.name.size() === (scope.catalogPrefix.size() + 3)) {
408 interestName = interestName.appendSegment(scope.retrievedSegments++);
Tyler Scott66a965d2016-02-29 15:41:33 -0700409 //console.log("Requesting data index: (", scope.retrievedSegments - 1, ") at ", interestName.toUri());
Chengyu Fan7b978f82015-12-09 17:03:23 -0700410 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600411
Tyler Scott7ae6be02016-06-22 15:29:26 -0600412 this.expressInterest(interestName, function(interest, data) {
Tyler Scott66a965d2016-02-29 15:41:33 -0700413 //Response
Tyler Scott66a965d2016-02-29 15:41:33 -0700414 if (data.getContent().length === 0) {
415 scope.resultMenu.find('.totalResults').text(0);
416 scope.resultMenu.find('.pageNumber').text(0);
417 scope.resultMenu.find('.pageLength').text(0);
418 console.log("Empty response.");
419 scope.resultTable.html("<tr><td>Empty response. This usually means no results.</td></tr>");
420 return;
Tyler Scottcdfcde82015-09-14 16:13:29 -0600421 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600422
Tyler Scott66a965d2016-02-29 15:41:33 -0700423 var content = JSON.parse(data.getContent().toString().replace(/[\n\0]/g, ""));
424
425 if (!content.results) {
426 scope.resultMenu.find('.totalResults').text(0);
427 scope.resultMenu.find('.pageNumber').text(0);
428 scope.resultMenu.find('.pageLength').text(0);
429 console.log("No results were found!");
430 scope.resultTable.html("<tr><td>No Results</td></tr>");
431 return;
432 }
433
434 scope.results = scope.results.concat(content.results);
Tyler Scott66a965d2016-02-29 15:41:33 -0700435 scope.resultCount = content.resultCount;
Tyler Scott66a965d2016-02-29 15:41:33 -0700436 scope.resultMenu.find('.totalResults').text(scope.resultCount);
Tyler Scott66a965d2016-02-29 15:41:33 -0700437 scope.page = index;
Tyler Scott66a965d2016-02-29 15:41:33 -0700438 // reset scope.name
439 scope.name = new Name(data.getName().getPrefix(scope.catalogPrefix.size() + 3));
Tyler Scott66a965d2016-02-29 15:41:33 -0700440 scope.getResults(index);
441 //Keep calling this until we have enough data.
Tyler Scott7ae6be02016-06-22 15:29:26 -0600442 }, function() {});//Ignore failure
Tyler Scott66a965d2016-02-29 15:41:33 -0700443
444 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600445 Atmos.prototype.query = function(prefix, parameters, callback, timeout) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600446 var queryPrefix = new Name(prefix);
447 queryPrefix.append("query");
Tyler Scottcdfcde82015-09-14 16:13:29 -0600448 var jsonString = JSON.stringify(parameters);
449 queryPrefix.append(jsonString);
Tyler Scott66a965d2016-02-29 15:41:33 -0700450 this.expressInterest(queryPrefix, callback, timeout);
Tyler Scott66a965d2016-02-29 15:41:33 -0700451 }
Tyler Scottd61bf832015-11-30 16:36:17 -0700452
Tyler Scott66a965d2016-02-29 15:41:33 -0700453 Atmos.prototype.expressInterest = function(name, success, failure) {
Tyler Scott66a965d2016-02-29 15:41:33 -0700454 var interest = new Interest(name);
Tyler Scott7ae6be02016-06-22 15:29:26 -0600455 interest.setInterestLifetimeMilliseconds(500);
Tyler Scott66a965d2016-02-29 15:41:33 -0700456 interest.setMustBeFresh(true);
Tyler Scott66a965d2016-02-29 15:41:33 -0700457 const face = this.face;
Tyler Scottf912dea2016-08-09 21:50:34 +0000458 var cancelled = false;
459 var attempt = 0;
460 openLoadingOverlay(function(update){
461 async.retry(4, function(done) {
462 face.expressInterest(interest, function(interest, data) {
463 update(true, attempt, attempt);
464 done();
465 success(interest, data);
466 }, function(interest) {
467 update(false, attempt++, attempt);
468 done("Timeout", interest);
469 });
470 }, function(err, interest) {
471 update(true, attempt, attempt);
472 if (err) {
473 console.log(err, interest);
474 failure(interest);
475 }
Tyler Scott66a965d2016-02-29 15:41:33 -0700476 });
Tyler Scottf912dea2016-08-09 21:50:34 +0000477 }, function(){
478 cancelled = true;
Tyler Scottd61bf832015-11-30 16:36:17 -0700479 });
Tyler Scottf912dea2016-08-09 21:50:34 +0000480
Tyler Scott66a965d2016-02-29 15:41:33 -0700481 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600482
483 /**
484 * This function returns a map of all the categories active filters.
485 * @return {Object<string, string>}
486 */
Tyler Scott66a965d2016-02-29 15:41:33 -0700487 Atmos.prototype.getFilters = function() {
488 var filters = this.filters.children().toArray().reduce(function(prev, current) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600489 var data = $(current).text().split(/:/);
490 prev[data[0]] = data[1];
491 return prev;
Tyler Scott66a965d2016-02-29 15:41:33 -0700492 }, {});
493 //Collect a map<category, filter>.
Tyler Scottcdfcde82015-09-14 16:13:29 -0600494 //TODO Make the return value map<category, Array<filter>>
495 return filters;
Tyler Scott66a965d2016-02-29 15:41:33 -0700496 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600497
498 /**
499 * Creates a closable alert for the user.
Tyler Scott66a965d2016-02-29 15:41:33 -0700500
Tyler Scottcdfcde82015-09-14 16:13:29 -0600501 * @param {string} message
502 * @param {string} type - Override the alert type.
503 */
504 Atmos.prototype.createAlert = function(message, type) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600505 var alert = $('<div class="alert"><div>');
Tyler Scott66a965d2016-02-29 15:41:33 -0700506 alert.addClass(type ? type : 'alert-info');
Tyler Scottcdfcde82015-09-14 16:13:29 -0600507 alert.text(message);
508 alert.append(closeButton);
Tyler Scottcdfcde82015-09-14 16:13:29 -0600509 this.alerts.append(alert);
Tyler Scott66a965d2016-02-29 15:41:33 -0700510 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600511
512 /**
513 * Requests all of the names represented by the buttons in the elements list.
Tyler Scott66a965d2016-02-29 15:41:33 -0700514
Tyler Scottcdfcde82015-09-14 16:13:29 -0600515 * @param elements {Array<jQuery>} A list of the table row elements
Tyler Scottf355e452015-11-06 21:35:14 -0700516 * @param subsetFileName {String} If present then do a subsetting request instead.
Tyler Scottcdfcde82015-09-14 16:13:29 -0600517 */
Tyler Scott66a965d2016-02-29 15:41:33 -0700518 Atmos.prototype.request = function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600519 //Pseudo globals.
520 var keyChain;
521 var certificateName;
522 var keyAdded = false;
Tyler Scott66a965d2016-02-29 15:41:33 -0700523 return function(elements, subsetFilename) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600524
525 var names = [];
Tyler Scott7ae6be02016-06-22 15:29:26 -0600526
Tyler Scott66a965d2016-02-29 15:41:33 -0700527 $(elements).find('.metaDataLink').each(function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600528 var name = $(this).text();
529 names.push(name);
Tyler Scottf355e452015-11-06 21:35:14 -0700530 });
Tyler Scottf355e452015-11-06 21:35:14 -0700531 var subset = false;
Tyler Scott66a965d2016-02-29 15:41:33 -0700532 if (!subsetFilename) {
Tyler Scottf355e452015-11-06 21:35:14 -0700533 $('#subsetting').hide();
534 } else {
535 $('#subsetting').show();
536 subset = true;
537 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600538
539 var scope = this;
Tyler Scott384f37a2016-05-05 16:09:05 -0600540
541 //FIXME The following is temporary, it allows people to direct download from
542 //a single host with a small set of names. It is to demo the functionality but
543 //could use improvement. (Multiple servers, non static list, etc)
544 var directDls = $('#directDownloadList').empty();
Tyler Scott7ae6be02016-06-22 15:29:26 -0600545 names.forEach(function(name) {
546 if (scope.conversions[name]) {
547 //If the name exists in the conversions.
Tyler Scott384f37a2016-05-05 16:09:05 -0600548 var ele = $('<a href="http://atmos-mwsc.ucar.edu/ucar/' + conversions[name] + '" class="list-group-item>' + name + '</a>');
549 directDls.append(ele);
550 }
551 });
552
Tyler Scott66a965d2016-02-29 15:41:33 -0700553 this.requestForm.on('submit', function(e) {
554 //This will be registered for the next submit from the form.
Tyler Scottcdfcde82015-09-14 16:13:29 -0600555 e.preventDefault();
Tyler Scottf355e452015-11-06 21:35:14 -0700556 $('#request .alert').remove();
Tyler Scottf355e452015-11-06 21:35:14 -0700557 var variables = [];
Tyler Scott66a965d2016-02-29 15:41:33 -0700558 if (subset) {
559 $('#subsetVariables .row').each(function() {
Tyler Scottf355e452015-11-06 21:35:14 -0700560 var t = $(this);
561 var values = {};
Tyler Scott66a965d2016-02-29 15:41:33 -0700562 t.find('.values input').each(function() {
Tyler Scottf355e452015-11-06 21:35:14 -0700563 var t = $(this);
564 values[t.attr('name')] = t.val();
565 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700566 variables.push({
567 variable: t.find('.variable').val(),
568 values: values
569 });
Tyler Scottf355e452015-11-06 21:35:14 -0700570 });
571 }
572
Tyler Scottcdfcde82015-09-14 16:13:29 -0600573 //Form checking
574 var dest = scope.requestForm.find('#requestDest .active');
Tyler Scott66a965d2016-02-29 15:41:33 -0700575 if (dest.length !== 1) {
Tyler Scottf355e452015-11-06 21:35:14 -0700576 var alert = $('<div class="alert alert-warning">A destination is required!' + closeButton + '<div>');
577 $('#request > .panel-body').append(alert);
Tyler Scottcdfcde82015-09-14 16:13:29 -0600578 return;
579 }
580
Tyler Scott66a965d2016-02-29 15:41:33 -0700581 $('#request').modal('hide');
Tyler Scottb59e6de2015-09-18 14:46:30 -0600582
Tyler Scott7ae6be02016-06-22 15:29:26 -0600583 //Initial params are ok. We can close the form.
Tyler Scottb59e6de2015-09-18 14:46:30 -0600584 scope.cleanRequestForm();
Tyler Scottcdfcde82015-09-14 16:13:29 -0600585
Tyler Scott7ae6be02016-06-22 15:29:26 -0600586 $(this).off(e); //Don't fire this again, the request must be regenerated
Tyler Scottcdfcde82015-09-14 16:13:29 -0600587
588 //Key setup
Tyler Scott66a965d2016-02-29 15:41:33 -0700589 if (!keyAdded) {
590 if (!scope.config.retrieval.demoKey || !scope.config.retrieval.demoKey.pub || !scope.config.retrieval.demoKey.priv) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600591 scope.createAlert("This host was not configured to handle retrieval! See console for details.", 'alert-danger');
592 console.error("Missing/invalid key! This must be configured in the config on the server.", scope.config.demoKey);
593 return;
594 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600595 //FIXME base64 may or may not exist in other browsers. Need a new polyfill.
Tyler Scott66a965d2016-02-29 15:41:33 -0700596 var pub = new Buffer(base64.toByteArray(scope.config.retrieval.demoKey.pub));
597 //MUST be a Buffer (Buffer != Uint8Array)
Tyler Scottcdfcde82015-09-14 16:13:29 -0600598 var priv = new Buffer(base64.toByteArray(scope.config.retrieval.demoKey.priv));
Tyler Scottcdfcde82015-09-14 16:13:29 -0600599 var identityStorage = new MemoryIdentityStorage();
600 var privateKeyStorage = new MemoryPrivateKeyStorage();
Tyler Scott7ae6be02016-06-22 15:29:26 -0600601 keyChain = new KeyChain(new IdentityManager(identityStorage,privateKeyStorage),new SelfVerifyPolicyManager(identityStorage));
Tyler Scottcdfcde82015-09-14 16:13:29 -0600602 var keyName = new Name("/retrieve/DSK-123");
Tyler Scott7ae6be02016-06-22 15:29:26 -0600603 certificateName = keyName.getSubName(0, keyName.size() - 1).append("KEY").append(keyName.get(-1)).append("ID-CERT").append("0");
Tyler Scott66a965d2016-02-29 15:41:33 -0700604 identityStorage.addKey(keyName, KeyType.RSA, new Blob(pub,false));
Tyler Scottcdfcde82015-09-14 16:13:29 -0600605 privateKeyStorage.setKeyPairForKeyName(keyName, KeyType.RSA, pub, priv);
Tyler Scottcdfcde82015-09-14 16:13:29 -0600606 scope.face.setCommandSigningInfo(keyChain, certificateName);
Tyler Scottcdfcde82015-09-14 16:13:29 -0600607 keyAdded = true;
Tyler Scottcdfcde82015-09-14 16:13:29 -0600608 }
609
610 //Retrieval
611 var retrievePrefix = new Name("/catalog/ui/" + guid());
Tyler Scott7ae6be02016-06-22 15:29:26 -0600612 scope.face.registerPrefix(retrievePrefix, function(prefix, interest, face, interestFilterId, filter) {
Tyler Scott66a965d2016-02-29 15:41:33 -0700613 //On Interest
614 //This function will exist until the page exits but will likely only be used once.
Tyler Scott66a965d2016-02-29 15:41:33 -0700615 var data = new Data(interest.getName());
616 var content;
617 if (subset) {
618 content = JSON.stringify({
619 name: subsetFilename,
620 subset: variables
Tyler Scottd61bf832015-11-30 16:36:17 -0700621 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700622 } else {
623 content = JSON.stringify(names);
Tyler Scottcdfcde82015-09-14 16:13:29 -0600624 }
Tyler Scott7ae6be02016-06-22 15:29:26 -0600625
Tyler Scott66a965d2016-02-29 15:41:33 -0700626 //Blob breaks the data! Don't use it
627 data.setContent(content);
Tyler Scott7ae6be02016-06-22 15:29:26 -0600628
Tyler Scott66a965d2016-02-29 15:41:33 -0700629 //TODO Packetize this.
630 keyChain.sign(data, certificateName);
631
632 try {
633 face.putData(data);
634 console.log("Responded for", interest.getName().toUri(), data);
635 scope.createAlert("Data retrieval has initiated.", "alert-success");
636 } catch (e) {
637 console.error("Failed to respond to", interest.getName().toUri(), data);
638 scope.createAlert("Data retrieval failed.");
639 }
Tyler Scott66a965d2016-02-29 15:41:33 -0700640 }, function(prefix) {
641 //On fail
642 scope.createAlert("Failed to register the retrieval URI! See console for details.", "alert-danger");
643 console.error("Failed to register URI:", prefix.toUri(), prefix);
644 }, function(prefix, registeredPrefixId) {
645 //On success
646 var name = new Name(dest.text());
647 name.append(prefix);
Tyler Scott7ae6be02016-06-22 15:29:26 -0600648 scope.expressInterest(name, function(interest, data) {
Tyler Scott66a965d2016-02-29 15:41:33 -0700649 //Success
650 console.log("Request for", name.toUri(), "succeeded.", interest, data);
Tyler Scott7ae6be02016-06-22 15:29:26 -0600651 }, function() {
Tyler Scott66a965d2016-02-29 15:41:33 -0700652 console.warn("Failed to request from retrieve agent.");
Tyler Scott7ae6be02016-06-22 15:29:26 -0600653 });
654 });
Tyler Scottcdfcde82015-09-14 16:13:29 -0600655 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700656 $('#request').modal();
657 //This forces the form to be the only option.
Tyler Scott66a965d2016-02-29 15:41:33 -0700658 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600659 }();
660
661 Atmos.prototype.filterSetup = function() {
662 //Filter setup
Tyler Scottcdfcde82015-09-14 16:13:29 -0600663 var prefix = new Name(this.catalog).append("filters-initialization");
664
665 var scope = this;
666
Tyler Scott66a965d2016-02-29 15:41:33 -0700667 this.getAll(prefix, function(data) {
668 //Success
669 var raw = JSON.parse(data.replace(/[\n\0]/g, ''));
670 //Remove null byte and parse
Tyler Scottcdfcde82015-09-14 16:13:29 -0600671 console.log("Filter categories:", raw);
672
Tyler Scott66a965d2016-02-29 15:41:33 -0700673 $.each(raw, function(index, object) {
674 //Unpack list of objects
Tyler Scott7ae6be02016-06-22 15:29:26 -0600675
Tyler Scott66a965d2016-02-29 15:41:33 -0700676 $.each(object, function(category, searchOptions) {
677 //Unpack category from object (We don't know what it is called)
Tyler Scottcdfcde82015-09-14 16:13:29 -0600678 //Create the category
679 var e = $('<li><a href="#">' + category.replace(/_/g, " ") + '</a><ul class="subnav nav nav-pills nav-stacked"></ul></li>');
Tyler Scottcdfcde82015-09-14 16:13:29 -0600680 var sub = e.find('ul.subnav');
Tyler Scott66a965d2016-02-29 15:41:33 -0700681 $.each(searchOptions, function(index, name) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600682 //Create the filter list inside the category
Tyler Scott7ae6be02016-06-22 15:29:26 -0600683
Tyler Scottcdfcde82015-09-14 16:13:29 -0600684 var item = $('<li><a href="#">' + name + '</a></li>');
685 sub.append(item);
Tyler Scottf912dea2016-08-09 21:50:34 +0000686 item.find('a').click(function(e) {
687 e.preventDefault();
Tyler Scott66a965d2016-02-29 15:41:33 -0700688 //Click on the side menu filters
689 if (item.hasClass('active')) {
690 //Does the filter already exist?
Tyler Scottcdfcde82015-09-14 16:13:29 -0600691 item.removeClass('active');
692 scope.filters.find(':contains(' + category + ':' + name + ')').remove();
Tyler Scott66a965d2016-02-29 15:41:33 -0700693 } else {
694 //Add a filter
Tyler Scottcdfcde82015-09-14 16:13:29 -0600695 item.addClass('active');
696 var filter = $('<span class="label label-default"></span>');
697 filter.text(category + ':' + name);
Tyler Scottcdfcde82015-09-14 16:13:29 -0600698 scope.filters.append(filter);
Tyler Scottf912dea2016-08-09 21:50:34 +0000699 filter.click(function(e) {
Tyler Scott66a965d2016-02-29 15:41:33 -0700700 //Click on a filter
Tyler Scottcdfcde82015-09-14 16:13:29 -0600701 filter.remove();
702 item.removeClass('active');
703 });
704 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600705 });
706 });
Tyler Scottcdfcde82015-09-14 16:13:29 -0600707 //Toggle the menus. (Only respond when the immediate tab is clicked.)
Tyler Scottf912dea2016-08-09 21:50:34 +0000708 e.find('> a').click(function(e) {
709 e.preventDefault();
Tyler Scottcdfcde82015-09-14 16:13:29 -0600710 scope.categories.find('.subnav').slideUp();
711 var t = $(this).siblings('.subnav');
Tyler Scott66a965d2016-02-29 15:41:33 -0700712 if (!t.is(':visible')) {
713 //If the sub menu is not visible
714 t.slideDown(function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600715 t.triggerHandler('focus');
Tyler Scott66a965d2016-02-29 15:41:33 -0700716 });
717 //Make it visible and look at it.
Tyler Scottcdfcde82015-09-14 16:13:29 -0600718 }
719 });
Tyler Scottcdfcde82015-09-14 16:13:29 -0600720 scope.categories.append(e);
Tyler Scottcdfcde82015-09-14 16:13:29 -0600721 });
722 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700723 }, function(interest) {
724 //Timeout
Tyler Scottcdfcde82015-09-14 16:13:29 -0600725 scope.createAlert("Failed to initialize the filters!", "alert-danger");
726 console.error("Failed to initialize filters!", interest);
727 ga('send', 'event', 'error', 'filters');
728 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700729 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600730
731 /**
732 * This function retrieves all segments in order until it knows it has reached the last one.
733 * It then returns the final joined result.
Tyler Scott66a965d2016-02-29 15:41:33 -0700734
Tyler Scottf355e452015-11-06 21:35:14 -0700735 * @param prefix {String|Name} The ndn name we are retrieving.
736 * @param callback {function(String)} if successful, will call the callback with a string of data.
737 * @param failure {function(Interest)} if unsuccessful, will call failure with the last failed interest.
738 * @param stop {boolean} stop if no finalBlock.
Tyler Scottcdfcde82015-09-14 16:13:29 -0600739 */
Tyler Scott66a965d2016-02-29 15:41:33 -0700740 Atmos.prototype.getAll = function(prefix, callback, failure, stop) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600741 var scope = this;
742 var d = [];
Tyler Scottd61bf832015-11-30 16:36:17 -0700743 var name = new Name(prefix);
744 var segment = 0;
Tyler Scott66a965d2016-02-29 15:41:33 -0700745 var request = function() {
Tyler Scottd61bf832015-11-30 16:36:17 -0700746 var n2 = new Name(name);
747 n2.appendSegment(segment);
Tyler Scott7ae6be02016-06-22 15:29:26 -0600748 scope.expressInterest(n2, handleData, function(err, interest) {
749 failure(interest)
750 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700751 //Forward to handleData and ignore error
752 }
Tyler Scott66a965d2016-02-29 15:41:33 -0700753 var handleData = function(interest, data) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600754 d.push(data.getContent().toString());
Tyler Scottf355e452015-11-06 21:35:14 -0700755 var hasFinalBlock = data.getMetaInfo().getFinalBlockId().value.length === 0;
756 var finalBlockStop = hasFinalBlock && stop;
Tyler Scott7ae6be02016-06-22 15:29:26 -0600757 if (finalBlockStop || (!hasFinalBlock && interest.getName().get(-1).toSegment() == data.getMetaInfo().getFinalBlockId().toSegment())) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600758 callback(d.join(""));
759 } else {
Tyler Scottd61bf832015-11-30 16:36:17 -0700760 segment++;
761 request();
Tyler Scottcdfcde82015-09-14 16:13:29 -0600762 }
Tyler Scott66a965d2016-02-29 15:41:33 -0700763 }
Tyler Scottd61bf832015-11-30 16:36:17 -0700764 request();
Tyler Scott66a965d2016-02-29 15:41:33 -0700765 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600766
Tyler Scott66a965d2016-02-29 15:41:33 -0700767 Atmos.prototype.cleanRequestForm = function() {
Tyler Scottb59e6de2015-09-18 14:46:30 -0600768 $('#requestDest').prev().removeClass('btn-success').addClass('btn-default');
769 $('#requestDropText').text('Destination');
770 $('#requestDest .active').removeClass('active');
Tyler Scottf355e452015-11-06 21:35:14 -0700771 $('#subsetMenu').attr('class', 'collapse');
772 $('#subsetVariables').empty();
773 $('#request .alert').alert('close').remove();
Tyler Scott66a965d2016-02-29 15:41:33 -0700774 }
Tyler Scottb59e6de2015-09-18 14:46:30 -0600775
Tyler Scott66a965d2016-02-29 15:41:33 -0700776 Atmos.prototype.setupRequestForm = function() {
Tyler Scottb59e6de2015-09-18 14:46:30 -0600777 var scope = this;
Tyler Scott66a965d2016-02-29 15:41:33 -0700778 this.requestForm.find('#requestCancel').click(function() {
779 $('#request').unbind('submit')//Removes all event handlers.
780 .modal('hide');
781 //Hides the form.
Tyler Scottb59e6de2015-09-18 14:46:30 -0600782 scope.cleanRequestForm();
Tyler Scottcdfcde82015-09-14 16:13:29 -0600783 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700784 var dests = $(this.config['retrieval']['destinations'].reduce(function(prev, current) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600785 prev.push('<li><a href="#">');
786 prev.push(current);
787 prev.push("</a></li>");
788 return prev;
789 }, []).join(""));
Tyler Scott7ae6be02016-06-22 15:29:26 -0600790 this.requestForm.find('#requestDest').append(dests).on('click', 'a', function(e) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600791 $('#requestDest .active').removeClass('active');
Tyler Scottb59e6de2015-09-18 14:46:30 -0600792 var t = $(this);
793 t.parent().addClass('active');
794 $('#requestDropText').text(t.text());
795 $('#requestDest').prev().removeClass('btn-default').addClass('btn-success');
Tyler Scottcdfcde82015-09-14 16:13:29 -0600796 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700797 var addVariable = function(selector) {
798 var ele = $(selector).clone().attr('id', '');
799 ele.find('.close').click(function() {
Tyler Scottf355e452015-11-06 21:35:14 -0700800 ele.remove();
801 });
802 $('#subsetVariables').append(ele);
Tyler Scott66a965d2016-02-29 15:41:33 -0700803 }
Tyler Scott66a965d2016-02-29 15:41:33 -0700804 $('#subsetAddVariableBtn').click(function() {
Tyler Scottf355e452015-11-06 21:35:14 -0700805 addVariable('#customTemplate');
806 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700807 $('#subsetAddTimeVariable').click(function() {
Tyler Scottf355e452015-11-06 21:35:14 -0700808 addVariable('#timeTemplate');
809 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700810 $('#subsetAddLocVariable').click(function() {
Tyler Scottf355e452015-11-06 21:35:14 -0700811 addVariable('#locationTemplate');
812 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700813 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600814
Tyler Scott66a965d2016-02-29 15:41:33 -0700815 Atmos.prototype.getMetaData = (function() {
Tyler Scott48f92cd2015-10-16 18:31:20 -0600816 var cache = {};
Tyler Scott48f92cd2015-10-16 18:31:20 -0600817 return function(element) {
818 var name = $(element).text();
Tyler Scottf355e452015-11-06 21:35:14 -0700819 ga('send', 'event', 'request', 'metaData');
Tyler Scottf355e452015-11-06 21:35:14 -0700820 var subsetButton = '<button class="btn btn-default subsetButton" type="button">Subset</button>';
Tyler Scott48f92cd2015-10-16 18:31:20 -0600821 if (cache[name]) {
Tyler Scottf355e452015-11-06 21:35:14 -0700822 return [subsetButton, '<pre class="metaData">', cache[name], '</pre>'].join('');
Tyler Scott48f92cd2015-10-16 18:31:20 -0600823 }
Tyler Scott48f92cd2015-10-16 18:31:20 -0600824 var prefix = new Name(name).append("metadata");
Tyler Scott66a965d2016-02-29 15:41:33 -0700825 var id = guid();
826 //We need an id because the return MUST be a string.
Tyler Scott48f92cd2015-10-16 18:31:20 -0600827 var ret = '<div id="' + id + '"><span class="fa fa-spinner fa-spin"></span></div>';
Tyler Scott66a965d2016-02-29 15:41:33 -0700828 this.getAll(prefix, function(data) {
Tyler Scott48f92cd2015-10-16 18:31:20 -0600829 var el = $('<pre class="metaData"></pre>');
830 el.text(data);
Tyler Scottf355e452015-11-06 21:35:14 -0700831 var container = $('<div></div>');
832 container.append($(subsetButton));
833 container.append(el);
834 $('#' + id).empty().append(container);
Tyler Scott48f92cd2015-10-16 18:31:20 -0600835 cache[name] = data;
Tyler Scott66a965d2016-02-29 15:41:33 -0700836 }, function(interest) {
Tyler Scott48f92cd2015-10-16 18:31:20 -0600837 $('#' + id).text("The metadata is unavailable for this name.");
838 console.log("Data is unavailable for " + name);
839 });
Tyler Scott48f92cd2015-10-16 18:31:20 -0600840 return ret;
Tyler Scott66a965d2016-02-29 15:41:33 -0700841 }
Tyler Scott48f92cd2015-10-16 18:31:20 -0600842 })();
843
Tyler Scottcdfcde82015-09-14 16:13:29 -0600844 return Atmos;
845
846})();