New subsetting interface.
+ Fixes and improvements.
+ Added default value for subsetting variables.
Change-Id: I3b4681bfa4dc85e877465cec29d00166069d91b3
diff --git a/client/catalog-dev/js/catalog.js b/client/catalog-dev/js/catalog.js
index 158aad9..d8937cd 100644
--- a/client/catalog-dev/js/catalog.js
+++ b/client/catalog-dev/js/catalog.js
@@ -251,6 +251,14 @@
e.preventDefault();
});
+ 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);
+ });
+
}
Atmos.prototype.clearResults = function(){
@@ -393,6 +401,8 @@
this.resultMenu.find('.previous').removeClass('disabled');
}
+ $.scrollTo("#results", 500, {interrupt: true});
+
}
Atmos.prototype.getResults = function(index){
@@ -401,8 +411,6 @@
$('#results').removeClass('hidden').slideDown();
}
- $.scrollTo("#results", 500, {interrupt: true});
-
if ((this.results.length === this.resultCount) || (this.resultsPerPage * (index + 1) < this.results.length)){
//console.log("We already have index", index);
this.page = index;
@@ -524,6 +532,7 @@
* 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(){
@@ -532,30 +541,51 @@
var certificateName;
var keyAdded = false;
- return function(elements){
+ return function(elements, subsetFilename){
var names = [];
- var destination = $('#requestDest .active').text();
- $(elements).find('>*:nth-child(2)').each(function(){
+ $(elements).find('.metaDataLink').each(function(){
var name = $(this).text();
names.push(name);
- });//.append('<span class="badge">Requested!</span>')
- //Disabling the checkbox doesn't make sense anymore with the ability to request to multiple destinations.
- //$(elements).find('.resultSelector').prop('disabled', true).prop('checked', false);
+ });
+
+ var subset = false;
+
+ if (!subsetFilename){
+ $('#subsetting').hide();
+ } else {
+ $('#subsetting').show();
+ subset = true;
+ }
var scope = this;
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(){
+ var t = $(this);
+ var values = {};
+ t.find('.values input').each(function(){
+ var t = $(this);
+ values[t.attr('name')] = t.val();
+ });
+ variables.push({variable: t.find('.variable').val(), values: values});
+ });
+ }
+
//Form checking
var dest = scope.requestForm.find('#requestDest .active');
if (dest.length !== 1){
- $('#requestForm').append($('<div class="alert alert-warning">A destination is required!' + closeButton + '<div>'));
+ 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.
- .remove('.alert') //Remove any alerts
+ $('#request').modal('hide');//Initial params are ok. We can close the form.
scope.cleanRequestForm();
@@ -600,8 +630,14 @@
//This function will exist until the page exits but will likely only be used once.
var data = new Data(interest.getName());
- var content = JSON.stringify(names);
- data.setContent(content);
+ 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 {
@@ -616,7 +652,6 @@
}, 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);
@@ -717,8 +752,13 @@
/**
* 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){
+ Atmos.prototype.getAll = function(prefix, callback, failure, stop){
var scope = this;
var d = [];
@@ -726,7 +766,7 @@
var count = 3;
var retry = function(interest){
if (count === 0){
- console.log("Failed to 'getAll' after 3 attempts", interest);
+ console.log("Failed to 'getAll' after 3 attempts", interest.toUri(), interest);
failure(interest);
} else {
count--;
@@ -751,8 +791,11 @@
d.push(data.getContent().toString());
- if (data.getMetaInfo().getFinalBlockId().value.length !== 0 &&
- interest.getName().get(-1).toSegment() == data.getMetaInfo().getFinalBlockId().toSegment()){
+ var hasFinalBlock = data.getMetaInfo().getFinalBlockId().value.length === 0;
+ var finalBlockStop = hasFinalBlock && stop;
+
+ if (finalBlockStop ||
+ (!hasFinalBlock && interest.getName().get(-1).toSegment() == data.getMetaInfo().getFinalBlockId().toSegment())){
callback(d.join(""));
} else {
request(interest.getName().get(-1).toSegment() + 1);
@@ -768,6 +811,9 @@
$('#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(){
@@ -796,49 +842,23 @@
$('#requestDest').prev().removeClass('btn-default').addClass('btn-success');
});
- //This code will remain unused until users must use their own keys instead of the demo key.
-// var scope = this;
+ var addVariable = function(selector){
+ var ele = $(selector).clone().attr('id','');
+ ele.find('.close').click(function(){
+ ele.remove();
+ });
+ $('#subsetVariables').append(ele);
+ };
-// var warning = '<div class="alert alert-warning">' + closeButton + '<div>';
-
-// var handleFile = function(e){
-// var t = $(this);
-// if (e.target.files.length > 1){
-// var el = $(warning);
-// t.append(el.append("We are looking for a single file, we will try the first only!"));
-// } else if (e.target.files.length === 0) {
-// var el = $(warning.replace("alert-warning", "alert-danger"));
-// t.append(el.append("No file was supplied!"));
-// return;
-// }
-
-// var reader = new FileReader();
-// reader.onload = function(e){
-// var key;
-// try {
-// key = JSON.parse(e.target.result);
-// } catch (e) {
-// console.error("Could not parse the key! (", key, ")");
-// var el = $(warning.replace("alert-warning", "alert-danger"));
-// t.append(el.append("Failed to parse the key file, is it a valid json key?"));
-// }
-
-// if (!key.DEFAULT_RSA_PUBLIC_KEY_DER || !key.DEFAULT_RSA_PRIVATE_KEY_DER) {
-// console.warn("Invalid key", key);
-// var el = $(warning.replace("alert-warning", "alert-danger"));
-// t.append(el.append("Failed to parse the key file, it is missing required attributes."));
-// }
-
-
-// };
-
-// }
-
-// this.requestForm.find('#requestDrop').on('dragover', function(e){
-// e.dataTransfer.dropEffect = 'copy';
-// }).on('drop', handleFile);
-
-// this.requestForm.find('input[type=file]').change(handleFile);
+ $('#subsetAddVariableBtn').click(function(){
+ addVariable('#customTemplate');
+ });
+ $('#subsetAddTimeVariable').click(function(){
+ addVariable('#timeTemplate');
+ });
+ $('#subsetAddLocVariable').click(function(){
+ addVariable('#locationTemplate');
+ });
}
@@ -849,8 +869,12 @@
return function(element) {
var name = $(element).text();
+ ga('send', 'event', 'request', 'metaData');
+
+ var subsetButton = '<button class="btn btn-default subsetButton" type="button">Subset</button>';
+
if (cache[name]) {
- return ['<pre class="metaData">', cache[name], '</pre>'].join('');
+ return [subsetButton, '<pre class="metaData">', cache[name], '</pre>'].join('');
}
var prefix = new Name(name).append("metadata");
@@ -860,7 +884,10 @@
this.getAll(prefix, function(data){
var el = $('<pre class="metaData"></pre>');
el.text(data);
- $('#' + id).remove('span').append(el);
+ var container = $('<div></div>');
+ container.append($(subsetButton));
+ container.append(el);
+ $('#' + id).empty().append(container);
cache[name] = data;
}, function(interest){
$('#' + id).text("The metadata is unavailable for this name.");