blob: 447afa264f93e8e61fbfd91b071b7a558a59685a [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 Scottcdfcde82015-09-14 16:13:29 -06006 Promise.all([
Tyler Scott66a965d2016-02-29 15:41:33 -07007 new Promise(function(resolve, reject) {
8 $.ajax('../config.json').done(function(data) {
9 config = data;
10 resolve();
11 }).fail(function() {
12 console.error("Failed to get config.");
13 ga('send', 'event', 'error', 'config');
14 reject();
15 });
Tyler Scott384f37a2016-05-05 16:09:05 -060016 }),
Tyler Scott66a965d2016-02-29 15:41:33 -070017 new Promise(function(resolve, reject) {
18 var timeout = setTimeout(function() {
19 console.error("Document never loaded? Something bad has happened!");
20 reject();
21 }, 10000);
22 $(function() {
23 clearTimeout(timeout);
24 resolve();
25 });
Tyler Scott384f37a2016-05-05 16:09:05 -060026 }),
27 new Promise(function(resolve, reject) {
28 $.getJSON('../conversions.json').done(function(data) {
29 conversions = data;
30 resolve();
31 }).fail(function(){
32 console.error("Failed to get conversions.");
33 ga('send', 'event', 'error', 'config');
34 //reject(); We will continue anyways. We don't need this functionality.
35 conversions = {};
36 resolve();
37 });
38 })
Tyler Scott66a965d2016-02-29 15:41:33 -070039 ]).then(function() {
Tyler Scott2118a412015-10-29 15:17:05 -060040
Tyler Scott66a965d2016-02-29 15:41:33 -070041 var getParameterByName = function(name) {
42 name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
43 var regex = new RegExp("[\\?&]" + name + "=([^&#]*)");
44 var results = regex.exec(location.search);
45 return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
46 }
Tyler Scott2118a412015-10-29 15:17:05 -060047
48 //Overwrite config if present. Any failure will just cause this to be skipped.
Tyler Scott66a965d2016-02-29 15:41:33 -070049 try {
Tyler Scott2118a412015-10-29 15:17:05 -060050 var configParam = JSON.parse(getParameterByName('config'));
51 config = jQuery.extend(true, config, configParam);
Tyler Scott66a965d2016-02-29 15:41:33 -070052 } catch (e) {
Tyler Scott2118a412015-10-29 15:17:05 -060053 console.warn("Failure in config overwrite, skipping.", e);
54 }
55
Tyler Scott384f37a2016-05-05 16:09:05 -060056 new Atmos(config, conversions);
Tyler Scott66a965d2016-02-29 15:41:33 -070057 }, function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -060058 console.error("Failed to initialize!");
59 ga('send', 'event', 'error', 'init');
60 });
61})();
62
Tyler Scott66a965d2016-02-29 15:41:33 -070063var Atmos = (function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -060064 "use strict";
65
66 var closeButton = '<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>';
67
Tyler Scott66a965d2016-02-29 15:41:33 -070068 var guid = function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -060069 var d = new Date().getTime();
70 var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
Tyler Scott66a965d2016-02-29 15:41:33 -070071 var r = (d + Math.random() * 16) % 16 | 0;
72 d = Math.floor(d / 16);
73 return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
Tyler Scottcdfcde82015-09-14 16:13:29 -060074 });
75 return uuid;
Tyler Scott66a965d2016-02-29 15:41:33 -070076 }
Tyler Scottcdfcde82015-09-14 16:13:29 -060077
78 /**
79 * Atmos
80 * @version 2.0
Tyler Scott66a965d2016-02-29 15:41:33 -070081
Tyler Scottcdfcde82015-09-14 16:13:29 -060082 * Configures an Atmos object. This manages the atmos interface.
Tyler Scott66a965d2016-02-29 15:41:33 -070083
Tyler Scottcdfcde82015-09-14 16:13:29 -060084 * @constructor
85 * @param {string} catalog - NDN path
86 * @param {Object} config - Object of configuration options for a Face.
87 */
Tyler Scott384f37a2016-05-05 16:09:05 -060088 var Atmos = function(config, conversions) {
Tyler Scottcdfcde82015-09-14 16:13:29 -060089
90 //Internal variables.
91 this.results = [];
92 this.resultCount = Infinity;
Tyler Scott66a965d2016-02-29 15:41:33 -070093 this.name = null ;
Tyler Scottcdfcde82015-09-14 16:13:29 -060094 this.page = 0;
95 this.resultsPerPage = 25;
96 this.retrievedSegments = 0;
97
98 //Config/init
99 this.config = config;
Tyler Scott384f37a2016-05-05 16:09:05 -0600100 this.conversions = conversions;
Tyler Scottcdfcde82015-09-14 16:13:29 -0600101
102 this.catalog = config['global']['catalogPrefix'];
Chengyu Fan7b978f82015-12-09 17:03:23 -0700103 this.catalogPrefix = new Name(this.catalog);
Tyler Scottcdfcde82015-09-14 16:13:29 -0600104
105 this.face = new Face(config['global']['faceConfig']);
106
107 //Easy access dom variables
108 this.categories = $('#side-menu');
109 this.resultTable = $('#resultTable');
110 this.filters = $('#filters');
111 this.searchInput = $('#search');
112 this.searchBar = $('#searchBar');
113 this.searchButton = $('#searchButton');
114 this.resultMenu = $('.resultMenu');
115 this.alerts = $('#alerts');
116 this.requestForm = $('#requestForm');
117
118 var scope = this;
119
Tyler Scott66a965d2016-02-29 15:41:33 -0700120 $('.requestSelectedButton').click(function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600121 ga('send', 'event', 'button', 'click', 'request');
122 scope.request(scope.resultTable.find('.resultSelector:checked:not([disabled])').parent().parent());
123 });
124
125 this.filterSetup();
126
127 //Init autocomplete
Tyler Scott66a965d2016-02-29 15:41:33 -0700128 this.searchInput.autoComplete(function(field, callback) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600129 ga('send', 'event', 'search', 'autocomplete');
Tyler Scott66a965d2016-02-29 15:41:33 -0700130 scope.autoComplete(field, function(data) {
Tyler Scott94458992015-09-24 14:16:28 -0700131 var list = data.next;
132 var last = data.lastComponent === true;
Tyler Scott66a965d2016-02-29 15:41:33 -0700133 callback(list.map(function(element) {
134 return field + element + (last ? "/" : "");
135 //Don't add trailing slash for last component.
Tyler Scottcdfcde82015-09-14 16:13:29 -0600136 }));
137 });
138 });
139
140 //Handle search
Tyler Scott66a965d2016-02-29 15:41:33 -0700141 this.searchBar.submit(function(e) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600142 ga('send', 'event', 'search', 'submit');
143 e.preventDefault();
Tyler Scott66a965d2016-02-29 15:41:33 -0700144 if (scope.searchInput.val().length === 0) {
145 if (!scope.searchBar.hasClass('has-error')) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600146 scope.searchBar.addClass('has-error').append('<span class="help-block">Search path is required!</span>');
147 }
148 return;
149 } else {
Tyler Scott66a965d2016-02-29 15:41:33 -0700150 scope.searchBar.removeClass('has-error').find('.help-block').fadeOut(function() {
151 $(this).remove()
152 });
Tyler Scottcdfcde82015-09-14 16:13:29 -0600153 }
154 scope.pathSearch();
155 });
156
Tyler Scott66a965d2016-02-29 15:41:33 -0700157 this.searchButton.click(function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600158 console.log("Search Button Pressed");
159 ga('send', 'event', 'button', 'click', 'search');
160 scope.search();
161 });
162
163 //Result navigation handlers
Tyler Scott66a965d2016-02-29 15:41:33 -0700164 this.resultMenu.find('.next').click(function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600165 ga('send', 'event', 'button', 'click', 'next');
Tyler Scott66a965d2016-02-29 15:41:33 -0700166 if (!$(this).hasClass('disabled')) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600167 scope.getResults(scope.page + 1);
168 }
169 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700170 this.resultMenu.find('.previous').click(function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600171 ga('send', 'event', 'button', 'click', 'previous');
Tyler Scott66a965d2016-02-29 15:41:33 -0700172 if (!$(this).hasClass('disabled')) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600173 scope.getResults(scope.page - 1);
174 }
175 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700176 this.resultMenu.find('.clearResults').click(function() {
Tyler Scotte8dac702015-10-13 14:33:25 -0600177 ga('send', 'event', 'button', 'click', 'resultClear');
178 scope.clearResults();
Tyler Scott66a965d2016-02-29 15:41:33 -0700179 $('#results').fadeOut(function() {
Tyler Scotte8dac702015-10-13 14:33:25 -0600180 $(this).addClass('hidden');
181 });
182 });
Tyler Scottcdfcde82015-09-14 16:13:29 -0600183
184 //Change the number of results per page handler
Tyler Scott66a965d2016-02-29 15:41:33 -0700185 var rpps = $('.resultsPerPageSelector').click(function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600186
187 var t = $(this);
188
Tyler Scott66a965d2016-02-29 15:41:33 -0700189 if (t.hasClass('active')) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600190 return;
191 }
192
193 rpps.find('.active').removeClass('active');
194 t.addClass('active');
195 scope.resultsPerPage = Number(t.text());
Tyler Scott66a965d2016-02-29 15:41:33 -0700196 scope.getResults(0);
197 //Force return to page 1;
Tyler Scottcdfcde82015-09-14 16:13:29 -0600198
199 });
200
201 //Init tree search
Tyler Scott66a965d2016-02-29 15:41:33 -0700202 $('#treeSearch div').treeExplorer(function(path, callback) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600203 console.log("Tree Explorer request", path);
204 ga('send', 'event', 'tree', 'request');
Tyler Scott66a965d2016-02-29 15:41:33 -0700205 scope.autoComplete(path, function(data) {
Tyler Scottb59e6de2015-09-18 14:46:30 -0600206 var list = data.next;
207 var last = (data.lastComponent === true);
Tyler Scottbb42ed22015-10-21 17:02:56 -0600208
209 if (last) {
210 console.log("Redirecting last element request to a search.");
211 scope.clearResults();
Tyler Scott66a965d2016-02-29 15:41:33 -0700212 scope.query(scope.catalog, {
213 '??': path
214 },
215 function(interest, data) {
Tyler Scottbb42ed22015-10-21 17:02:56 -0600216 console.log("Search response", interest, data);
Chengyu Fan7b978f82015-12-09 17:03:23 -0700217 scope.name = interest.getName();
Tyler Scottbb42ed22015-10-21 17:02:56 -0600218 scope.getResults(0);
Tyler Scott66a965d2016-02-29 15:41:33 -0700219 }, function(interest) {
Tyler Scottbb42ed22015-10-21 17:02:56 -0600220 console.warn("Failed to retrieve final component.", interest, path);
221 scope.createAlert("Failed to request final component. " + path + " See console for details.");
222 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700223 return;
224 //Don't call the callback
Tyler Scottbb42ed22015-10-21 17:02:56 -0600225 }
226
Tyler Scottcdfcde82015-09-14 16:13:29 -0600227 console.log("Autocomplete response", list);
Tyler Scott66a965d2016-02-29 15:41:33 -0700228 callback(list.map(function(element) {
229 return (path == "/" ? "/" : "") + element + "/";
Tyler Scottcdfcde82015-09-14 16:13:29 -0600230 }));
Chengyu Fan7b978f82015-12-09 17:03:23 -0700231 });
Tyler Scottcdfcde82015-09-14 16:13:29 -0600232 });
233
Tyler Scott66a965d2016-02-29 15:41:33 -0700234 $('#treeSearch').on('click', '.treeSearch', function() {
Tyler Scottb59e6de2015-09-18 14:46:30 -0600235 var t = $(this);
236
237 scope.clearResults();
238
239 var path = t.parent().parent().attr('id');
240
Tyler Scottbb42ed22015-10-21 17:02:56 -0600241 console.log("Tree search:", path);
Tyler Scottb59e6de2015-09-18 14:46:30 -0600242
Tyler Scott66a965d2016-02-29 15:41:33 -0700243 scope.query(scope.catalog, {
244 '??': path
245 },
246 function(interest, data) {
247 //Success
Tyler Scottb59e6de2015-09-18 14:46:30 -0600248 console.log("Tree search response", interest, data);
249
Chengyu Fan7b978f82015-12-09 17:03:23 -0700250 scope.name = interest.getName();
Tyler Scottb59e6de2015-09-18 14:46:30 -0600251
252 scope.getResults(0);
253 },
Tyler Scott66a965d2016-02-29 15:41:33 -0700254 function(interest) {
255 //Failure
Tyler Scottb59e6de2015-09-18 14:46:30 -0600256 console.warn("Request failed! Timeout", interest);
Tyler Scott66a965d2016-02-29 15:41:33 -0700257 scope.createAlert("Request timed out.\"" + interest.getName().toUri() + "\" See console for details.");
Tyler Scottb59e6de2015-09-18 14:46:30 -0600258 });
259
260 });
261
Tyler Scottcdfcde82015-09-14 16:13:29 -0600262 this.setupRequestForm();
263
Tyler Scott48f92cd2015-10-16 18:31:20 -0600264 this.resultTable.popover({
Tyler Scott66a965d2016-02-29 15:41:33 -0700265 selector: ".metaDataLink",
266 content: function() {
Tyler Scott48f92cd2015-10-16 18:31:20 -0600267 return scope.getMetaData(this);
268 },
269 title: "Metadata",
270 html: true,
271 trigger: 'click',
272 placement: 'bottom'
273 });
274
Tyler Scott66a965d2016-02-29 15:41:33 -0700275 this.resultTable.on('click', '.metaDataLink', function(e) {
Tyler Scott48f92cd2015-10-16 18:31:20 -0600276 //This prevents the page from scrolling when you click on a name.
277 e.preventDefault();
278 });
279
Tyler Scott66a965d2016-02-29 15:41:33 -0700280 this.resultTable.on('click', '.subsetButton', function() {
Tyler Scottf355e452015-11-06 21:35:14 -0700281 var metaData = $(this).siblings('pre').text();
282 var exp = /netcdf ([\w-]+)/;
283 var match = exp.exec(metaData);
Tyler Scott66a965d2016-02-29 15:41:33 -0700284 var filename = match[0].replace(/netcdf /, '') + '.nc';
285 scope.request(null , filename);
Tyler Scottf355e452015-11-06 21:35:14 -0700286 });
287
Tyler Scott66a965d2016-02-29 15:41:33 -0700288 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600289
Tyler Scott66a965d2016-02-29 15:41:33 -0700290 Atmos.prototype.clearResults = function() {
291 this.results = [];
292 //Drop any old results.
Tyler Scottcdfcde82015-09-14 16:13:29 -0600293 this.retrievedSegments = 0;
294 this.resultCount = Infinity;
295 this.page = 0;
296 this.resultTable.empty();
Tyler Scott66a965d2016-02-29 15:41:33 -0700297 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600298
Tyler Scott66a965d2016-02-29 15:41:33 -0700299 Atmos.prototype.pathSearch = function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600300 var value = this.searchInput.val();
301
302 this.clearResults();
303
304 var scope = this;
305
Tyler Scott66a965d2016-02-29 15:41:33 -0700306 this.query(this.catalog, {
307 "??": value
308 },
309 function(interest, data) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600310 console.log("Query response:", interest, data);
311
Tyler Scott66a965d2016-02-29 15:41:33 -0700312 scope.name = interest.getName();
Tyler Scottcdfcde82015-09-14 16:13:29 -0600313
314 scope.getResults(0);
315
316 },
Tyler Scott66a965d2016-02-29 15:41:33 -0700317 function(interest) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600318 console.warn("Request failed! Timeout", interest);
319 scope.createAlert("Request timed out. \"" + interest.getName().toUri() + "\" See console for details.");
320 });
321
Tyler Scott66a965d2016-02-29 15:41:33 -0700322 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600323
Tyler Scott66a965d2016-02-29 15:41:33 -0700324 Atmos.prototype.search = function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600325
326 var filters = this.getFilters();
327
328 console.log("Search started!", this.searchInput.val(), filters);
329
330 console.log("Initiating query");
331
332 this.clearResults();
333
334 var scope = this;
335
336 this.query(this.catalog, filters,
Tyler Scott66a965d2016-02-29 15:41:33 -0700337 function(interest, data) {
338 //Response function
Tyler Scottcdfcde82015-09-14 16:13:29 -0600339 console.log("Query Response:", interest, data);
340
Chengyu Fan7b978f82015-12-09 17:03:23 -0700341 scope.name = interest.getName();
Tyler Scottcdfcde82015-09-14 16:13:29 -0600342
343 scope.getResults(0);
344
Tyler Scott66a965d2016-02-29 15:41:33 -0700345 }, function(interest) {
346 //Timeout function
Tyler Scottd980a292015-10-13 15:16:34 -0600347 console.warn("Request failed after 3 attempts!", interest);
348 scope.createAlert("Request failed after 3 attempts. \"" + interest.getName().toUri() + "\" See console for details.");
Tyler Scottcdfcde82015-09-14 16:13:29 -0600349 });
350
Tyler Scott66a965d2016-02-29 15:41:33 -0700351 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600352
Tyler Scott66a965d2016-02-29 15:41:33 -0700353 Atmos.prototype.autoComplete = function(field, callback) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600354
355 var scope = this;
356
Tyler Scott66a965d2016-02-29 15:41:33 -0700357 var result = {};
Tyler Scottcdfcde82015-09-14 16:13:29 -0600358
Tyler Scott66a965d2016-02-29 15:41:33 -0700359 const getAll = function(interest, data) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600360
Tyler Scott66a965d2016-02-29 15:41:33 -0700361 if (data.getContent().length !== 0) {
362 var resp = JSON.parse(data.getContent().toString().replace(/[\n\0]/g, ""));
363 if (result.next) {
364 result.next = result.next.concat(resp.next);
365 } else {
366 result = resp;
Tyler Scottd61bf832015-11-30 16:36:17 -0700367 }
Tyler Scott66a965d2016-02-29 15:41:33 -0700368 } else {
369 callback(result);
370 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600371
Tyler Scott66a965d2016-02-29 15:41:33 -0700372 var name = data.getName();
373 var segment = name.components[name.getComponentCount() - 1];
374 if (segment.toSegment() !== data.getMetaInfo().getFinalBlockId().toSegment()){
375 name = name.getPrefix(-1); //Remove segment
376 name.appendSegment(segment.toSegment() + 1);
377 scope.expressInterest(name, getAll, function() {
378 console.warn("Autocomplete timed out, results may be incomplete.");
379 callback(result);
380 //Return if we get a timeout.
381 });
382 } else {
383 callback(result);
384 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600385
Tyler Scott66a965d2016-02-29 15:41:33 -0700386 }
387
388 this.query(this.catalog, {
389 "?": field
390 }, getAll);
391
392 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600393
394 Atmos.prototype.showResults = function(resultIndex) {
395
396 var results = this.results.slice(this.resultsPerPage * resultIndex, this.resultsPerPage * (resultIndex + 1));
397
398 var resultDOM = $(
Tyler Scott66a965d2016-02-29 15:41:33 -0700399 results.reduce(function(prev, current) {
400 prev.push('<tr><td><input class="resultSelector" type="checkbox"></td><td class="popover-container"><a href="#" class="metaDataLink">');
401 prev.push(current);
402 prev.push('</a></td></tr>');
403 return prev;
404 }, ['<tr><th><input id="resultSelectAll" type="checkbox" title="Select All"> Select</th><th>Name</th></tr>']).join('')
Tyler Scottcdfcde82015-09-14 16:13:29 -0600405 );
406
Tyler Scott66a965d2016-02-29 15:41:33 -0700407 resultDOM.find('#resultSelectAll').click(function() {
408 if ($(this).is(':checked')) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600409 resultDOM.find('.resultSelector:not([disabled])').prop('checked', true);
410 } else {
411 resultDOM.find('.resultSelector:not([disabled])').prop('checked', false);
412 }
413 });
414
415 this.resultTable.hide().empty().append(resultDOM).slideDown('slow');
416
417 this.resultMenu.find('.pageNumber').text(resultIndex + 1);
418 this.resultMenu.find('.pageLength').text(this.resultsPerPage * resultIndex + results.length);
419
420 if (this.resultsPerPage * (resultIndex + 1) >= this.resultCount) {
421 this.resultMenu.find('.next').addClass('disabled');
Tyler Scott66a965d2016-02-29 15:41:33 -0700422 } else if (resultIndex === 0) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600423 this.resultMenu.find('.next').removeClass('disabled');
424 }
425
Tyler Scott66a965d2016-02-29 15:41:33 -0700426 if (resultIndex === 0) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600427 this.resultMenu.find('.previous').addClass('disabled');
428 } else if (resultIndex === 1) {
429 this.resultMenu.find('.previous').removeClass('disabled');
430 }
431
Tyler Scott66a965d2016-02-29 15:41:33 -0700432 $.scrollTo("#results", 500, {
433 interrupt: true
434 });
Tyler Scottf355e452015-11-06 21:35:14 -0700435
Tyler Scott66a965d2016-02-29 15:41:33 -0700436 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600437
Tyler Scott66a965d2016-02-29 15:41:33 -0700438 Atmos.prototype.getResults = function(index) {
Chengyu Fan7b978f82015-12-09 17:03:23 -0700439 var scope = this;
Tyler Scottcdfcde82015-09-14 16:13:29 -0600440
Tyler Scott66a965d2016-02-29 15:41:33 -0700441 if ($('#results').hasClass('hidden')) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600442 $('#results').removeClass('hidden').slideDown();
443 }
444
Tyler Scott66a965d2016-02-29 15:41:33 -0700445 if ((scope.results.length === scope.resultCount) || (scope.resultsPerPage * (index + 1) < scope.results.length)) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600446 //console.log("We already have index", index);
Chengyu Fan7b978f82015-12-09 17:03:23 -0700447 scope.page = index;
448 scope.showResults(index);
Tyler Scottcdfcde82015-09-14 16:13:29 -0600449 return;
450 }
451
Tyler Scott66a965d2016-02-29 15:41:33 -0700452 if (scope.name === null ) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600453 console.error("This shouldn't be reached! We are getting results before a search has occured!");
454 throw new Error("Illegal State");
455 }
456
Chengyu Fan7b978f82015-12-09 17:03:23 -0700457 var interestName = new Name(scope.name);
Tyler Scottcdfcde82015-09-14 16:13:29 -0600458
Chengyu Fan7b978f82015-12-09 17:03:23 -0700459 // Interest name should be /<catalog-prefix>/query/<query-param>/<version>/<#seq>
460 if (scope.name.size() === (scope.catalogPrefix.size() + 3)) {
461 interestName = interestName.appendSegment(scope.retrievedSegments++);
Tyler Scott66a965d2016-02-29 15:41:33 -0700462 //console.log("Requesting data index: (", scope.retrievedSegments - 1, ") at ", interestName.toUri());
Chengyu Fan7b978f82015-12-09 17:03:23 -0700463 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600464
Tyler Scott66a965d2016-02-29 15:41:33 -0700465 this.expressInterest(interestName,
466 function(interest, data) {
467 //Response
Tyler Scottcdfcde82015-09-14 16:13:29 -0600468
Tyler Scott66a965d2016-02-29 15:41:33 -0700469 if (data.getContent().length === 0) {
470 scope.resultMenu.find('.totalResults').text(0);
471 scope.resultMenu.find('.pageNumber').text(0);
472 scope.resultMenu.find('.pageLength').text(0);
473 console.log("Empty response.");
474 scope.resultTable.html("<tr><td>Empty response. This usually means no results.</td></tr>");
475 return;
Tyler Scottcdfcde82015-09-14 16:13:29 -0600476 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600477
Tyler Scott66a965d2016-02-29 15:41:33 -0700478 var content = JSON.parse(data.getContent().toString().replace(/[\n\0]/g, ""));
479
480 if (!content.results) {
481 scope.resultMenu.find('.totalResults').text(0);
482 scope.resultMenu.find('.pageNumber').text(0);
483 scope.resultMenu.find('.pageLength').text(0);
484 console.log("No results were found!");
485 scope.resultTable.html("<tr><td>No Results</td></tr>");
486 return;
487 }
488
489 scope.results = scope.results.concat(content.results);
490
491 scope.resultCount = content.resultCount;
492
493 scope.resultMenu.find('.totalResults').text(scope.resultCount);
494
495 scope.page = index;
496
497 // reset scope.name
498 scope.name = new Name(data.getName().getPrefix(scope.catalogPrefix.size() + 3));
499
500 scope.getResults(index);
501 //Keep calling this until we have enough data.
502
503 }, function() {}//Ignore failure
504 );
505
506 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600507
508 Atmos.prototype.query = function(prefix, parameters, callback, timeout) {
509
510 var queryPrefix = new Name(prefix);
511 queryPrefix.append("query");
512
513 var jsonString = JSON.stringify(parameters);
514 queryPrefix.append(jsonString);
515
Tyler Scott66a965d2016-02-29 15:41:33 -0700516 this.expressInterest(queryPrefix, callback, timeout);
Tyler Scottcdfcde82015-09-14 16:13:29 -0600517
Tyler Scott66a965d2016-02-29 15:41:33 -0700518 }
Tyler Scottd61bf832015-11-30 16:36:17 -0700519
Tyler Scott66a965d2016-02-29 15:41:33 -0700520
521 Atmos.prototype.expressInterest = function(name, success, failure) {
522
523 var interest = new Interest(name);
524 interest.setInterestLifetimeMilliseconds(1500);
525 interest.setMustBeFresh(true);
526
527 const face = this.face;
528
529 async.retry(4, function(done) {
530 face.expressInterest(interest, function(interest, data) {
Tyler Scottd61bf832015-11-30 16:36:17 -0700531 done();
Tyler Scott66a965d2016-02-29 15:41:33 -0700532 success(interest, data);
533 }, function(interest) {
534 done("Interest timed out 4 times.", interest);
535 });
536 }, function(err, interest) {
537 if (err) {
538 console.log(err, interest);
539 failure(interest);
Tyler Scott8724e422015-10-13 17:59:07 -0600540 }
Tyler Scottd61bf832015-11-30 16:36:17 -0700541 });
Tyler Scottcdfcde82015-09-14 16:13:29 -0600542
Tyler Scott66a965d2016-02-29 15:41:33 -0700543 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600544
545 /**
546 * This function returns a map of all the categories active filters.
547 * @return {Object<string, string>}
548 */
Tyler Scott66a965d2016-02-29 15:41:33 -0700549 Atmos.prototype.getFilters = function() {
550 var filters = this.filters.children().toArray().reduce(function(prev, current) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600551 var data = $(current).text().split(/:/);
552 prev[data[0]] = data[1];
553 return prev;
Tyler Scott66a965d2016-02-29 15:41:33 -0700554 }, {});
555 //Collect a map<category, filter>.
Tyler Scottcdfcde82015-09-14 16:13:29 -0600556 //TODO Make the return value map<category, Array<filter>>
557 return filters;
Tyler Scott66a965d2016-02-29 15:41:33 -0700558 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600559
560 /**
561 * Creates a closable alert for the user.
Tyler Scott66a965d2016-02-29 15:41:33 -0700562
Tyler Scottcdfcde82015-09-14 16:13:29 -0600563 * @param {string} message
564 * @param {string} type - Override the alert type.
565 */
566 Atmos.prototype.createAlert = function(message, type) {
567
568 var alert = $('<div class="alert"><div>');
Tyler Scott66a965d2016-02-29 15:41:33 -0700569 alert.addClass(type ? type : 'alert-info');
Tyler Scottcdfcde82015-09-14 16:13:29 -0600570 alert.text(message);
571 alert.append(closeButton);
572
573 this.alerts.append(alert);
Tyler Scott66a965d2016-02-29 15:41:33 -0700574 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600575
576 /**
577 * Requests all of the names represented by the buttons in the elements list.
Tyler Scott66a965d2016-02-29 15:41:33 -0700578
Tyler Scottcdfcde82015-09-14 16:13:29 -0600579 * @param elements {Array<jQuery>} A list of the table row elements
Tyler Scottf355e452015-11-06 21:35:14 -0700580 * @param subsetFileName {String} If present then do a subsetting request instead.
Tyler Scottcdfcde82015-09-14 16:13:29 -0600581 */
Tyler Scott66a965d2016-02-29 15:41:33 -0700582 Atmos.prototype.request = function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600583
584 //Pseudo globals.
585 var keyChain;
586 var certificateName;
587 var keyAdded = false;
588
Tyler Scott66a965d2016-02-29 15:41:33 -0700589 return function(elements, subsetFilename) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600590
591 var names = [];
Tyler Scott66a965d2016-02-29 15:41:33 -0700592 $(elements).find('.metaDataLink').each(function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600593 var name = $(this).text();
594 names.push(name);
Tyler Scottf355e452015-11-06 21:35:14 -0700595 });
596
597 var subset = false;
598
Tyler Scott66a965d2016-02-29 15:41:33 -0700599 if (!subsetFilename) {
Tyler Scottf355e452015-11-06 21:35:14 -0700600 $('#subsetting').hide();
601 } else {
602 $('#subsetting').show();
603 subset = true;
604 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600605
606 var scope = this;
Tyler Scott384f37a2016-05-05 16:09:05 -0600607
608 //FIXME The following is temporary, it allows people to direct download from
609 //a single host with a small set of names. It is to demo the functionality but
610 //could use improvement. (Multiple servers, non static list, etc)
611 var directDls = $('#directDownloadList').empty();
612 names.forEach(function(name){
613 if (scope.conversions[name]){ //If the name exists in the conversions.
614 var ele = $('<a href="http://atmos-mwsc.ucar.edu/ucar/' + conversions[name] + '" class="list-group-item>' + name + '</a>');
615 directDls.append(ele);
616 }
617 });
618
Tyler Scott66a965d2016-02-29 15:41:33 -0700619 this.requestForm.on('submit', function(e) {
620 //This will be registered for the next submit from the form.
Tyler Scottcdfcde82015-09-14 16:13:29 -0600621 e.preventDefault();
622
Tyler Scottf355e452015-11-06 21:35:14 -0700623 $('#request .alert').remove();
624
625 var variables = [];
Tyler Scott66a965d2016-02-29 15:41:33 -0700626 if (subset) {
627 $('#subsetVariables .row').each(function() {
Tyler Scottf355e452015-11-06 21:35:14 -0700628 var t = $(this);
629 var values = {};
Tyler Scott66a965d2016-02-29 15:41:33 -0700630 t.find('.values input').each(function() {
Tyler Scottf355e452015-11-06 21:35:14 -0700631 var t = $(this);
632 values[t.attr('name')] = t.val();
633 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700634 variables.push({
635 variable: t.find('.variable').val(),
636 values: values
637 });
Tyler Scottf355e452015-11-06 21:35:14 -0700638 });
639 }
640
Tyler Scottcdfcde82015-09-14 16:13:29 -0600641 //Form checking
642 var dest = scope.requestForm.find('#requestDest .active');
Tyler Scott66a965d2016-02-29 15:41:33 -0700643 if (dest.length !== 1) {
Tyler Scottf355e452015-11-06 21:35:14 -0700644 var alert = $('<div class="alert alert-warning">A destination is required!' + closeButton + '<div>');
645 $('#request > .panel-body').append(alert);
Tyler Scottcdfcde82015-09-14 16:13:29 -0600646 return;
647 }
648
Tyler Scott66a965d2016-02-29 15:41:33 -0700649 $('#request').modal('hide');
650 //Initial params are ok. We can close the form.
Tyler Scottb59e6de2015-09-18 14:46:30 -0600651
652 scope.cleanRequestForm();
Tyler Scottcdfcde82015-09-14 16:13:29 -0600653
Tyler Scott66a965d2016-02-29 15:41:33 -0700654 $(this).off(e);
655 //Don't fire this again, the request must be regenerated
Tyler Scottcdfcde82015-09-14 16:13:29 -0600656
657 //Key setup
Tyler Scott66a965d2016-02-29 15:41:33 -0700658 if (!keyAdded) {
659 if (!scope.config.retrieval.demoKey || !scope.config.retrieval.demoKey.pub || !scope.config.retrieval.demoKey.priv) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600660 scope.createAlert("This host was not configured to handle retrieval! See console for details.", 'alert-danger');
661 console.error("Missing/invalid key! This must be configured in the config on the server.", scope.config.demoKey);
662 return;
663 }
664
665 //FIXME base64 may or may not exist in other browsers. Need a new polyfill.
Tyler Scott66a965d2016-02-29 15:41:33 -0700666 var pub = new Buffer(base64.toByteArray(scope.config.retrieval.demoKey.pub));
667 //MUST be a Buffer (Buffer != Uint8Array)
Tyler Scottcdfcde82015-09-14 16:13:29 -0600668 var priv = new Buffer(base64.toByteArray(scope.config.retrieval.demoKey.priv));
669
670 var identityStorage = new MemoryIdentityStorage();
671 var privateKeyStorage = new MemoryPrivateKeyStorage();
Tyler Scott66a965d2016-02-29 15:41:33 -0700672 keyChain = new KeyChain(new IdentityManager(identityStorage,privateKeyStorage),
673 new SelfVerifyPolicyManager(identityStorage));
Tyler Scottcdfcde82015-09-14 16:13:29 -0600674
675 var keyName = new Name("/retrieve/DSK-123");
676 certificateName = keyName.getSubName(0, keyName.size() - 1)
Tyler Scott66a965d2016-02-29 15:41:33 -0700677 .append("KEY").append(keyName.get(-1))
678 .append("ID-CERT").append("0");
Tyler Scottcdfcde82015-09-14 16:13:29 -0600679
Tyler Scott66a965d2016-02-29 15:41:33 -0700680 identityStorage.addKey(keyName, KeyType.RSA, new Blob(pub,false));
Tyler Scottcdfcde82015-09-14 16:13:29 -0600681 privateKeyStorage.setKeyPairForKeyName(keyName, KeyType.RSA, pub, priv);
682
683 scope.face.setCommandSigningInfo(keyChain, certificateName);
684
685 keyAdded = true;
686
687 }
688
689 //Retrieval
690 var retrievePrefix = new Name("/catalog/ui/" + guid());
691
Tyler Scottcdfcde82015-09-14 16:13:29 -0600692 scope.face.registerPrefix(retrievePrefix,
Tyler Scott66a965d2016-02-29 15:41:33 -0700693 function(prefix, interest, face, interestFilterId, filter) {
694 //On Interest
695 //This function will exist until the page exits but will likely only be used once.
Tyler Scottcdfcde82015-09-14 16:13:29 -0600696
Tyler Scott66a965d2016-02-29 15:41:33 -0700697 var data = new Data(interest.getName());
698 var content;
699 if (subset) {
700 content = JSON.stringify({
701 name: subsetFilename,
702 subset: variables
Tyler Scottd61bf832015-11-30 16:36:17 -0700703 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700704 } else {
705 content = JSON.stringify(names);
Tyler Scottcdfcde82015-09-14 16:13:29 -0600706 }
Tyler Scott66a965d2016-02-29 15:41:33 -0700707 //Blob breaks the data! Don't use it
708 data.setContent(content);
709 //TODO Packetize this.
710 keyChain.sign(data, certificateName);
711
712 try {
713 face.putData(data);
714 console.log("Responded for", interest.getName().toUri(), data);
715 scope.createAlert("Data retrieval has initiated.", "alert-success");
716 } catch (e) {
717 console.error("Failed to respond to", interest.getName().toUri(), data);
718 scope.createAlert("Data retrieval failed.");
719 }
720
721 }, function(prefix) {
722 //On fail
723 scope.createAlert("Failed to register the retrieval URI! See console for details.", "alert-danger");
724 console.error("Failed to register URI:", prefix.toUri(), prefix);
725 }, function(prefix, registeredPrefixId) {
726 //On success
727 var name = new Name(dest.text());
728 name.append(prefix);
729
730 scope.expressInterest(name,
731 function(interest, data) {
732 //Success
733 console.log("Request for", name.toUri(), "succeeded.", interest, data);
734 },
735 function() {
736 console.warn("Failed to request from retrieve agent.");
737 }
738 );
739 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600740 );
741
742 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700743 $('#request').modal();
744 //This forces the form to be the only option.
Tyler Scottcdfcde82015-09-14 16:13:29 -0600745
Tyler Scott66a965d2016-02-29 15:41:33 -0700746 }
747
Tyler Scottcdfcde82015-09-14 16:13:29 -0600748 }();
749
750 Atmos.prototype.filterSetup = function() {
751 //Filter setup
752
753 var prefix = new Name(this.catalog).append("filters-initialization");
754
755 var scope = this;
756
Tyler Scott66a965d2016-02-29 15:41:33 -0700757 this.getAll(prefix, function(data) {
758 //Success
759 var raw = JSON.parse(data.replace(/[\n\0]/g, ''));
760 //Remove null byte and parse
Tyler Scottcdfcde82015-09-14 16:13:29 -0600761
762 console.log("Filter categories:", raw);
763
Tyler Scott66a965d2016-02-29 15:41:33 -0700764 $.each(raw, function(index, object) {
765 //Unpack list of objects
766 $.each(object, function(category, searchOptions) {
767 //Unpack category from object (We don't know what it is called)
Tyler Scottcdfcde82015-09-14 16:13:29 -0600768 //Create the category
769 var e = $('<li><a href="#">' + category.replace(/_/g, " ") + '</a><ul class="subnav nav nav-pills nav-stacked"></ul></li>');
770
771 var sub = e.find('ul.subnav');
Tyler Scott66a965d2016-02-29 15:41:33 -0700772 $.each(searchOptions, function(index, name) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600773 //Create the filter list inside the category
774 var item = $('<li><a href="#">' + name + '</a></li>');
775 sub.append(item);
Tyler Scott66a965d2016-02-29 15:41:33 -0700776 item.click(function() {
777 //Click on the side menu filters
778 if (item.hasClass('active')) {
779 //Does the filter already exist?
Tyler Scottcdfcde82015-09-14 16:13:29 -0600780 item.removeClass('active');
781 scope.filters.find(':contains(' + category + ':' + name + ')').remove();
Tyler Scott66a965d2016-02-29 15:41:33 -0700782 } else {
783 //Add a filter
Tyler Scottcdfcde82015-09-14 16:13:29 -0600784 item.addClass('active');
785 var filter = $('<span class="label label-default"></span>');
786 filter.text(category + ':' + name);
787
788 scope.filters.append(filter);
789
Tyler Scott66a965d2016-02-29 15:41:33 -0700790 filter.click(function() {
791 //Click on a filter
Tyler Scottcdfcde82015-09-14 16:13:29 -0600792 filter.remove();
793 item.removeClass('active');
794 });
795 }
796
797 });
798 });
799
800 //Toggle the menus. (Only respond when the immediate tab is clicked.)
Tyler Scott66a965d2016-02-29 15:41:33 -0700801 e.find('> a').click(function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600802 scope.categories.find('.subnav').slideUp();
803 var t = $(this).siblings('.subnav');
Tyler Scott66a965d2016-02-29 15:41:33 -0700804 if (!t.is(':visible')) {
805 //If the sub menu is not visible
806 t.slideDown(function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600807 t.triggerHandler('focus');
Tyler Scott66a965d2016-02-29 15:41:33 -0700808 });
809 //Make it visible and look at it.
Tyler Scottcdfcde82015-09-14 16:13:29 -0600810 }
811 });
812
813 scope.categories.append(e);
814
815 });
816 });
817
Tyler Scott66a965d2016-02-29 15:41:33 -0700818 }, function(interest) {
819 //Timeout
Tyler Scottcdfcde82015-09-14 16:13:29 -0600820 scope.createAlert("Failed to initialize the filters!", "alert-danger");
821 console.error("Failed to initialize filters!", interest);
822 ga('send', 'event', 'error', 'filters');
823 });
824
Tyler Scott66a965d2016-02-29 15:41:33 -0700825 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600826
827 /**
828 * This function retrieves all segments in order until it knows it has reached the last one.
829 * It then returns the final joined result.
Tyler Scott66a965d2016-02-29 15:41:33 -0700830
Tyler Scottf355e452015-11-06 21:35:14 -0700831 * @param prefix {String|Name} The ndn name we are retrieving.
832 * @param callback {function(String)} if successful, will call the callback with a string of data.
833 * @param failure {function(Interest)} if unsuccessful, will call failure with the last failed interest.
834 * @param stop {boolean} stop if no finalBlock.
Tyler Scottcdfcde82015-09-14 16:13:29 -0600835 */
Tyler Scott66a965d2016-02-29 15:41:33 -0700836 Atmos.prototype.getAll = function(prefix, callback, failure, stop) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600837
838 var scope = this;
839 var d = [];
840
Tyler Scottd61bf832015-11-30 16:36:17 -0700841 var name = new Name(prefix);
842 var segment = 0;
Tyler Scott8724e422015-10-13 17:59:07 -0600843
Tyler Scott66a965d2016-02-29 15:41:33 -0700844 var request = function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600845
Tyler Scottd61bf832015-11-30 16:36:17 -0700846 var n2 = new Name(name);
847 n2.appendSegment(segment);
Tyler Scottcdfcde82015-09-14 16:13:29 -0600848
Tyler Scott66a965d2016-02-29 15:41:33 -0700849 scope.expressInterest(n2, handleData, function() {});
850 //Forward to handleData and ignore error
851 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600852
Tyler Scott66a965d2016-02-29 15:41:33 -0700853 var handleData = function(interest, data) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600854
855 d.push(data.getContent().toString());
856
Tyler Scottf355e452015-11-06 21:35:14 -0700857 var hasFinalBlock = data.getMetaInfo().getFinalBlockId().value.length === 0;
858 var finalBlockStop = hasFinalBlock && stop;
859
860 if (finalBlockStop ||
Tyler Scott66a965d2016-02-29 15:41:33 -0700861 (!hasFinalBlock && interest.getName().get(-1).toSegment() == data.getMetaInfo().getFinalBlockId().toSegment())) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600862 callback(d.join(""));
863 } else {
Tyler Scottd61bf832015-11-30 16:36:17 -0700864 segment++;
865 request();
Tyler Scottcdfcde82015-09-14 16:13:29 -0600866 }
867
Tyler Scott66a965d2016-02-29 15:41:33 -0700868 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600869
Tyler Scottd61bf832015-11-30 16:36:17 -0700870 request();
Tyler Scottcdfcde82015-09-14 16:13:29 -0600871
Tyler Scott66a965d2016-02-29 15:41:33 -0700872 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600873
Tyler Scott66a965d2016-02-29 15:41:33 -0700874 Atmos.prototype.cleanRequestForm = function() {
Tyler Scottb59e6de2015-09-18 14:46:30 -0600875 $('#requestDest').prev().removeClass('btn-success').addClass('btn-default');
876 $('#requestDropText').text('Destination');
877 $('#requestDest .active').removeClass('active');
Tyler Scottf355e452015-11-06 21:35:14 -0700878 $('#subsetMenu').attr('class', 'collapse');
879 $('#subsetVariables').empty();
880 $('#request .alert').alert('close').remove();
Tyler Scott66a965d2016-02-29 15:41:33 -0700881 }
Tyler Scottb59e6de2015-09-18 14:46:30 -0600882
Tyler Scott66a965d2016-02-29 15:41:33 -0700883 Atmos.prototype.setupRequestForm = function() {
Tyler Scottb59e6de2015-09-18 14:46:30 -0600884
885 var scope = this;
886
Tyler Scott66a965d2016-02-29 15:41:33 -0700887 this.requestForm.find('#requestCancel').click(function() {
888 $('#request').unbind('submit')//Removes all event handlers.
889 .modal('hide');
890 //Hides the form.
Tyler Scottb59e6de2015-09-18 14:46:30 -0600891 scope.cleanRequestForm();
Tyler Scottcdfcde82015-09-14 16:13:29 -0600892 });
893
Tyler Scott66a965d2016-02-29 15:41:33 -0700894 var dests = $(this.config['retrieval']['destinations'].reduce(function(prev, current) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600895 prev.push('<li><a href="#">');
896 prev.push(current);
897 prev.push("</a></li>");
898 return prev;
899 }, []).join(""));
900
901 this.requestForm.find('#requestDest').append(dests)
Tyler Scott66a965d2016-02-29 15:41:33 -0700902 .on('click', 'a', function(e) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600903 $('#requestDest .active').removeClass('active');
Tyler Scottb59e6de2015-09-18 14:46:30 -0600904 var t = $(this);
905 t.parent().addClass('active');
906 $('#requestDropText').text(t.text());
907 $('#requestDest').prev().removeClass('btn-default').addClass('btn-success');
Tyler Scottcdfcde82015-09-14 16:13:29 -0600908 });
909
Tyler Scott66a965d2016-02-29 15:41:33 -0700910 var addVariable = function(selector) {
911 var ele = $(selector).clone().attr('id', '');
912 ele.find('.close').click(function() {
Tyler Scottf355e452015-11-06 21:35:14 -0700913 ele.remove();
914 });
915 $('#subsetVariables').append(ele);
Tyler Scott66a965d2016-02-29 15:41:33 -0700916 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600917
Tyler Scott66a965d2016-02-29 15:41:33 -0700918 $('#subsetAddVariableBtn').click(function() {
Tyler Scottf355e452015-11-06 21:35:14 -0700919 addVariable('#customTemplate');
920 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700921 $('#subsetAddTimeVariable').click(function() {
Tyler Scottf355e452015-11-06 21:35:14 -0700922 addVariable('#timeTemplate');
923 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700924 $('#subsetAddLocVariable').click(function() {
Tyler Scottf355e452015-11-06 21:35:14 -0700925 addVariable('#locationTemplate');
926 });
Tyler Scottcdfcde82015-09-14 16:13:29 -0600927
Tyler Scott66a965d2016-02-29 15:41:33 -0700928 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600929
Tyler Scott66a965d2016-02-29 15:41:33 -0700930 Atmos.prototype.getMetaData = (function() {
Tyler Scott48f92cd2015-10-16 18:31:20 -0600931
932 var cache = {};
933
934 return function(element) {
935 var name = $(element).text();
936
Tyler Scottf355e452015-11-06 21:35:14 -0700937 ga('send', 'event', 'request', 'metaData');
938
939 var subsetButton = '<button class="btn btn-default subsetButton" type="button">Subset</button>';
940
Tyler Scott48f92cd2015-10-16 18:31:20 -0600941 if (cache[name]) {
Tyler Scottf355e452015-11-06 21:35:14 -0700942 return [subsetButton, '<pre class="metaData">', cache[name], '</pre>'].join('');
Tyler Scott48f92cd2015-10-16 18:31:20 -0600943 }
944
945 var prefix = new Name(name).append("metadata");
Tyler Scott66a965d2016-02-29 15:41:33 -0700946 var id = guid();
947 //We need an id because the return MUST be a string.
Tyler Scott48f92cd2015-10-16 18:31:20 -0600948 var ret = '<div id="' + id + '"><span class="fa fa-spinner fa-spin"></span></div>';
949
Tyler Scott66a965d2016-02-29 15:41:33 -0700950 this.getAll(prefix, function(data) {
Tyler Scott48f92cd2015-10-16 18:31:20 -0600951 var el = $('<pre class="metaData"></pre>');
952 el.text(data);
Tyler Scottf355e452015-11-06 21:35:14 -0700953 var container = $('<div></div>');
954 container.append($(subsetButton));
955 container.append(el);
956 $('#' + id).empty().append(container);
Tyler Scott48f92cd2015-10-16 18:31:20 -0600957 cache[name] = data;
Tyler Scott66a965d2016-02-29 15:41:33 -0700958 }, function(interest) {
Tyler Scott48f92cd2015-10-16 18:31:20 -0600959 $('#' + id).text("The metadata is unavailable for this name.");
960 console.log("Data is unavailable for " + name);
961 });
962
963 return ret;
964
Tyler Scott66a965d2016-02-29 15:41:33 -0700965 }
Tyler Scott48f92cd2015-10-16 18:31:20 -0600966 })();
967
Tyler Scottcdfcde82015-09-14 16:13:29 -0600968 return Atmos;
969
970})();