The big code and interface cleanup
Change-Id: I96c6a921950c5f479c023deddf6b3e979cc5ff18
diff --git a/client/catalog-dev/config-example.json b/client/catalog-dev/config-example.json
index 9c37d97..18c782e 100644
--- a/client/catalog-dev/config-example.json
+++ b/client/catalog-dev/config-example.json
@@ -1,18 +1,18 @@
{
- "global": {
- "catalogPrefix": "/catalog",
- "faceConfig": {
- "host": "atmos-nwsc.ucar.edu",
- "port": 9696
- }
- },
- "retrieval": {
- "demoKey": {
- "pub": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuAmnWYKE7E8G+hyy4TiTU7t91KyIGvglEeT6HWEkW4LKzXLO22a1jVS9+yP96I6vp7N5vpS1t7oXtgWuzkO+O85u6gfbvwp+67zJe2I89eHO4dmNnP4fx/j7WcCUCyzZfbyW67h5IoouoBIdQge2Xdvh9rFdex9UUhyjEZv5676zlcqlhz8xGBrJmQHsqpD9ijY1XhKBvoSIoQ0ZKkpmwVk8QYM9PbjUqzSQBj4aYXS+BPV6aRudVvyDt2DBXp2FNP0CGrosCXKnSl4Yv8BYp0k0RmFZDuJuntLb/XIvPEfMX5li7g3zHzAlIJIVSwT+FRkd3H5cECFSIZFUYIuSQQIDAQAB",
- "priv": "MIIEpQIBAAKCAQEAuAmnWYKE7E8G+hyy4TiTU7t91KyIGvglEeT6HWEkW4LKzXLO22a1jVS9+yP96I6vp7N5vpS1t7oXtgWuzkO+O85u6gfbvwp+67zJe2I89eHO4dmNnP4fx/j7WcCUCyzZfbyW67h5IoouoBIdQge2Xdvh9rFdex9UUhyjEZv5676zlcqlhz8xGBrJmQHsqpD9ijY1XhKBvoSIoQ0ZKkpmwVk8QYM9PbjUqzSQBj4aYXS+BPV6aRudVvyDt2DBXp2FNP0CGrosCXKnSl4Yv8BYp0k0RmFZDuJuntLb/XIvPEfMX5li7g3zHzAlIJIVSwT+FRkd3H5cECFSIZFUYIuSQQIDAQABAoIBAQCKBftzfxavn6lM5T8m+GZN0vzRBsBg8Z/jpsYKSLOayiHNKYCIPaSFpXuCIYEo6/JDJLB2xVLvwupLgkGSwm2mrvCyJkihI38Cz6iQF6I+iia9bYrupgwxzsK7klm1c+J9kXXivYxj4hyLwmoc/mnARMtYV7cTQvDbUEzgRQmPykWKBv6Y0SL1WprfiRfKIMwSqQk91ffj6whKxBLAuUdseVBmo/ivLPq0a+wDrcvaJAxSB4eIwCHzAugkRA/NoK0vG3mra0lK5jvQrcNIuffxNAnresDVDTnYRc42etjePLAhlpeK/4sjYE/wPdeP8yzLHUg/hsSpAPIjLXJNZqUBAoGBANxPmUQNf1lGHo/nLY3dVMD3+kYNnTUD8XwS81qdg8/dNyF8t+7DOdJ1j7Itb+zGA1XXAGfTm6JoUG+eKKR2OSuyZcxygpOgzxAFanXKhTWZsKbG70xNmX0sOAEhtTGsgFTEGEv977MwIlFa6n2bsp3Luj/AGmvNsOYvBDPXOklxAoGBANXZyXAaE7M5JALusLuEFxLGvWVz6TRdQ//c+FWvKrnh+nFlTlAPpDvlaPJJca8ViNevxJ2UhGtbENXAqgwTYpnAi/yQD4dATViIveK6Pn4t12mpPAlkMbbMTR8jtp5l1oHchcwe8QuEOKuTX5+STpNGlWs+tsMb12mhCpc3eO3RAoGAMxjDE2WOA8afkACuMBkFbzwUb+r4azNe7sf2aS3fRHaqMroabuYYoxdhHJItQ10pqN8U2P/bOO+4uCqWgo5o9BmMQr7MSjEh1TVsW6V8/9GFhyjcl3XoA4Ad/SU0QTEhEofomrdqwMSJMRVFDZzu8Gov6FlFx3sNbFW7Q8rHWgECgYEAq/TVz3iIgsLdvCXmosHSM9zvCpcr3FlqhmFOpseVmaamVWxajnIlY6xSuRBpg5nTUWwas4Nq/1BYtyiXE+K6lFuJtOq6Mc145EoANkIAYkHGR0Y36m1QtGaPVQzImZHV7NJAHCR9Ov90+jIk4BErca1+FKB3IWhPzLYb6ABJEyECgYEAthhzWSxPkqyiLl+2vnhdR3EEkvDX6MV6hGu4tDAf2A1Y0GSApyEaSAA31hlxu5EgneLD7Ns2HMpIfQMydB5lcwKQc9g/tVI1eRzuk6Myi+2JmPEM2BLyiX8yI+xnZlKDiZleQitCS4RQGz5HbXT70aYQIGxuvkQ/uf68jdrL6o8="
- },
- "destinations": [
- "/retrieve/ucar"
- ]
- }
+ "global": {
+ "catalogPrefix": "/catalog",
+ "faceConfig": {
+ "host": "atmos-nwsc.ucar.edu",
+ "port": 9696
+ }
+ },
+ "retrieval": {
+ "demoKey": {
+ "pub": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuAmnWYKE7E8G+hyy4TiTU7t91KyIGvglEeT6HWEkW4LKzXLO22a1jVS9+yP96I6vp7N5vpS1t7oXtgWuzkO+O85u6gfbvwp+67zJe2I89eHO4dmNnP4fx/j7WcCUCyzZfbyW67h5IoouoBIdQge2Xdvh9rFdex9UUhyjEZv5676zlcqlhz8xGBrJmQHsqpD9ijY1XhKBvoSIoQ0ZKkpmwVk8QYM9PbjUqzSQBj4aYXS+BPV6aRudVvyDt2DBXp2FNP0CGrosCXKnSl4Yv8BYp0k0RmFZDuJuntLb/XIvPEfMX5li7g3zHzAlIJIVSwT+FRkd3H5cECFSIZFUYIuSQQIDAQAB",
+ "priv": "MIIEpQIBAAKCAQEAuAmnWYKE7E8G+hyy4TiTU7t91KyIGvglEeT6HWEkW4LKzXLO22a1jVS9+yP96I6vp7N5vpS1t7oXtgWuzkO+O85u6gfbvwp+67zJe2I89eHO4dmNnP4fx/j7WcCUCyzZfbyW67h5IoouoBIdQge2Xdvh9rFdex9UUhyjEZv5676zlcqlhz8xGBrJmQHsqpD9ijY1XhKBvoSIoQ0ZKkpmwVk8QYM9PbjUqzSQBj4aYXS+BPV6aRudVvyDt2DBXp2FNP0CGrosCXKnSl4Yv8BYp0k0RmFZDuJuntLb/XIvPEfMX5li7g3zHzAlIJIVSwT+FRkd3H5cECFSIZFUYIuSQQIDAQABAoIBAQCKBftzfxavn6lM5T8m+GZN0vzRBsBg8Z/jpsYKSLOayiHNKYCIPaSFpXuCIYEo6/JDJLB2xVLvwupLgkGSwm2mrvCyJkihI38Cz6iQF6I+iia9bYrupgwxzsK7klm1c+J9kXXivYxj4hyLwmoc/mnARMtYV7cTQvDbUEzgRQmPykWKBv6Y0SL1WprfiRfKIMwSqQk91ffj6whKxBLAuUdseVBmo/ivLPq0a+wDrcvaJAxSB4eIwCHzAugkRA/NoK0vG3mra0lK5jvQrcNIuffxNAnresDVDTnYRc42etjePLAhlpeK/4sjYE/wPdeP8yzLHUg/hsSpAPIjLXJNZqUBAoGBANxPmUQNf1lGHo/nLY3dVMD3+kYNnTUD8XwS81qdg8/dNyF8t+7DOdJ1j7Itb+zGA1XXAGfTm6JoUG+eKKR2OSuyZcxygpOgzxAFanXKhTWZsKbG70xNmX0sOAEhtTGsgFTEGEv977MwIlFa6n2bsp3Luj/AGmvNsOYvBDPXOklxAoGBANXZyXAaE7M5JALusLuEFxLGvWVz6TRdQ//c+FWvKrnh+nFlTlAPpDvlaPJJca8ViNevxJ2UhGtbENXAqgwTYpnAi/yQD4dATViIveK6Pn4t12mpPAlkMbbMTR8jtp5l1oHchcwe8QuEOKuTX5+STpNGlWs+tsMb12mhCpc3eO3RAoGAMxjDE2WOA8afkACuMBkFbzwUb+r4azNe7sf2aS3fRHaqMroabuYYoxdhHJItQ10pqN8U2P/bOO+4uCqWgo5o9BmMQr7MSjEh1TVsW6V8/9GFhyjcl3XoA4Ad/SU0QTEhEofomrdqwMSJMRVFDZzu8Gov6FlFx3sNbFW7Q8rHWgECgYEAq/TVz3iIgsLdvCXmosHSM9zvCpcr3FlqhmFOpseVmaamVWxajnIlY6xSuRBpg5nTUWwas4Nq/1BYtyiXE+K6lFuJtOq6Mc145EoANkIAYkHGR0Y36m1QtGaPVQzImZHV7NJAHCR9Ov90+jIk4BErca1+FKB3IWhPzLYb6ABJEyECgYEAthhzWSxPkqyiLl+2vnhdR3EEkvDX6MV6hGu4tDAf2A1Y0GSApyEaSAA31hlxu5EgneLD7Ns2HMpIfQMydB5lcwKQc9g/tVI1eRzuk6Myi+2JmPEM2BLyiX8yI+xnZlKDiZleQitCS4RQGz5HbXT70aYQIGxuvkQ/uf68jdrL6o8="
+ },
+ "destinations": [
+ "/retrieve/ucar"
+ ]
+ }
}
diff --git a/client/catalog-dev/js/catalog.js b/client/catalog-dev/js/catalog.js
index 3e025b6..178ee18 100644
--- a/client/catalog-dev/js/catalog.js
+++ b/client/catalog-dev/js/catalog.js
@@ -1,83 +1,85 @@
//Run when the document loads AND we have the config loaded.
-(function(){
+(function() {
"use strict";
var config;
Promise.all([
- new Promise(function(resolve, reject){
- $.ajax('config.json').done(function(data){
- config = data;
- resolve();
- }).fail(function(){
- console.error("Failed to get config.");
- ga('send', 'event', 'error', 'config');
- reject();
- });
- }),
- new Promise(function(resolve, reject){
- var timeout = setTimeout(function(){
- console.error("Document never loaded? Something bad has happened!");
- reject();
- }, 10000);
- $(function () {
- clearTimeout(timeout);
- resolve();
- });
- })
- ]).then(function(){
+ new Promise(function(resolve, reject) {
+ $.ajax('../config.json').done(function(data) {
+ config = data;
+ resolve();
+ }).fail(function() {
+ console.error("Failed to get config.");
+ ga('send', 'event', 'error', 'config');
+ reject();
+ });
+ }
+ ),
+ new Promise(function(resolve, reject) {
+ var timeout = setTimeout(function() {
+ console.error("Document never loaded? Something bad has happened!");
+ reject();
+ }, 10000);
+ $(function() {
+ clearTimeout(timeout);
+ resolve();
+ });
+ }
+ )
+ ]).then(function() {
- var getParameterByName = function(name){
- name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
- var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
- results = regex.exec(location.search);
- return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
- };
+ var getParameterByName = function(name) {
+ name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
+ var regex = new RegExp("[\\?&]" + name + "=([^&#]*)");
+ var results = regex.exec(location.search);
+ return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
+ }
//Overwrite config if present. Any failure will just cause this to be skipped.
- try{
+ try {
var configParam = JSON.parse(getParameterByName('config'));
config = jQuery.extend(true, config, configParam);
- } catch(e){
+ } catch (e) {
console.warn("Failure in config overwrite, skipping.", e);
}
new Atmos(config);
- }, function(){
+ }, function() {
console.error("Failed to initialize!");
ga('send', 'event', 'error', 'init');
});
})();
-var Atmos = (function(){
+var Atmos = (function() {
"use strict";
var closeButton = '<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>';
- var guid = function(){
+ var guid = function() {
var d = new Date().getTime();
var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
- var r = (d + Math.random()*16)%16 | 0;
- d = Math.floor(d/16);
- return (c=='x' ? r : (r&0x3|0x8)).toString(16);
+ var r = (d + Math.random() * 16) % 16 | 0;
+ d = Math.floor(d / 16);
+ return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
return uuid;
- };
+ }
/**
* Atmos
* @version 2.0
- *
+
* Configures an Atmos object. This manages the atmos interface.
- *
+
* @constructor
* @param {string} catalog - NDN path
* @param {Object} config - Object of configuration options for a Face.
*/
- var Atmos = function(config){
+ var Atmos = function(config) {
//Internal variables.
this.results = [];
this.resultCount = Infinity;
- this.name = null;
+ this.name = null ;
this.page = 0;
this.resultsPerPage = 25;
this.retrievedSegments = 0;
@@ -103,7 +105,7 @@
var scope = this;
- $('.requestSelectedButton').click(function(){
+ $('.requestSelectedButton').click(function() {
ga('send', 'event', 'button', 'click', 'request');
scope.request(scope.resultTable.find('.resultSelector:checked:not([disabled])').parent().parent());
});
@@ -111,106 +113,113 @@
this.filterSetup();
//Init autocomplete
- this.searchInput.autoComplete(function(field, callback){
+ this.searchInput.autoComplete(function(field, callback) {
ga('send', 'event', 'search', 'autocomplete');
- scope.autoComplete(field, function(data){
+ scope.autoComplete(field, function(data) {
var list = data.next;
var last = data.lastComponent === true;
- callback(list.map(function(element){
- return field + element + (last?"/":""); //Don't add trailing slash for last component.
+ callback(list.map(function(element) {
+ return field + element + (last ? "/" : "");
+ //Don't add trailing slash for last component.
}));
});
});
//Handle search
- this.searchBar.submit(function(e){
+ this.searchBar.submit(function(e) {
ga('send', 'event', 'search', 'submit');
e.preventDefault();
- if (scope.searchInput.val().length === 0){
- if (!scope.searchBar.hasClass('has-error')){
+ if (scope.searchInput.val().length === 0) {
+ if (!scope.searchBar.hasClass('has-error')) {
scope.searchBar.addClass('has-error').append('<span class="help-block">Search path is required!</span>');
}
return;
} else {
- scope.searchBar.removeClass('has-error').find('.help-block').fadeOut(function(){$(this).remove()});
+ scope.searchBar.removeClass('has-error').find('.help-block').fadeOut(function() {
+ $(this).remove()
+ });
}
scope.pathSearch();
});
- this.searchButton.click(function(){
+ this.searchButton.click(function() {
console.log("Search Button Pressed");
ga('send', 'event', 'button', 'click', 'search');
scope.search();
});
//Result navigation handlers
- this.resultMenu.find('.next').click(function(){
+ this.resultMenu.find('.next').click(function() {
ga('send', 'event', 'button', 'click', 'next');
- if (!$(this).hasClass('disabled')){
+ if (!$(this).hasClass('disabled')) {
scope.getResults(scope.page + 1);
}
});
- this.resultMenu.find('.previous').click(function(){
+ this.resultMenu.find('.previous').click(function() {
ga('send', 'event', 'button', 'click', 'previous');
- if (!$(this).hasClass('disabled')){
+ if (!$(this).hasClass('disabled')) {
scope.getResults(scope.page - 1);
}
});
- this.resultMenu.find('.clearResults').click(function(){
+ this.resultMenu.find('.clearResults').click(function() {
ga('send', 'event', 'button', 'click', 'resultClear');
scope.clearResults();
- $('#results').fadeOut(function(){
+ $('#results').fadeOut(function() {
$(this).addClass('hidden');
});
});
//Change the number of results per page handler
- var rpps = $('.resultsPerPageSelector').click(function(){
+ var rpps = $('.resultsPerPageSelector').click(function() {
var t = $(this);
- if (t.hasClass('active')){
+ if (t.hasClass('active')) {
return;
}
rpps.find('.active').removeClass('active');
t.addClass('active');
scope.resultsPerPage = Number(t.text());
- scope.getResults(0); //Force return to page 1;
+ scope.getResults(0);
+ //Force return to page 1;
});
//Init tree search
- $('#treeSearch div').treeExplorer(function(path, callback){
+ $('#treeSearch div').treeExplorer(function(path, callback) {
console.log("Tree Explorer request", path);
ga('send', 'event', 'tree', 'request');
- scope.autoComplete(path, function(data){
+ scope.autoComplete(path, function(data) {
var list = data.next;
var last = (data.lastComponent === true);
if (last) {
console.log("Redirecting last element request to a search.");
scope.clearResults();
- scope.query(scope.catalog, {'??': path},
- function(interest, data){
+ scope.query(scope.catalog, {
+ '??': path
+ },
+ function(interest, data) {
console.log("Search response", interest, data);
scope.name = interest.getName();
scope.getResults(0);
- }, function(interest){
+ }, function(interest) {
console.warn("Failed to retrieve final component.", interest, path);
scope.createAlert("Failed to request final component. " + path + " See console for details.");
});
- return; //Don't call the callback
+ return;
+ //Don't call the callback
}
console.log("Autocomplete response", list);
- callback(list.map(function(element){
- return (path == "/"?"/":"") + element + "/";
+ callback(list.map(function(element) {
+ return (path == "/" ? "/" : "") + element + "/";
}));
});
});
- $('#treeSearch').on('click', '.treeSearch', function(){
+ $('#treeSearch').on('click', '.treeSearch', function() {
var t = $(this);
scope.clearResults();
@@ -219,17 +228,21 @@
console.log("Tree search:", path);
- scope.query(scope.catalog, {'??': path},
- function(interest, data){ //Success
+ scope.query(scope.catalog, {
+ '??': path
+ },
+ function(interest, data) {
+ //Success
console.log("Tree search response", interest, data);
scope.name = interest.getName();
scope.getResults(0);
},
- function(interest){ //Failure
+ function(interest) {
+ //Failure
console.warn("Request failed! Timeout", interest);
- scope.createAlert("Request timed out.\""+ interest.getName().toUri() + "\" See console for details.");
+ scope.createAlert("Request timed out.\"" + interest.getName().toUri() + "\" See console for details.");
});
});
@@ -237,8 +250,8 @@
this.setupRequestForm();
this.resultTable.popover({
- selector : ".metaDataLink",
- content: function(){
+ selector: ".metaDataLink",
+ content: function() {
return scope.getMetaData(this);
},
title: "Metadata",
@@ -247,53 +260,56 @@
placement: 'bottom'
});
- this.resultTable.on('click', '.metaDataLink', function(e){
+ this.resultTable.on('click', '.metaDataLink', function(e) {
//This prevents the page from scrolling when you click on a name.
e.preventDefault();
});
- this.resultTable.on('click', '.subsetButton', function(){
+ this.resultTable.on('click', '.subsetButton', function() {
var metaData = $(this).siblings('pre').text();
var exp = /netcdf ([\w-]+)/;
var match = exp.exec(metaData);
- var filename = match[0].replace(/netcdf /,'') + '.nc';
- scope.request(null, filename);
+ var filename = match[0].replace(/netcdf /, '') + '.nc';
+ scope.request(null , filename);
});
- };
+ }
- Atmos.prototype.clearResults = function(){
- this.results = []; //Drop any old results.
+ Atmos.prototype.clearResults = function() {
+ this.results = [];
+ //Drop any old results.
this.retrievedSegments = 0;
this.resultCount = Infinity;
this.page = 0;
this.resultTable.empty();
- };
+ }
- Atmos.prototype.pathSearch = function(){
+ Atmos.prototype.pathSearch = function() {
var value = this.searchInput.val();
this.clearResults();
var scope = this;
- this.query(this.catalog, {"??": value},
- function(interest, data){
+ this.query(this.catalog, {
+ "??": value
+ },
+ function(interest, data) {
console.log("Query response:", interest, data);
- scope.name = data.getName();
+ scope.name = interest.getName();
scope.getResults(0);
},
- function(interest){
+ function(interest) {
console.warn("Request failed! Timeout", interest);
scope.createAlert("Request timed out. \"" + interest.getName().toUri() + "\" See console for details.");
});
- };
+ }
- Atmos.prototype.search = function(){
+ Atmos.prototype.search = function() {
var filters = this.getFilters();
@@ -306,77 +322,78 @@
var scope = this;
this.query(this.catalog, filters,
- function(interest, data){ //Response function
+ function(interest, data) {
+ //Response function
console.log("Query Response:", interest, data);
scope.name = interest.getName();
scope.getResults(0);
- }, function(interest){ //Timeout function
+ }, function(interest) {
+ //Timeout function
console.warn("Request failed after 3 attempts!", interest);
scope.createAlert("Request failed after 3 attempts. \"" + interest.getName().toUri() + "\" See console for details.");
});
- };
+ }
- Atmos.prototype.autoComplete = function(field, callback){
+ Atmos.prototype.autoComplete = function(field, callback) {
var scope = this;
- this.query(this.catalog, {"?": field},
- function(interest, data){
+ var result = {};
- var name = interest.getName();
+ const getAll = function(interest, data) {
- var interest = new Interest(name);
- interest.setInterestLifetimeMilliseconds(1500);
- interest.setMustBeFresh(true);
-
- async.retry(4, function(done){
- scope.face.expressInterest(interest,
- function(interest, data){
-
- if (data.getContent().length !== 0){
- callback(JSON.parse(data.getContent().toString().replace(/[\n\0]/g, "")));
- done();
- } else {
- callback([]);
- done();
- }
-
- }, function(){
- done("Failed attempt to request data.")
- });
- }, function(err, results){
- if (err){
- console.warn("Interest timed out!", interest);
- scope.createAlert("Request failed after 3 attempts. \"" + interest.getName().toUri() + "\" See console for details.");
+ if (data.getContent().length !== 0) {
+ var resp = JSON.parse(data.getContent().toString().replace(/[\n\0]/g, ""));
+ if (result.next) {
+ result.next = result.next.concat(resp.next);
+ } else {
+ result = resp;
}
- });
+ } else {
+ callback(result);
+ }
- }, function(interest){
- console.error("Request failed! Timeout", interest);
- scope.createAlert("Request failed after 3 attempts. \"" + interest.getName().toUri() + "\" See console for details.");
- });
+ var name = data.getName();
+ var segment = name.components[name.getComponentCount() - 1];
+ if (segment.toSegment() !== data.getMetaInfo().getFinalBlockId().toSegment()){
+ name = name.getPrefix(-1); //Remove segment
+ name.appendSegment(segment.toSegment() + 1);
+ scope.expressInterest(name, getAll, function() {
+ console.warn("Autocomplete timed out, results may be incomplete.");
+ callback(result);
+ //Return if we get a timeout.
+ });
+ } else {
+ callback(result);
+ }
- };
+ }
+
+ this.query(this.catalog, {
+ "?": field
+ }, getAll);
+
+ }
Atmos.prototype.showResults = function(resultIndex) {
var results = this.results.slice(this.resultsPerPage * resultIndex, this.resultsPerPage * (resultIndex + 1));
var resultDOM = $(
- results.reduce(function(prev, current){
- prev.push('<tr><td><input class="resultSelector" type="checkbox"></td><td class="popover-container"><a href="#" class="metaDataLink">');
- prev.push(current);
- prev.push('</a></td></tr>');
- return prev;
- }, ['<tr><th><input id="resultSelectAll" type="checkbox" title="Select All"> Select</th><th>Name</th></tr>']).join('')
+ results.reduce(function(prev, current) {
+ prev.push('<tr><td><input class="resultSelector" type="checkbox"></td><td class="popover-container"><a href="#" class="metaDataLink">');
+ prev.push(current);
+ prev.push('</a></td></tr>');
+ return prev;
+ }, ['<tr><th><input id="resultSelectAll" type="checkbox" title="Select All"> Select</th><th>Name</th></tr>']).join('')
);
- resultDOM.find('#resultSelectAll').click(function(){
- if ($(this).is(':checked')){
+ resultDOM.find('#resultSelectAll').click(function() {
+ if ($(this).is(':checked')) {
resultDOM.find('.resultSelector:not([disabled])').prop('checked', true);
} else {
resultDOM.find('.resultSelector:not([disabled])').prop('checked', false);
@@ -390,35 +407,37 @@
if (this.resultsPerPage * (resultIndex + 1) >= this.resultCount) {
this.resultMenu.find('.next').addClass('disabled');
- } else if (resultIndex === 0){
+ } else if (resultIndex === 0) {
this.resultMenu.find('.next').removeClass('disabled');
}
- if (resultIndex === 0){
+ if (resultIndex === 0) {
this.resultMenu.find('.previous').addClass('disabled');
} else if (resultIndex === 1) {
this.resultMenu.find('.previous').removeClass('disabled');
}
- $.scrollTo("#results", 500, {interrupt: true});
+ $.scrollTo("#results", 500, {
+ interrupt: true
+ });
- };
+ }
- Atmos.prototype.getResults = function(index){
+ Atmos.prototype.getResults = function(index) {
var scope = this;
- if ($('#results').hasClass('hidden')){
+ if ($('#results').hasClass('hidden')) {
$('#results').removeClass('hidden').slideDown();
}
- if ((scope.results.length === scope.resultCount) || (scope.resultsPerPage * (index + 1) < scope.results.length)){
+ if ((scope.results.length === scope.resultCount) || (scope.resultsPerPage * (index + 1) < scope.results.length)) {
//console.log("We already have index", index);
scope.page = index;
scope.showResults(index);
return;
}
- if (scope.name === null) {
+ if (scope.name === null ) {
console.error("This shouldn't be reached! We are getting results before a search has occured!");
throw new Error("Illegal State");
}
@@ -428,66 +447,51 @@
// Interest name should be /<catalog-prefix>/query/<query-param>/<version>/<#seq>
if (scope.name.size() === (scope.catalogPrefix.size() + 3)) {
interestName = interestName.appendSegment(scope.retrievedSegments++);
- console.log("Requesting data index: (", scope.retrievedSegments - 1, ") at ", interestName.toUri());
+ //console.log("Requesting data index: (", scope.retrievedSegments - 1, ") at ", interestName.toUri());
}
- var interest = new Interest(interestName);
+ this.expressInterest(interestName,
+ function(interest, data) {
+ //Response
- interest.setInterestLifetimeMilliseconds(1500);
- interest.setMustBeFresh(true);
-
- async.retry(4, function(done){
- scope.face.expressInterest(interest,
- function(interest, data){ //Response
-
- if (data.getContent().length === 0){
- scope.resultMenu.find('.totalResults').text(0);
- scope.resultMenu.find('.pageNumber').text(0);
- scope.resultMenu.find('.pageLength').text(0);
- console.log("Empty response.");
- scope.resultTable.html("<tr><td>Empty response. This usually means no results.</td></tr>");
- return;
- }
-
- var content = JSON.parse(data.getContent().toString().replace(/[\n\0]/g,""));
-
- if (!content.results){
- scope.resultMenu.find('.totalResults').text(0);
- scope.resultMenu.find('.pageNumber').text(0);
- scope.resultMenu.find('.pageLength').text(0);
- console.log("No results were found!");
- scope.resultTable.html("<tr><td>No Results</td></tr>");
- return;
- }
-
- scope.results = scope.results.concat(content.results);
-
- scope.resultCount = content.resultCount;
-
- scope.resultMenu.find('.totalResults').text(scope.resultCount);
-
- scope.page = index;
-
- // reset scope.name
- scope.name = new Name(data.getName().getPrefix(scope.catalogPrefix.size() + 3));
-
- scope.getResults(index); //Keep calling this until we have enough data.
-
- done();
-
- },
- function(interest){ //Timeout
- done("Failed to request results.");
- }
- );
- }, function(err){
- if (err){
- console.error("Failed to retrieve results: timeout", interest);
- scope.createAlert("Request failed after 3 attempts. \"" + interest.getName().toUri() + "\" See console for details.");
+ if (data.getContent().length === 0) {
+ scope.resultMenu.find('.totalResults').text(0);
+ scope.resultMenu.find('.pageNumber').text(0);
+ scope.resultMenu.find('.pageLength').text(0);
+ console.log("Empty response.");
+ scope.resultTable.html("<tr><td>Empty response. This usually means no results.</td></tr>");
+ return;
}
- });
- };
+ var content = JSON.parse(data.getContent().toString().replace(/[\n\0]/g, ""));
+
+ if (!content.results) {
+ scope.resultMenu.find('.totalResults').text(0);
+ scope.resultMenu.find('.pageNumber').text(0);
+ scope.resultMenu.find('.pageLength').text(0);
+ console.log("No results were found!");
+ scope.resultTable.html("<tr><td>No Results</td></tr>");
+ return;
+ }
+
+ scope.results = scope.results.concat(content.results);
+
+ scope.resultCount = content.resultCount;
+
+ scope.resultMenu.find('.totalResults').text(scope.resultCount);
+
+ scope.page = index;
+
+ // reset scope.name
+ scope.name = new Name(data.getName().getPrefix(scope.catalogPrefix.size() + 3));
+
+ scope.getResults(index);
+ //Keep calling this until we have enough data.
+
+ }, function() {}//Ignore failure
+ );
+
+ }
Atmos.prototype.query = function(prefix, parameters, callback, timeout) {
@@ -497,81 +501,90 @@
var jsonString = JSON.stringify(parameters);
queryPrefix.append(jsonString);
- var queryInterest = new Interest(queryPrefix);
- queryInterest.setInterestLifetimeMilliseconds(1500);
- queryInterest.setMustBeFresh(true);
+ this.expressInterest(queryPrefix, callback, timeout);
- var face = this.face;
+ }
- async.retry(4, function(done){
- face.expressInterest(queryInterest, function(interest, data){
- callback(interest, data);
+
+ Atmos.prototype.expressInterest = function(name, success, failure) {
+
+ var interest = new Interest(name);
+ interest.setInterestLifetimeMilliseconds(1500);
+ interest.setMustBeFresh(true);
+
+ const face = this.face;
+
+ async.retry(4, function(done) {
+ face.expressInterest(interest, function(interest, data) {
done();
- }, function(interest){
- done("Failed attempt to query results", interest);
- });
- }, function(err, interest){
- if (err){
- timeout(interest);
+ success(interest, data);
+ }, function(interest) {
+ done("Interest timed out 4 times.", interest);
+ });
+ }, function(err, interest) {
+ if (err) {
+ console.log(err, interest);
+ failure(interest);
}
});
- };
+ }
/**
* This function returns a map of all the categories active filters.
* @return {Object<string, string>}
*/
- Atmos.prototype.getFilters = function(){
- var filters = this.filters.children().toArray().reduce(function(prev, current){
+ Atmos.prototype.getFilters = function() {
+ var filters = this.filters.children().toArray().reduce(function(prev, current) {
var data = $(current).text().split(/:/);
prev[data[0]] = data[1];
return prev;
- }, {}); //Collect a map<category, filter>.
+ }, {});
+ //Collect a map<category, filter>.
//TODO Make the return value map<category, Array<filter>>
return filters;
- };
+ }
/**
* Creates a closable alert for the user.
- *
+
* @param {string} message
* @param {string} type - Override the alert type.
*/
Atmos.prototype.createAlert = function(message, type) {
var alert = $('<div class="alert"><div>');
- alert.addClass(type?type:'alert-info');
+ alert.addClass(type ? type : 'alert-info');
alert.text(message);
alert.append(closeButton);
this.alerts.append(alert);
- };
+ }
/**
* Requests all of the names represented by the buttons in the elements list.
- *
+
* @param elements {Array<jQuery>} A list of the table row elements
* @param subsetFileName {String} If present then do a subsetting request instead.
*/
- Atmos.prototype.request = function(){
+ Atmos.prototype.request = function() {
//Pseudo globals.
var keyChain;
var certificateName;
var keyAdded = false;
- return function(elements, subsetFilename){
+ return function(elements, subsetFilename) {
var names = [];
- $(elements).find('.metaDataLink').each(function(){
+ $(elements).find('.metaDataLink').each(function() {
var name = $(this).text();
names.push(name);
});
var subset = false;
- if (!subsetFilename){
+ if (!subsetFilename) {
$('#subsetting').hide();
} else {
$('#subsetting').show();
@@ -579,61 +592,68 @@
}
var scope = this;
- this.requestForm.on('submit', function(e){ //This will be registered for the next submit from the form.
+ this.requestForm.on('submit', function(e) {
+ //This will be registered for the next submit from the form.
e.preventDefault();
$('#request .alert').remove();
var variables = [];
- if (subset){
- $('#subsetVariables .row').each(function(){
+ if (subset) {
+ $('#subsetVariables .row').each(function() {
var t = $(this);
var values = {};
- t.find('.values input').each(function(){
+ t.find('.values input').each(function() {
var t = $(this);
values[t.attr('name')] = t.val();
});
- variables.push({variable: t.find('.variable').val(), values: values});
+ variables.push({
+ variable: t.find('.variable').val(),
+ values: values
+ });
});
}
//Form checking
var dest = scope.requestForm.find('#requestDest .active');
- if (dest.length !== 1){
+ if (dest.length !== 1) {
var alert = $('<div class="alert alert-warning">A destination is required!' + closeButton + '<div>');
$('#request > .panel-body').append(alert);
return;
}
- $('#request').modal('hide');//Initial params are ok. We can close the form.
+ $('#request').modal('hide');
+ //Initial params are ok. We can close the form.
scope.cleanRequestForm();
- $(this).off(e); //Don't fire this again, the request must be regenerated
+ $(this).off(e);
+ //Don't fire this again, the request must be regenerated
//Key setup
- if (!keyAdded){
- if (!scope.config.retrieval.demoKey || !scope.config.retrieval.demoKey.pub || !scope.config.retrieval.demoKey.priv){
+ if (!keyAdded) {
+ if (!scope.config.retrieval.demoKey || !scope.config.retrieval.demoKey.pub || !scope.config.retrieval.demoKey.priv) {
scope.createAlert("This host was not configured to handle retrieval! See console for details.", 'alert-danger');
console.error("Missing/invalid key! This must be configured in the config on the server.", scope.config.demoKey);
return;
}
//FIXME base64 may or may not exist in other browsers. Need a new polyfill.
- var pub = new Buffer(base64.toByteArray(scope.config.retrieval.demoKey.pub)); //MUST be a Buffer (Buffer != Uint8Array)
+ var pub = new Buffer(base64.toByteArray(scope.config.retrieval.demoKey.pub));
+ //MUST be a Buffer (Buffer != Uint8Array)
var priv = new Buffer(base64.toByteArray(scope.config.retrieval.demoKey.priv));
var identityStorage = new MemoryIdentityStorage();
var privateKeyStorage = new MemoryPrivateKeyStorage();
- keyChain = new KeyChain(new IdentityManager(identityStorage, privateKeyStorage),
- new SelfVerifyPolicyManager(identityStorage));
+ keyChain = new KeyChain(new IdentityManager(identityStorage,privateKeyStorage),
+ new SelfVerifyPolicyManager(identityStorage));
var keyName = new Name("/retrieve/DSK-123");
certificateName = keyName.getSubName(0, keyName.size() - 1)
- .append("KEY").append(keyName.get(-1))
- .append("ID-CERT").append("0");
+ .append("KEY").append(keyName.get(-1))
+ .append("ID-CERT").append("0");
- identityStorage.addKey(keyName, KeyType.RSA, new Blob(pub, false));
+ identityStorage.addKey(keyName, KeyType.RSA, new Blob(pub,false));
privateKeyStorage.setKeyPairForKeyName(keyName, KeyType.RSA, pub, priv);
scope.face.setCommandSigningInfo(keyChain, certificateName);
@@ -646,62 +666,61 @@
var retrievePrefix = new Name("/catalog/ui/" + guid());
scope.face.registerPrefix(retrievePrefix,
- function(prefix, interest, face, interestFilterId, filter){ //On Interest
- //This function will exist until the page exits but will likely only be used once.
+ function(prefix, interest, face, interestFilterId, filter) {
+ //On Interest
+ //This function will exist until the page exits but will likely only be used once.
- var data = new Data(interest.getName());
- var content;
- if (subset){
- content = JSON.stringify({name: subsetFilename, subset: variables});
- } else {
- content = JSON.stringify(names);
- }
- //Blob breaks the data! Don't use it
- data.setContent(content); //TODO Packetize this.
- keyChain.sign(data, certificateName);
-
- try {
- face.putData(data);
- console.log("Responded for", interest.getName().toUri(), data);
- scope.createAlert("Data retrieval has initiated.", "alert-success");
- } catch (e) {
- console.error("Failed to respond to", interest.getName().toUri(), data);
- scope.createAlert("Data retrieval failed.");
- }
-
- }, function(prefix){ //On fail
- scope.createAlert("Failed to register the retrieval URI! See console for details.", "alert-danger");
- console.error("Failed to register URI:", prefix.toUri(), prefix);
- }, function(prefix, registeredPrefixId){ //On success
- var name = new Name(dest.text());
- name.append(prefix);
- var interest = new Interest(name);
- interest.setInterestLifetimeMilliseconds(1500);
-
- async.retry(4, function(done){
- scope.face.expressInterest(interest,
- function(interest, data){ //Success
- console.log("Request for", name.toUri(), "succeeded.", interest, data);
- done();
- },
- function(){
- done("Failed to request from retrieve agent.");
- }
- );
- }, function(err){
- if (err){
- console.error("Request for", name.toUri(), "timed out (3 times).", interest);
- scope.createAlert("Request for " + name.toUri() + " timed out after 3 attempts. This means that the retrieve failed! See console for more details.");
- }
+ var data = new Data(interest.getName());
+ var content;
+ if (subset) {
+ content = JSON.stringify({
+ name: subsetFilename,
+ subset: variables
});
-
+ } else {
+ content = JSON.stringify(names);
}
+ //Blob breaks the data! Don't use it
+ data.setContent(content);
+ //TODO Packetize this.
+ keyChain.sign(data, certificateName);
+
+ try {
+ face.putData(data);
+ console.log("Responded for", interest.getName().toUri(), data);
+ scope.createAlert("Data retrieval has initiated.", "alert-success");
+ } catch (e) {
+ console.error("Failed to respond to", interest.getName().toUri(), data);
+ scope.createAlert("Data retrieval failed.");
+ }
+
+ }, function(prefix) {
+ //On fail
+ scope.createAlert("Failed to register the retrieval URI! See console for details.", "alert-danger");
+ console.error("Failed to register URI:", prefix.toUri(), prefix);
+ }, function(prefix, registeredPrefixId) {
+ //On success
+ var name = new Name(dest.text());
+ name.append(prefix);
+
+ scope.expressInterest(name,
+ function(interest, data) {
+ //Success
+ console.log("Request for", name.toUri(), "succeeded.", interest, data);
+ },
+ function() {
+ console.warn("Failed to request from retrieve agent.");
+ }
+ );
+ }
);
});
- $('#request').modal(); //This forces the form to be the only option.
+ $('#request').modal();
+ //This forces the form to be the only option.
- };
+ }
+
}();
Atmos.prototype.filterSetup = function() {
@@ -711,33 +730,41 @@
var scope = this;
- this.getAll(prefix, function(data) { //Success
- var raw = JSON.parse(data.replace(/[\n\0]/g, '')); //Remove null byte and parse
+ this.getAll(prefix, function(data) {
+ //Success
+ var raw = JSON.parse(data.replace(/[\n\0]/g, ''));
+ //Remove null byte and parse
console.log("Filter categories:", raw);
- $.each(raw, function(index, object){ //Unpack list of objects
- $.each(object, function(category, searchOptions) { //Unpack category from object (We don't know what it is called)
+ $.each(raw, function(index, object) {
+ //Unpack list of objects
+ $.each(object, function(category, searchOptions) {
+ //Unpack category from object (We don't know what it is called)
//Create the category
var e = $('<li><a href="#">' + category.replace(/_/g, " ") + '</a><ul class="subnav nav nav-pills nav-stacked"></ul></li>');
var sub = e.find('ul.subnav');
- $.each(searchOptions, function(index, name){
+ $.each(searchOptions, function(index, name) {
//Create the filter list inside the category
var item = $('<li><a href="#">' + name + '</a></li>');
sub.append(item);
- item.click(function(){ //Click on the side menu filters
- if (item.hasClass('active')){ //Does the filter already exist?
+ item.click(function() {
+ //Click on the side menu filters
+ if (item.hasClass('active')) {
+ //Does the filter already exist?
item.removeClass('active');
scope.filters.find(':contains(' + category + ':' + name + ')').remove();
- } else { //Add a filter
+ } else {
+ //Add a filter
item.addClass('active');
var filter = $('<span class="label label-default"></span>');
filter.text(category + ':' + name);
scope.filters.append(filter);
- filter.click(function(){ //Click on a filter
+ filter.click(function() {
+ //Click on a filter
filter.remove();
item.removeClass('active');
});
@@ -747,13 +774,15 @@
});
//Toggle the menus. (Only respond when the immediate tab is clicked.)
- e.find('> a').click(function(){
+ e.find('> a').click(function() {
scope.categories.find('.subnav').slideUp();
var t = $(this).siblings('.subnav');
- if ( !t.is(':visible') ){ //If the sub menu is not visible
- t.slideDown(function(){
+ if (!t.is(':visible')) {
+ //If the sub menu is not visible
+ t.slideDown(function() {
t.triggerHandler('focus');
- }); //Make it visible and look at it.
+ });
+ //Make it visible and look at it.
}
});
@@ -762,24 +791,25 @@
});
});
- }, function(interest){ //Timeout
+ }, function(interest) {
+ //Timeout
scope.createAlert("Failed to initialize the filters!", "alert-danger");
console.error("Failed to initialize filters!", interest);
ga('send', 'event', 'error', 'filters');
});
- };
+ }
/**
* This function retrieves all segments in order until it knows it has reached the last one.
* It then returns the final joined result.
- *
+
* @param prefix {String|Name} The ndn name we are retrieving.
* @param callback {function(String)} if successful, will call the callback with a string of data.
* @param failure {function(Interest)} if unsuccessful, will call failure with the last failed interest.
* @param stop {boolean} stop if no finalBlock.
*/
- Atmos.prototype.getAll = function(prefix, callback, failure, stop){
+ Atmos.prototype.getAll = function(prefix, callback, failure, stop) {
var scope = this;
var d = [];
@@ -787,33 +817,16 @@
var name = new Name(prefix);
var segment = 0;
- var request = function(){
+ var request = function() {
var n2 = new Name(name);
n2.appendSegment(segment);
- var interest = new Interest(n2);
- interest.setInterestLifetimeMilliseconds(1500);
- interest.setMustBeFresh(true); //Is this needed?
+ scope.expressInterest(n2, handleData, function() {});
+ //Forward to handleData and ignore error
+ }
- async.retry(4, function(done){
- scope.face.expressInterest(interest,
- function(interest, data){
- handleData(interest, data);
- done();
- }, function(){
- done("Failed to get segment.");
- }
- );
- }, function(err){
- if (err){
- console.log("Failed after 3 attempts:", err);
- }
- });
-
- };
-
- var handleData = function(interest, data){
+ var handleData = function(interest, data) {
d.push(data.getContent().toString());
@@ -821,39 +834,40 @@
var finalBlockStop = hasFinalBlock && stop;
if (finalBlockStop ||
- (!hasFinalBlock && interest.getName().get(-1).toSegment() == data.getMetaInfo().getFinalBlockId().toSegment())){
+ (!hasFinalBlock && interest.getName().get(-1).toSegment() == data.getMetaInfo().getFinalBlockId().toSegment())) {
callback(d.join(""));
} else {
segment++;
request();
}
- };
+ }
request();
- };
+ }
- Atmos.prototype.cleanRequestForm = function(){
+ Atmos.prototype.cleanRequestForm = function() {
$('#requestDest').prev().removeClass('btn-success').addClass('btn-default');
$('#requestDropText').text('Destination');
$('#requestDest .active').removeClass('active');
$('#subsetMenu').attr('class', 'collapse');
$('#subsetVariables').empty();
$('#request .alert').alert('close').remove();
- };
+ }
- Atmos.prototype.setupRequestForm = function(){
+ Atmos.prototype.setupRequestForm = function() {
var scope = this;
- this.requestForm.find('#requestCancel').click(function(){
- $('#request').unbind('submit') //Removes all event handlers.
- .modal('hide'); //Hides the form.
+ this.requestForm.find('#requestCancel').click(function() {
+ $('#request').unbind('submit')//Removes all event handlers.
+ .modal('hide');
+ //Hides the form.
scope.cleanRequestForm();
});
- var dests = $(this.config['retrieval']['destinations'].reduce(function(prev, current){
+ var dests = $(this.config['retrieval']['destinations'].reduce(function(prev, current) {
prev.push('<li><a href="#">');
prev.push(current);
prev.push("</a></li>");
@@ -861,7 +875,7 @@
}, []).join(""));
this.requestForm.find('#requestDest').append(dests)
- .on('click', 'a', function(e){
+ .on('click', 'a', function(e) {
$('#requestDest .active').removeClass('active');
var t = $(this);
t.parent().addClass('active');
@@ -869,27 +883,27 @@
$('#requestDest').prev().removeClass('btn-default').addClass('btn-success');
});
- var addVariable = function(selector){
- var ele = $(selector).clone().attr('id','');
- ele.find('.close').click(function(){
+ var addVariable = function(selector) {
+ var ele = $(selector).clone().attr('id', '');
+ ele.find('.close').click(function() {
ele.remove();
});
$('#subsetVariables').append(ele);
- };
+ }
- $('#subsetAddVariableBtn').click(function(){
+ $('#subsetAddVariableBtn').click(function() {
addVariable('#customTemplate');
});
- $('#subsetAddTimeVariable').click(function(){
+ $('#subsetAddTimeVariable').click(function() {
addVariable('#timeTemplate');
});
- $('#subsetAddLocVariable').click(function(){
+ $('#subsetAddLocVariable').click(function() {
addVariable('#locationTemplate');
});
- };
+ }
- Atmos.prototype.getMetaData = (function(){
+ Atmos.prototype.getMetaData = (function() {
var cache = {};
@@ -905,10 +919,11 @@
}
var prefix = new Name(name).append("metadata");
- var id = guid(); //We need an id because the return MUST be a string.
+ var id = guid();
+ //We need an id because the return MUST be a string.
var ret = '<div id="' + id + '"><span class="fa fa-spinner fa-spin"></span></div>';
- this.getAll(prefix, function(data){
+ this.getAll(prefix, function(data) {
var el = $('<pre class="metaData"></pre>');
el.text(data);
var container = $('<div></div>');
@@ -916,14 +931,14 @@
container.append(el);
$('#' + id).empty().append(container);
cache[name] = data;
- }, function(interest){
+ }, function(interest) {
$('#' + id).text("The metadata is unavailable for this name.");
console.log("Data is unavailable for " + name);
});
return ret;
- };
+ }
})();
return Atmos;