blob: 178ee18c3bfa958cc33b46155aa011469ff1e9da [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;
5 Promise.all([
Tyler Scott66a965d2016-02-29 15:41:33 -07006 new Promise(function(resolve, reject) {
7 $.ajax('../config.json').done(function(data) {
8 config = data;
9 resolve();
10 }).fail(function() {
11 console.error("Failed to get config.");
12 ga('send', 'event', 'error', 'config');
13 reject();
14 });
15 }
16 ),
17 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 });
26 }
27 )
28 ]).then(function() {
Tyler Scott2118a412015-10-29 15:17:05 -060029
Tyler Scott66a965d2016-02-29 15:41:33 -070030 var getParameterByName = function(name) {
31 name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
32 var regex = new RegExp("[\\?&]" + name + "=([^&#]*)");
33 var results = regex.exec(location.search);
34 return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
35 }
Tyler Scott2118a412015-10-29 15:17:05 -060036
37 //Overwrite config if present. Any failure will just cause this to be skipped.
Tyler Scott66a965d2016-02-29 15:41:33 -070038 try {
Tyler Scott2118a412015-10-29 15:17:05 -060039 var configParam = JSON.parse(getParameterByName('config'));
40 config = jQuery.extend(true, config, configParam);
Tyler Scott66a965d2016-02-29 15:41:33 -070041 } catch (e) {
Tyler Scott2118a412015-10-29 15:17:05 -060042 console.warn("Failure in config overwrite, skipping.", e);
43 }
44
Tyler Scottcdfcde82015-09-14 16:13:29 -060045 new Atmos(config);
Tyler Scott66a965d2016-02-29 15:41:33 -070046 }, function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -060047 console.error("Failed to initialize!");
48 ga('send', 'event', 'error', 'init');
49 });
50})();
51
Tyler Scott66a965d2016-02-29 15:41:33 -070052var Atmos = (function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -060053 "use strict";
54
55 var closeButton = '<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>';
56
Tyler Scott66a965d2016-02-29 15:41:33 -070057 var guid = function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -060058 var d = new Date().getTime();
59 var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
Tyler Scott66a965d2016-02-29 15:41:33 -070060 var r = (d + Math.random() * 16) % 16 | 0;
61 d = Math.floor(d / 16);
62 return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
Tyler Scottcdfcde82015-09-14 16:13:29 -060063 });
64 return uuid;
Tyler Scott66a965d2016-02-29 15:41:33 -070065 }
Tyler Scottcdfcde82015-09-14 16:13:29 -060066
67 /**
68 * Atmos
69 * @version 2.0
Tyler Scott66a965d2016-02-29 15:41:33 -070070
Tyler Scottcdfcde82015-09-14 16:13:29 -060071 * Configures an Atmos object. This manages the atmos interface.
Tyler Scott66a965d2016-02-29 15:41:33 -070072
Tyler Scottcdfcde82015-09-14 16:13:29 -060073 * @constructor
74 * @param {string} catalog - NDN path
75 * @param {Object} config - Object of configuration options for a Face.
76 */
Tyler Scott66a965d2016-02-29 15:41:33 -070077 var Atmos = function(config) {
Tyler Scottcdfcde82015-09-14 16:13:29 -060078
79 //Internal variables.
80 this.results = [];
81 this.resultCount = Infinity;
Tyler Scott66a965d2016-02-29 15:41:33 -070082 this.name = null ;
Tyler Scottcdfcde82015-09-14 16:13:29 -060083 this.page = 0;
84 this.resultsPerPage = 25;
85 this.retrievedSegments = 0;
86
87 //Config/init
88 this.config = config;
89
90 this.catalog = config['global']['catalogPrefix'];
Chengyu Fan7b978f82015-12-09 17:03:23 -070091 this.catalogPrefix = new Name(this.catalog);
Tyler Scottcdfcde82015-09-14 16:13:29 -060092
93 this.face = new Face(config['global']['faceConfig']);
94
95 //Easy access dom variables
96 this.categories = $('#side-menu');
97 this.resultTable = $('#resultTable');
98 this.filters = $('#filters');
99 this.searchInput = $('#search');
100 this.searchBar = $('#searchBar');
101 this.searchButton = $('#searchButton');
102 this.resultMenu = $('.resultMenu');
103 this.alerts = $('#alerts');
104 this.requestForm = $('#requestForm');
105
106 var scope = this;
107
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 });
112
113 this.filterSetup();
114
115 //Init autocomplete
Tyler Scott66a965d2016-02-29 15:41:33 -0700116 this.searchInput.autoComplete(function(field, callback) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600117 ga('send', 'event', 'search', 'autocomplete');
Tyler Scott66a965d2016-02-29 15:41:33 -0700118 scope.autoComplete(field, function(data) {
Tyler Scott94458992015-09-24 14:16:28 -0700119 var list = data.next;
120 var last = data.lastComponent === true;
Tyler Scott66a965d2016-02-29 15:41:33 -0700121 callback(list.map(function(element) {
122 return field + element + (last ? "/" : "");
123 //Don't add trailing slash for last component.
Tyler Scottcdfcde82015-09-14 16:13:29 -0600124 }));
125 });
126 });
127
128 //Handle search
Tyler Scott66a965d2016-02-29 15:41:33 -0700129 this.searchBar.submit(function(e) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600130 ga('send', 'event', 'search', 'submit');
131 e.preventDefault();
Tyler Scott66a965d2016-02-29 15:41:33 -0700132 if (scope.searchInput.val().length === 0) {
133 if (!scope.searchBar.hasClass('has-error')) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600134 scope.searchBar.addClass('has-error').append('<span class="help-block">Search path is required!</span>');
135 }
136 return;
137 } else {
Tyler Scott66a965d2016-02-29 15:41:33 -0700138 scope.searchBar.removeClass('has-error').find('.help-block').fadeOut(function() {
139 $(this).remove()
140 });
Tyler Scottcdfcde82015-09-14 16:13:29 -0600141 }
142 scope.pathSearch();
143 });
144
Tyler Scott66a965d2016-02-29 15:41:33 -0700145 this.searchButton.click(function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600146 console.log("Search Button Pressed");
147 ga('send', 'event', 'button', 'click', 'search');
148 scope.search();
149 });
150
151 //Result navigation handlers
Tyler Scott66a965d2016-02-29 15:41:33 -0700152 this.resultMenu.find('.next').click(function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600153 ga('send', 'event', 'button', 'click', 'next');
Tyler Scott66a965d2016-02-29 15:41:33 -0700154 if (!$(this).hasClass('disabled')) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600155 scope.getResults(scope.page + 1);
156 }
157 });
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 Scott66a965d2016-02-29 15:41:33 -0700164 this.resultMenu.find('.clearResults').click(function() {
Tyler Scotte8dac702015-10-13 14:33:25 -0600165 ga('send', 'event', 'button', 'click', 'resultClear');
166 scope.clearResults();
Tyler Scott66a965d2016-02-29 15:41:33 -0700167 $('#results').fadeOut(function() {
Tyler Scotte8dac702015-10-13 14:33:25 -0600168 $(this).addClass('hidden');
169 });
170 });
Tyler Scottcdfcde82015-09-14 16:13:29 -0600171
172 //Change the number of results per page handler
Tyler Scott66a965d2016-02-29 15:41:33 -0700173 var rpps = $('.resultsPerPageSelector').click(function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600174
175 var t = $(this);
176
Tyler Scott66a965d2016-02-29 15:41:33 -0700177 if (t.hasClass('active')) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600178 return;
179 }
180
181 rpps.find('.active').removeClass('active');
182 t.addClass('active');
183 scope.resultsPerPage = Number(t.text());
Tyler Scott66a965d2016-02-29 15:41:33 -0700184 scope.getResults(0);
185 //Force return to page 1;
Tyler Scottcdfcde82015-09-14 16:13:29 -0600186
187 });
188
189 //Init tree search
Tyler Scott66a965d2016-02-29 15:41:33 -0700190 $('#treeSearch div').treeExplorer(function(path, callback) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600191 console.log("Tree Explorer request", path);
192 ga('send', 'event', 'tree', 'request');
Tyler Scott66a965d2016-02-29 15:41:33 -0700193 scope.autoComplete(path, function(data) {
Tyler Scottb59e6de2015-09-18 14:46:30 -0600194 var list = data.next;
195 var last = (data.lastComponent === true);
Tyler Scottbb42ed22015-10-21 17:02:56 -0600196
197 if (last) {
198 console.log("Redirecting last element request to a search.");
199 scope.clearResults();
Tyler Scott66a965d2016-02-29 15:41:33 -0700200 scope.query(scope.catalog, {
201 '??': path
202 },
203 function(interest, data) {
Tyler Scottbb42ed22015-10-21 17:02:56 -0600204 console.log("Search response", interest, data);
Chengyu Fan7b978f82015-12-09 17:03:23 -0700205 scope.name = interest.getName();
Tyler Scottbb42ed22015-10-21 17:02:56 -0600206 scope.getResults(0);
Tyler Scott66a965d2016-02-29 15:41:33 -0700207 }, function(interest) {
Tyler Scottbb42ed22015-10-21 17:02:56 -0600208 console.warn("Failed to retrieve final component.", interest, path);
209 scope.createAlert("Failed to request final component. " + path + " See console for details.");
210 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700211 return;
212 //Don't call the callback
Tyler Scottbb42ed22015-10-21 17:02:56 -0600213 }
214
Tyler Scottcdfcde82015-09-14 16:13:29 -0600215 console.log("Autocomplete response", list);
Tyler Scott66a965d2016-02-29 15:41:33 -0700216 callback(list.map(function(element) {
217 return (path == "/" ? "/" : "") + element + "/";
Tyler Scottcdfcde82015-09-14 16:13:29 -0600218 }));
Chengyu Fan7b978f82015-12-09 17:03:23 -0700219 });
Tyler Scottcdfcde82015-09-14 16:13:29 -0600220 });
221
Tyler Scott66a965d2016-02-29 15:41:33 -0700222 $('#treeSearch').on('click', '.treeSearch', function() {
Tyler Scottb59e6de2015-09-18 14:46:30 -0600223 var t = $(this);
224
225 scope.clearResults();
226
227 var path = t.parent().parent().attr('id');
228
Tyler Scottbb42ed22015-10-21 17:02:56 -0600229 console.log("Tree search:", path);
Tyler Scottb59e6de2015-09-18 14:46:30 -0600230
Tyler Scott66a965d2016-02-29 15:41:33 -0700231 scope.query(scope.catalog, {
232 '??': path
233 },
234 function(interest, data) {
235 //Success
Tyler Scottb59e6de2015-09-18 14:46:30 -0600236 console.log("Tree search response", interest, data);
237
Chengyu Fan7b978f82015-12-09 17:03:23 -0700238 scope.name = interest.getName();
Tyler Scottb59e6de2015-09-18 14:46:30 -0600239
240 scope.getResults(0);
241 },
Tyler Scott66a965d2016-02-29 15:41:33 -0700242 function(interest) {
243 //Failure
Tyler Scottb59e6de2015-09-18 14:46:30 -0600244 console.warn("Request failed! Timeout", interest);
Tyler Scott66a965d2016-02-29 15:41:33 -0700245 scope.createAlert("Request timed out.\"" + interest.getName().toUri() + "\" See console for details.");
Tyler Scottb59e6de2015-09-18 14:46:30 -0600246 });
247
248 });
249
Tyler Scottcdfcde82015-09-14 16:13:29 -0600250 this.setupRequestForm();
251
Tyler Scott48f92cd2015-10-16 18:31:20 -0600252 this.resultTable.popover({
Tyler Scott66a965d2016-02-29 15:41:33 -0700253 selector: ".metaDataLink",
254 content: function() {
Tyler Scott48f92cd2015-10-16 18:31:20 -0600255 return scope.getMetaData(this);
256 },
257 title: "Metadata",
258 html: true,
259 trigger: 'click',
260 placement: 'bottom'
261 });
262
Tyler Scott66a965d2016-02-29 15:41:33 -0700263 this.resultTable.on('click', '.metaDataLink', function(e) {
Tyler Scott48f92cd2015-10-16 18:31:20 -0600264 //This prevents the page from scrolling when you click on a name.
265 e.preventDefault();
266 });
267
Tyler Scott66a965d2016-02-29 15:41:33 -0700268 this.resultTable.on('click', '.subsetButton', function() {
Tyler Scottf355e452015-11-06 21:35:14 -0700269 var metaData = $(this).siblings('pre').text();
270 var exp = /netcdf ([\w-]+)/;
271 var match = exp.exec(metaData);
Tyler Scott66a965d2016-02-29 15:41:33 -0700272 var filename = match[0].replace(/netcdf /, '') + '.nc';
273 scope.request(null , filename);
Tyler Scottf355e452015-11-06 21:35:14 -0700274 });
275
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.clearResults = function() {
279 this.results = [];
280 //Drop any old results.
Tyler Scottcdfcde82015-09-14 16:13:29 -0600281 this.retrievedSegments = 0;
282 this.resultCount = Infinity;
283 this.page = 0;
284 this.resultTable.empty();
Tyler Scott66a965d2016-02-29 15:41:33 -0700285 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600286
Tyler Scott66a965d2016-02-29 15:41:33 -0700287 Atmos.prototype.pathSearch = function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600288 var value = this.searchInput.val();
289
290 this.clearResults();
291
292 var scope = this;
293
Tyler Scott66a965d2016-02-29 15:41:33 -0700294 this.query(this.catalog, {
295 "??": value
296 },
297 function(interest, data) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600298 console.log("Query response:", interest, data);
299
Tyler Scott66a965d2016-02-29 15:41:33 -0700300 scope.name = interest.getName();
Tyler Scottcdfcde82015-09-14 16:13:29 -0600301
302 scope.getResults(0);
303
304 },
Tyler Scott66a965d2016-02-29 15:41:33 -0700305 function(interest) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600306 console.warn("Request failed! Timeout", interest);
307 scope.createAlert("Request timed out. \"" + interest.getName().toUri() + "\" See console for details.");
308 });
309
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.search = function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600313
314 var filters = this.getFilters();
315
316 console.log("Search started!", this.searchInput.val(), filters);
317
318 console.log("Initiating query");
319
320 this.clearResults();
321
322 var scope = this;
323
324 this.query(this.catalog, filters,
Tyler Scott66a965d2016-02-29 15:41:33 -0700325 function(interest, data) {
326 //Response function
Tyler Scottcdfcde82015-09-14 16:13:29 -0600327 console.log("Query Response:", interest, data);
328
Chengyu Fan7b978f82015-12-09 17:03:23 -0700329 scope.name = interest.getName();
Tyler Scottcdfcde82015-09-14 16:13:29 -0600330
331 scope.getResults(0);
332
Tyler Scott66a965d2016-02-29 15:41:33 -0700333 }, function(interest) {
334 //Timeout function
Tyler Scottd980a292015-10-13 15:16:34 -0600335 console.warn("Request failed after 3 attempts!", interest);
336 scope.createAlert("Request failed after 3 attempts. \"" + interest.getName().toUri() + "\" See console for details.");
Tyler Scottcdfcde82015-09-14 16:13:29 -0600337 });
338
Tyler Scott66a965d2016-02-29 15:41:33 -0700339 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600340
Tyler Scott66a965d2016-02-29 15:41:33 -0700341 Atmos.prototype.autoComplete = function(field, callback) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600342
343 var scope = this;
344
Tyler Scott66a965d2016-02-29 15:41:33 -0700345 var result = {};
Tyler Scottcdfcde82015-09-14 16:13:29 -0600346
Tyler Scott66a965d2016-02-29 15:41:33 -0700347 const getAll = function(interest, data) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600348
Tyler Scott66a965d2016-02-29 15:41:33 -0700349 if (data.getContent().length !== 0) {
350 var resp = JSON.parse(data.getContent().toString().replace(/[\n\0]/g, ""));
351 if (result.next) {
352 result.next = result.next.concat(resp.next);
353 } else {
354 result = resp;
Tyler Scottd61bf832015-11-30 16:36:17 -0700355 }
Tyler Scott66a965d2016-02-29 15:41:33 -0700356 } else {
357 callback(result);
358 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600359
Tyler Scott66a965d2016-02-29 15:41:33 -0700360 var name = data.getName();
361 var segment = name.components[name.getComponentCount() - 1];
362 if (segment.toSegment() !== data.getMetaInfo().getFinalBlockId().toSegment()){
363 name = name.getPrefix(-1); //Remove segment
364 name.appendSegment(segment.toSegment() + 1);
365 scope.expressInterest(name, getAll, function() {
366 console.warn("Autocomplete timed out, results may be incomplete.");
367 callback(result);
368 //Return if we get a timeout.
369 });
370 } else {
371 callback(result);
372 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600373
Tyler Scott66a965d2016-02-29 15:41:33 -0700374 }
375
376 this.query(this.catalog, {
377 "?": field
378 }, getAll);
379
380 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600381
382 Atmos.prototype.showResults = function(resultIndex) {
383
384 var results = this.results.slice(this.resultsPerPage * resultIndex, this.resultsPerPage * (resultIndex + 1));
385
386 var resultDOM = $(
Tyler Scott66a965d2016-02-29 15:41:33 -0700387 results.reduce(function(prev, current) {
388 prev.push('<tr><td><input class="resultSelector" type="checkbox"></td><td class="popover-container"><a href="#" class="metaDataLink">');
389 prev.push(current);
390 prev.push('</a></td></tr>');
391 return prev;
392 }, ['<tr><th><input id="resultSelectAll" type="checkbox" title="Select All"> Select</th><th>Name</th></tr>']).join('')
Tyler Scottcdfcde82015-09-14 16:13:29 -0600393 );
394
Tyler Scott66a965d2016-02-29 15:41:33 -0700395 resultDOM.find('#resultSelectAll').click(function() {
396 if ($(this).is(':checked')) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600397 resultDOM.find('.resultSelector:not([disabled])').prop('checked', true);
398 } else {
399 resultDOM.find('.resultSelector:not([disabled])').prop('checked', false);
400 }
401 });
402
403 this.resultTable.hide().empty().append(resultDOM).slideDown('slow');
404
405 this.resultMenu.find('.pageNumber').text(resultIndex + 1);
406 this.resultMenu.find('.pageLength').text(this.resultsPerPage * resultIndex + results.length);
407
408 if (this.resultsPerPage * (resultIndex + 1) >= this.resultCount) {
409 this.resultMenu.find('.next').addClass('disabled');
Tyler Scott66a965d2016-02-29 15:41:33 -0700410 } else if (resultIndex === 0) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600411 this.resultMenu.find('.next').removeClass('disabled');
412 }
413
Tyler Scott66a965d2016-02-29 15:41:33 -0700414 if (resultIndex === 0) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600415 this.resultMenu.find('.previous').addClass('disabled');
416 } else if (resultIndex === 1) {
417 this.resultMenu.find('.previous').removeClass('disabled');
418 }
419
Tyler Scott66a965d2016-02-29 15:41:33 -0700420 $.scrollTo("#results", 500, {
421 interrupt: true
422 });
Tyler Scottf355e452015-11-06 21:35:14 -0700423
Tyler Scott66a965d2016-02-29 15:41:33 -0700424 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600425
Tyler Scott66a965d2016-02-29 15:41:33 -0700426 Atmos.prototype.getResults = function(index) {
Chengyu Fan7b978f82015-12-09 17:03:23 -0700427 var scope = this;
Tyler Scottcdfcde82015-09-14 16:13:29 -0600428
Tyler Scott66a965d2016-02-29 15:41:33 -0700429 if ($('#results').hasClass('hidden')) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600430 $('#results').removeClass('hidden').slideDown();
431 }
432
Tyler Scott66a965d2016-02-29 15:41:33 -0700433 if ((scope.results.length === scope.resultCount) || (scope.resultsPerPage * (index + 1) < scope.results.length)) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600434 //console.log("We already have index", index);
Chengyu Fan7b978f82015-12-09 17:03:23 -0700435 scope.page = index;
436 scope.showResults(index);
Tyler Scottcdfcde82015-09-14 16:13:29 -0600437 return;
438 }
439
Tyler Scott66a965d2016-02-29 15:41:33 -0700440 if (scope.name === null ) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600441 console.error("This shouldn't be reached! We are getting results before a search has occured!");
442 throw new Error("Illegal State");
443 }
444
Chengyu Fan7b978f82015-12-09 17:03:23 -0700445 var interestName = new Name(scope.name);
Tyler Scottcdfcde82015-09-14 16:13:29 -0600446
Chengyu Fan7b978f82015-12-09 17:03:23 -0700447 // Interest name should be /<catalog-prefix>/query/<query-param>/<version>/<#seq>
448 if (scope.name.size() === (scope.catalogPrefix.size() + 3)) {
449 interestName = interestName.appendSegment(scope.retrievedSegments++);
Tyler Scott66a965d2016-02-29 15:41:33 -0700450 //console.log("Requesting data index: (", scope.retrievedSegments - 1, ") at ", interestName.toUri());
Chengyu Fan7b978f82015-12-09 17:03:23 -0700451 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600452
Tyler Scott66a965d2016-02-29 15:41:33 -0700453 this.expressInterest(interestName,
454 function(interest, data) {
455 //Response
Tyler Scottcdfcde82015-09-14 16:13:29 -0600456
Tyler Scott66a965d2016-02-29 15:41:33 -0700457 if (data.getContent().length === 0) {
458 scope.resultMenu.find('.totalResults').text(0);
459 scope.resultMenu.find('.pageNumber').text(0);
460 scope.resultMenu.find('.pageLength').text(0);
461 console.log("Empty response.");
462 scope.resultTable.html("<tr><td>Empty response. This usually means no results.</td></tr>");
463 return;
Tyler Scottcdfcde82015-09-14 16:13:29 -0600464 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600465
Tyler Scott66a965d2016-02-29 15:41:33 -0700466 var content = JSON.parse(data.getContent().toString().replace(/[\n\0]/g, ""));
467
468 if (!content.results) {
469 scope.resultMenu.find('.totalResults').text(0);
470 scope.resultMenu.find('.pageNumber').text(0);
471 scope.resultMenu.find('.pageLength').text(0);
472 console.log("No results were found!");
473 scope.resultTable.html("<tr><td>No Results</td></tr>");
474 return;
475 }
476
477 scope.results = scope.results.concat(content.results);
478
479 scope.resultCount = content.resultCount;
480
481 scope.resultMenu.find('.totalResults').text(scope.resultCount);
482
483 scope.page = index;
484
485 // reset scope.name
486 scope.name = new Name(data.getName().getPrefix(scope.catalogPrefix.size() + 3));
487
488 scope.getResults(index);
489 //Keep calling this until we have enough data.
490
491 }, function() {}//Ignore failure
492 );
493
494 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600495
496 Atmos.prototype.query = function(prefix, parameters, callback, timeout) {
497
498 var queryPrefix = new Name(prefix);
499 queryPrefix.append("query");
500
501 var jsonString = JSON.stringify(parameters);
502 queryPrefix.append(jsonString);
503
Tyler Scott66a965d2016-02-29 15:41:33 -0700504 this.expressInterest(queryPrefix, callback, timeout);
Tyler Scottcdfcde82015-09-14 16:13:29 -0600505
Tyler Scott66a965d2016-02-29 15:41:33 -0700506 }
Tyler Scottd61bf832015-11-30 16:36:17 -0700507
Tyler Scott66a965d2016-02-29 15:41:33 -0700508
509 Atmos.prototype.expressInterest = function(name, success, failure) {
510
511 var interest = new Interest(name);
512 interest.setInterestLifetimeMilliseconds(1500);
513 interest.setMustBeFresh(true);
514
515 const face = this.face;
516
517 async.retry(4, function(done) {
518 face.expressInterest(interest, function(interest, data) {
Tyler Scottd61bf832015-11-30 16:36:17 -0700519 done();
Tyler Scott66a965d2016-02-29 15:41:33 -0700520 success(interest, data);
521 }, function(interest) {
522 done("Interest timed out 4 times.", interest);
523 });
524 }, function(err, interest) {
525 if (err) {
526 console.log(err, interest);
527 failure(interest);
Tyler Scott8724e422015-10-13 17:59:07 -0600528 }
Tyler Scottd61bf832015-11-30 16:36:17 -0700529 });
Tyler Scottcdfcde82015-09-14 16:13:29 -0600530
Tyler Scott66a965d2016-02-29 15:41:33 -0700531 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600532
533 /**
534 * This function returns a map of all the categories active filters.
535 * @return {Object<string, string>}
536 */
Tyler Scott66a965d2016-02-29 15:41:33 -0700537 Atmos.prototype.getFilters = function() {
538 var filters = this.filters.children().toArray().reduce(function(prev, current) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600539 var data = $(current).text().split(/:/);
540 prev[data[0]] = data[1];
541 return prev;
Tyler Scott66a965d2016-02-29 15:41:33 -0700542 }, {});
543 //Collect a map<category, filter>.
Tyler Scottcdfcde82015-09-14 16:13:29 -0600544 //TODO Make the return value map<category, Array<filter>>
545 return filters;
Tyler Scott66a965d2016-02-29 15:41:33 -0700546 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600547
548 /**
549 * Creates a closable alert for the user.
Tyler Scott66a965d2016-02-29 15:41:33 -0700550
Tyler Scottcdfcde82015-09-14 16:13:29 -0600551 * @param {string} message
552 * @param {string} type - Override the alert type.
553 */
554 Atmos.prototype.createAlert = function(message, type) {
555
556 var alert = $('<div class="alert"><div>');
Tyler Scott66a965d2016-02-29 15:41:33 -0700557 alert.addClass(type ? type : 'alert-info');
Tyler Scottcdfcde82015-09-14 16:13:29 -0600558 alert.text(message);
559 alert.append(closeButton);
560
561 this.alerts.append(alert);
Tyler Scott66a965d2016-02-29 15:41:33 -0700562 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600563
564 /**
565 * Requests all of the names represented by the buttons in the elements list.
Tyler Scott66a965d2016-02-29 15:41:33 -0700566
Tyler Scottcdfcde82015-09-14 16:13:29 -0600567 * @param elements {Array<jQuery>} A list of the table row elements
Tyler Scottf355e452015-11-06 21:35:14 -0700568 * @param subsetFileName {String} If present then do a subsetting request instead.
Tyler Scottcdfcde82015-09-14 16:13:29 -0600569 */
Tyler Scott66a965d2016-02-29 15:41:33 -0700570 Atmos.prototype.request = function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600571
572 //Pseudo globals.
573 var keyChain;
574 var certificateName;
575 var keyAdded = false;
576
Tyler Scott66a965d2016-02-29 15:41:33 -0700577 return function(elements, subsetFilename) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600578
579 var names = [];
Tyler Scott66a965d2016-02-29 15:41:33 -0700580 $(elements).find('.metaDataLink').each(function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600581 var name = $(this).text();
582 names.push(name);
Tyler Scottf355e452015-11-06 21:35:14 -0700583 });
584
585 var subset = false;
586
Tyler Scott66a965d2016-02-29 15:41:33 -0700587 if (!subsetFilename) {
Tyler Scottf355e452015-11-06 21:35:14 -0700588 $('#subsetting').hide();
589 } else {
590 $('#subsetting').show();
591 subset = true;
592 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600593
594 var scope = this;
Tyler Scott66a965d2016-02-29 15:41:33 -0700595 this.requestForm.on('submit', function(e) {
596 //This will be registered for the next submit from the form.
Tyler Scottcdfcde82015-09-14 16:13:29 -0600597 e.preventDefault();
598
Tyler Scottf355e452015-11-06 21:35:14 -0700599 $('#request .alert').remove();
600
601 var variables = [];
Tyler Scott66a965d2016-02-29 15:41:33 -0700602 if (subset) {
603 $('#subsetVariables .row').each(function() {
Tyler Scottf355e452015-11-06 21:35:14 -0700604 var t = $(this);
605 var values = {};
Tyler Scott66a965d2016-02-29 15:41:33 -0700606 t.find('.values input').each(function() {
Tyler Scottf355e452015-11-06 21:35:14 -0700607 var t = $(this);
608 values[t.attr('name')] = t.val();
609 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700610 variables.push({
611 variable: t.find('.variable').val(),
612 values: values
613 });
Tyler Scottf355e452015-11-06 21:35:14 -0700614 });
615 }
616
Tyler Scottcdfcde82015-09-14 16:13:29 -0600617 //Form checking
618 var dest = scope.requestForm.find('#requestDest .active');
Tyler Scott66a965d2016-02-29 15:41:33 -0700619 if (dest.length !== 1) {
Tyler Scottf355e452015-11-06 21:35:14 -0700620 var alert = $('<div class="alert alert-warning">A destination is required!' + closeButton + '<div>');
621 $('#request > .panel-body').append(alert);
Tyler Scottcdfcde82015-09-14 16:13:29 -0600622 return;
623 }
624
Tyler Scott66a965d2016-02-29 15:41:33 -0700625 $('#request').modal('hide');
626 //Initial params are ok. We can close the form.
Tyler Scottb59e6de2015-09-18 14:46:30 -0600627
628 scope.cleanRequestForm();
Tyler Scottcdfcde82015-09-14 16:13:29 -0600629
Tyler Scott66a965d2016-02-29 15:41:33 -0700630 $(this).off(e);
631 //Don't fire this again, the request must be regenerated
Tyler Scottcdfcde82015-09-14 16:13:29 -0600632
633 //Key setup
Tyler Scott66a965d2016-02-29 15:41:33 -0700634 if (!keyAdded) {
635 if (!scope.config.retrieval.demoKey || !scope.config.retrieval.demoKey.pub || !scope.config.retrieval.demoKey.priv) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600636 scope.createAlert("This host was not configured to handle retrieval! See console for details.", 'alert-danger');
637 console.error("Missing/invalid key! This must be configured in the config on the server.", scope.config.demoKey);
638 return;
639 }
640
641 //FIXME base64 may or may not exist in other browsers. Need a new polyfill.
Tyler Scott66a965d2016-02-29 15:41:33 -0700642 var pub = new Buffer(base64.toByteArray(scope.config.retrieval.demoKey.pub));
643 //MUST be a Buffer (Buffer != Uint8Array)
Tyler Scottcdfcde82015-09-14 16:13:29 -0600644 var priv = new Buffer(base64.toByteArray(scope.config.retrieval.demoKey.priv));
645
646 var identityStorage = new MemoryIdentityStorage();
647 var privateKeyStorage = new MemoryPrivateKeyStorage();
Tyler Scott66a965d2016-02-29 15:41:33 -0700648 keyChain = new KeyChain(new IdentityManager(identityStorage,privateKeyStorage),
649 new SelfVerifyPolicyManager(identityStorage));
Tyler Scottcdfcde82015-09-14 16:13:29 -0600650
651 var keyName = new Name("/retrieve/DSK-123");
652 certificateName = keyName.getSubName(0, keyName.size() - 1)
Tyler Scott66a965d2016-02-29 15:41:33 -0700653 .append("KEY").append(keyName.get(-1))
654 .append("ID-CERT").append("0");
Tyler Scottcdfcde82015-09-14 16:13:29 -0600655
Tyler Scott66a965d2016-02-29 15:41:33 -0700656 identityStorage.addKey(keyName, KeyType.RSA, new Blob(pub,false));
Tyler Scottcdfcde82015-09-14 16:13:29 -0600657 privateKeyStorage.setKeyPairForKeyName(keyName, KeyType.RSA, pub, priv);
658
659 scope.face.setCommandSigningInfo(keyChain, certificateName);
660
661 keyAdded = true;
662
663 }
664
665 //Retrieval
666 var retrievePrefix = new Name("/catalog/ui/" + guid());
667
Tyler Scottcdfcde82015-09-14 16:13:29 -0600668 scope.face.registerPrefix(retrievePrefix,
Tyler Scott66a965d2016-02-29 15:41:33 -0700669 function(prefix, interest, face, interestFilterId, filter) {
670 //On Interest
671 //This function will exist until the page exits but will likely only be used once.
Tyler Scottcdfcde82015-09-14 16:13:29 -0600672
Tyler Scott66a965d2016-02-29 15:41:33 -0700673 var data = new Data(interest.getName());
674 var content;
675 if (subset) {
676 content = JSON.stringify({
677 name: subsetFilename,
678 subset: variables
Tyler Scottd61bf832015-11-30 16:36:17 -0700679 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700680 } else {
681 content = JSON.stringify(names);
Tyler Scottcdfcde82015-09-14 16:13:29 -0600682 }
Tyler Scott66a965d2016-02-29 15:41:33 -0700683 //Blob breaks the data! Don't use it
684 data.setContent(content);
685 //TODO Packetize this.
686 keyChain.sign(data, certificateName);
687
688 try {
689 face.putData(data);
690 console.log("Responded for", interest.getName().toUri(), data);
691 scope.createAlert("Data retrieval has initiated.", "alert-success");
692 } catch (e) {
693 console.error("Failed to respond to", interest.getName().toUri(), data);
694 scope.createAlert("Data retrieval failed.");
695 }
696
697 }, function(prefix) {
698 //On fail
699 scope.createAlert("Failed to register the retrieval URI! See console for details.", "alert-danger");
700 console.error("Failed to register URI:", prefix.toUri(), prefix);
701 }, function(prefix, registeredPrefixId) {
702 //On success
703 var name = new Name(dest.text());
704 name.append(prefix);
705
706 scope.expressInterest(name,
707 function(interest, data) {
708 //Success
709 console.log("Request for", name.toUri(), "succeeded.", interest, data);
710 },
711 function() {
712 console.warn("Failed to request from retrieve agent.");
713 }
714 );
715 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600716 );
717
718 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700719 $('#request').modal();
720 //This forces the form to be the only option.
Tyler Scottcdfcde82015-09-14 16:13:29 -0600721
Tyler Scott66a965d2016-02-29 15:41:33 -0700722 }
723
Tyler Scottcdfcde82015-09-14 16:13:29 -0600724 }();
725
726 Atmos.prototype.filterSetup = function() {
727 //Filter setup
728
729 var prefix = new Name(this.catalog).append("filters-initialization");
730
731 var scope = this;
732
Tyler Scott66a965d2016-02-29 15:41:33 -0700733 this.getAll(prefix, function(data) {
734 //Success
735 var raw = JSON.parse(data.replace(/[\n\0]/g, ''));
736 //Remove null byte and parse
Tyler Scottcdfcde82015-09-14 16:13:29 -0600737
738 console.log("Filter categories:", raw);
739
Tyler Scott66a965d2016-02-29 15:41:33 -0700740 $.each(raw, function(index, object) {
741 //Unpack list of objects
742 $.each(object, function(category, searchOptions) {
743 //Unpack category from object (We don't know what it is called)
Tyler Scottcdfcde82015-09-14 16:13:29 -0600744 //Create the category
745 var e = $('<li><a href="#">' + category.replace(/_/g, " ") + '</a><ul class="subnav nav nav-pills nav-stacked"></ul></li>');
746
747 var sub = e.find('ul.subnav');
Tyler Scott66a965d2016-02-29 15:41:33 -0700748 $.each(searchOptions, function(index, name) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600749 //Create the filter list inside the category
750 var item = $('<li><a href="#">' + name + '</a></li>');
751 sub.append(item);
Tyler Scott66a965d2016-02-29 15:41:33 -0700752 item.click(function() {
753 //Click on the side menu filters
754 if (item.hasClass('active')) {
755 //Does the filter already exist?
Tyler Scottcdfcde82015-09-14 16:13:29 -0600756 item.removeClass('active');
757 scope.filters.find(':contains(' + category + ':' + name + ')').remove();
Tyler Scott66a965d2016-02-29 15:41:33 -0700758 } else {
759 //Add a filter
Tyler Scottcdfcde82015-09-14 16:13:29 -0600760 item.addClass('active');
761 var filter = $('<span class="label label-default"></span>');
762 filter.text(category + ':' + name);
763
764 scope.filters.append(filter);
765
Tyler Scott66a965d2016-02-29 15:41:33 -0700766 filter.click(function() {
767 //Click on a filter
Tyler Scottcdfcde82015-09-14 16:13:29 -0600768 filter.remove();
769 item.removeClass('active');
770 });
771 }
772
773 });
774 });
775
776 //Toggle the menus. (Only respond when the immediate tab is clicked.)
Tyler Scott66a965d2016-02-29 15:41:33 -0700777 e.find('> a').click(function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600778 scope.categories.find('.subnav').slideUp();
779 var t = $(this).siblings('.subnav');
Tyler Scott66a965d2016-02-29 15:41:33 -0700780 if (!t.is(':visible')) {
781 //If the sub menu is not visible
782 t.slideDown(function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600783 t.triggerHandler('focus');
Tyler Scott66a965d2016-02-29 15:41:33 -0700784 });
785 //Make it visible and look at it.
Tyler Scottcdfcde82015-09-14 16:13:29 -0600786 }
787 });
788
789 scope.categories.append(e);
790
791 });
792 });
793
Tyler Scott66a965d2016-02-29 15:41:33 -0700794 }, function(interest) {
795 //Timeout
Tyler Scottcdfcde82015-09-14 16:13:29 -0600796 scope.createAlert("Failed to initialize the filters!", "alert-danger");
797 console.error("Failed to initialize filters!", interest);
798 ga('send', 'event', 'error', 'filters');
799 });
800
Tyler Scott66a965d2016-02-29 15:41:33 -0700801 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600802
803 /**
804 * This function retrieves all segments in order until it knows it has reached the last one.
805 * It then returns the final joined result.
Tyler Scott66a965d2016-02-29 15:41:33 -0700806
Tyler Scottf355e452015-11-06 21:35:14 -0700807 * @param prefix {String|Name} The ndn name we are retrieving.
808 * @param callback {function(String)} if successful, will call the callback with a string of data.
809 * @param failure {function(Interest)} if unsuccessful, will call failure with the last failed interest.
810 * @param stop {boolean} stop if no finalBlock.
Tyler Scottcdfcde82015-09-14 16:13:29 -0600811 */
Tyler Scott66a965d2016-02-29 15:41:33 -0700812 Atmos.prototype.getAll = function(prefix, callback, failure, stop) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600813
814 var scope = this;
815 var d = [];
816
Tyler Scottd61bf832015-11-30 16:36:17 -0700817 var name = new Name(prefix);
818 var segment = 0;
Tyler Scott8724e422015-10-13 17:59:07 -0600819
Tyler Scott66a965d2016-02-29 15:41:33 -0700820 var request = function() {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600821
Tyler Scottd61bf832015-11-30 16:36:17 -0700822 var n2 = new Name(name);
823 n2.appendSegment(segment);
Tyler Scottcdfcde82015-09-14 16:13:29 -0600824
Tyler Scott66a965d2016-02-29 15:41:33 -0700825 scope.expressInterest(n2, handleData, function() {});
826 //Forward to handleData and ignore error
827 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600828
Tyler Scott66a965d2016-02-29 15:41:33 -0700829 var handleData = function(interest, data) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600830
831 d.push(data.getContent().toString());
832
Tyler Scottf355e452015-11-06 21:35:14 -0700833 var hasFinalBlock = data.getMetaInfo().getFinalBlockId().value.length === 0;
834 var finalBlockStop = hasFinalBlock && stop;
835
836 if (finalBlockStop ||
Tyler Scott66a965d2016-02-29 15:41:33 -0700837 (!hasFinalBlock && interest.getName().get(-1).toSegment() == data.getMetaInfo().getFinalBlockId().toSegment())) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600838 callback(d.join(""));
839 } else {
Tyler Scottd61bf832015-11-30 16:36:17 -0700840 segment++;
841 request();
Tyler Scottcdfcde82015-09-14 16:13:29 -0600842 }
843
Tyler Scott66a965d2016-02-29 15:41:33 -0700844 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600845
Tyler Scottd61bf832015-11-30 16:36:17 -0700846 request();
Tyler Scottcdfcde82015-09-14 16:13:29 -0600847
Tyler Scott66a965d2016-02-29 15:41:33 -0700848 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600849
Tyler Scott66a965d2016-02-29 15:41:33 -0700850 Atmos.prototype.cleanRequestForm = function() {
Tyler Scottb59e6de2015-09-18 14:46:30 -0600851 $('#requestDest').prev().removeClass('btn-success').addClass('btn-default');
852 $('#requestDropText').text('Destination');
853 $('#requestDest .active').removeClass('active');
Tyler Scottf355e452015-11-06 21:35:14 -0700854 $('#subsetMenu').attr('class', 'collapse');
855 $('#subsetVariables').empty();
856 $('#request .alert').alert('close').remove();
Tyler Scott66a965d2016-02-29 15:41:33 -0700857 }
Tyler Scottb59e6de2015-09-18 14:46:30 -0600858
Tyler Scott66a965d2016-02-29 15:41:33 -0700859 Atmos.prototype.setupRequestForm = function() {
Tyler Scottb59e6de2015-09-18 14:46:30 -0600860
861 var scope = this;
862
Tyler Scott66a965d2016-02-29 15:41:33 -0700863 this.requestForm.find('#requestCancel').click(function() {
864 $('#request').unbind('submit')//Removes all event handlers.
865 .modal('hide');
866 //Hides the form.
Tyler Scottb59e6de2015-09-18 14:46:30 -0600867 scope.cleanRequestForm();
Tyler Scottcdfcde82015-09-14 16:13:29 -0600868 });
869
Tyler Scott66a965d2016-02-29 15:41:33 -0700870 var dests = $(this.config['retrieval']['destinations'].reduce(function(prev, current) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600871 prev.push('<li><a href="#">');
872 prev.push(current);
873 prev.push("</a></li>");
874 return prev;
875 }, []).join(""));
876
877 this.requestForm.find('#requestDest').append(dests)
Tyler Scott66a965d2016-02-29 15:41:33 -0700878 .on('click', 'a', function(e) {
Tyler Scottcdfcde82015-09-14 16:13:29 -0600879 $('#requestDest .active').removeClass('active');
Tyler Scottb59e6de2015-09-18 14:46:30 -0600880 var t = $(this);
881 t.parent().addClass('active');
882 $('#requestDropText').text(t.text());
883 $('#requestDest').prev().removeClass('btn-default').addClass('btn-success');
Tyler Scottcdfcde82015-09-14 16:13:29 -0600884 });
885
Tyler Scott66a965d2016-02-29 15:41:33 -0700886 var addVariable = function(selector) {
887 var ele = $(selector).clone().attr('id', '');
888 ele.find('.close').click(function() {
Tyler Scottf355e452015-11-06 21:35:14 -0700889 ele.remove();
890 });
891 $('#subsetVariables').append(ele);
Tyler Scott66a965d2016-02-29 15:41:33 -0700892 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600893
Tyler Scott66a965d2016-02-29 15:41:33 -0700894 $('#subsetAddVariableBtn').click(function() {
Tyler Scottf355e452015-11-06 21:35:14 -0700895 addVariable('#customTemplate');
896 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700897 $('#subsetAddTimeVariable').click(function() {
Tyler Scottf355e452015-11-06 21:35:14 -0700898 addVariable('#timeTemplate');
899 });
Tyler Scott66a965d2016-02-29 15:41:33 -0700900 $('#subsetAddLocVariable').click(function() {
Tyler Scottf355e452015-11-06 21:35:14 -0700901 addVariable('#locationTemplate');
902 });
Tyler Scottcdfcde82015-09-14 16:13:29 -0600903
Tyler Scott66a965d2016-02-29 15:41:33 -0700904 }
Tyler Scottcdfcde82015-09-14 16:13:29 -0600905
Tyler Scott66a965d2016-02-29 15:41:33 -0700906 Atmos.prototype.getMetaData = (function() {
Tyler Scott48f92cd2015-10-16 18:31:20 -0600907
908 var cache = {};
909
910 return function(element) {
911 var name = $(element).text();
912
Tyler Scottf355e452015-11-06 21:35:14 -0700913 ga('send', 'event', 'request', 'metaData');
914
915 var subsetButton = '<button class="btn btn-default subsetButton" type="button">Subset</button>';
916
Tyler Scott48f92cd2015-10-16 18:31:20 -0600917 if (cache[name]) {
Tyler Scottf355e452015-11-06 21:35:14 -0700918 return [subsetButton, '<pre class="metaData">', cache[name], '</pre>'].join('');
Tyler Scott48f92cd2015-10-16 18:31:20 -0600919 }
920
921 var prefix = new Name(name).append("metadata");
Tyler Scott66a965d2016-02-29 15:41:33 -0700922 var id = guid();
923 //We need an id because the return MUST be a string.
Tyler Scott48f92cd2015-10-16 18:31:20 -0600924 var ret = '<div id="' + id + '"><span class="fa fa-spinner fa-spin"></span></div>';
925
Tyler Scott66a965d2016-02-29 15:41:33 -0700926 this.getAll(prefix, function(data) {
Tyler Scott48f92cd2015-10-16 18:31:20 -0600927 var el = $('<pre class="metaData"></pre>');
928 el.text(data);
Tyler Scottf355e452015-11-06 21:35:14 -0700929 var container = $('<div></div>');
930 container.append($(subsetButton));
931 container.append(el);
932 $('#' + id).empty().append(container);
Tyler Scott48f92cd2015-10-16 18:31:20 -0600933 cache[name] = data;
Tyler Scott66a965d2016-02-29 15:41:33 -0700934 }, function(interest) {
Tyler Scott48f92cd2015-10-16 18:31:20 -0600935 $('#' + id).text("The metadata is unavailable for this name.");
936 console.log("Data is unavailable for " + name);
937 });
938
939 return ret;
940
Tyler Scott66a965d2016-02-29 15:41:33 -0700941 }
Tyler Scott48f92cd2015-10-16 18:31:20 -0600942 })();
943
Tyler Scottcdfcde82015-09-14 16:13:29 -0600944 return Atmos;
945
946})();