blob: bdc9f5465d4f381019e8dffd948dcbd0b1569b6e [file] [log] [blame]
Tyler Scottcdfcde82015-09-14 16:13:29 -06001//Run when the document loads AND we have the config loaded.
2(function(){
3 "use strict";
4 var config;
5 Promise.all([
6 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 new Promise(function(resolve, reject){
17 var timeout = setTimeout(function(){
18 console.error("Document never loaded? Something bad has happened!");
19 reject();
20 }, 10000);
21 $(function () {
22 clearTimeout(timeout);
23 resolve();
24 });
25 })
26 ]).then(function(){
27 new Atmos(config);
28 }, function(){
29 console.error("Failed to initialize!");
30 ga('send', 'event', 'error', 'init');
31 });
32})();
33
34var Atmos = (function(){
35 "use strict";
36
37 var closeButton = '<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>';
38
39 var guid = function(){
40 var d = new Date().getTime();
41 var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
42 var r = (d + Math.random()*16)%16 | 0;
43 d = Math.floor(d/16);
44 return (c=='x' ? r : (r&0x3|0x8)).toString(16);
45 });
46 return uuid;
47 }
48
49 /**
50 * Atmos
51 * @version 2.0
52 *
53 * Configures an Atmos object. This manages the atmos interface.
54 *
55 * @constructor
56 * @param {string} catalog - NDN path
57 * @param {Object} config - Object of configuration options for a Face.
58 */
59 var Atmos = function(config){
60
61 //Internal variables.
62 this.results = [];
63 this.resultCount = Infinity;
64 this.name = null;
65 this.page = 0;
66 this.resultsPerPage = 25;
67 this.retrievedSegments = 0;
68
69 //Config/init
70 this.config = config;
71
72 this.catalog = config['global']['catalogPrefix'];
73
74 this.face = new Face(config['global']['faceConfig']);
75
76 //Easy access dom variables
77 this.categories = $('#side-menu');
78 this.resultTable = $('#resultTable');
79 this.filters = $('#filters');
80 this.searchInput = $('#search');
81 this.searchBar = $('#searchBar');
82 this.searchButton = $('#searchButton');
83 this.resultMenu = $('.resultMenu');
84 this.alerts = $('#alerts');
85 this.requestForm = $('#requestForm');
86
87 var scope = this;
88
89 $('.requestSelectedButton').click(function(){
90 ga('send', 'event', 'button', 'click', 'request');
91 scope.request(scope.resultTable.find('.resultSelector:checked:not([disabled])').parent().parent());
92 });
93
94 this.filterSetup();
95
96 //Init autocomplete
97 this.searchInput.autoComplete(function(field, callback){
98 ga('send', 'event', 'search', 'autocomplete');
Tyler Scott94458992015-09-24 14:16:28 -070099 scope.autoComplete(field, function(data){
100 var list = data.next;
101 var last = data.lastComponent === true;
Tyler Scottcdfcde82015-09-14 16:13:29 -0600102 callback(list.map(function(element){
Tyler Scott94458992015-09-24 14:16:28 -0700103 return field + element + (last?"/":""); //Don't add trailing slash for last component.
Tyler Scottcdfcde82015-09-14 16:13:29 -0600104 }));
105 });
106 });
107
108 //Handle search
109 this.searchBar.submit(function(e){
110 ga('send', 'event', 'search', 'submit');
111 e.preventDefault();
112 if (scope.searchInput.val().length === 0){
113 if (!scope.searchBar.hasClass('has-error')){
114 scope.searchBar.addClass('has-error').append('<span class="help-block">Search path is required!</span>');
115 }
116 return;
117 } else {
118 scope.searchBar.removeClass('has-error').find('.help-block').fadeOut(function(){$(this).remove()});
119 }
120 scope.pathSearch();
121 });
122
123 this.searchButton.click(function(){
124 console.log("Search Button Pressed");
125 ga('send', 'event', 'button', 'click', 'search');
126 scope.search();
127 });
128
129 //Result navigation handlers
130 this.resultMenu.find('.next').click(function(){
131 ga('send', 'event', 'button', 'click', 'next');
132 if (!$(this).hasClass('disabled')){
133 scope.getResults(scope.page + 1);
134 }
135 });
136 this.resultMenu.find('.previous').click(function(){
137 ga('send', 'event', 'button', 'click', 'previous');
138 if (!$(this).hasClass('disabled')){
139 scope.getResults(scope.page - 1);
140 }
141 });
142
143 //Change the number of results per page handler
144 var rpps = $('.resultsPerPageSelector').click(function(){
145
146 var t = $(this);
147
148 if (t.hasClass('active')){
149 return;
150 }
151
152 rpps.find('.active').removeClass('active');
153 t.addClass('active');
154 scope.resultsPerPage = Number(t.text());
155 scope.getResults(0); //Force return to page 1;
156
157 });
158
159 //Init tree search
160 $('#treeSearch div').treeExplorer(function(path, callback){
161 console.log("Tree Explorer request", path);
162 ga('send', 'event', 'tree', 'request');
Tyler Scottb59e6de2015-09-18 14:46:30 -0600163 scope.autoComplete(path, function(data){
164 var list = data.next;
165 var last = (data.lastComponent === true);
Tyler Scottcdfcde82015-09-14 16:13:29 -0600166 console.log("Autocomplete response", list);
167 callback(list.map(function(element){
Tyler Scottb59e6de2015-09-18 14:46:30 -0600168 return (path == "/"?"/":"") + element + (!last?"/":"");
Tyler Scottcdfcde82015-09-14 16:13:29 -0600169 }));
170 })
171 });
172
Tyler Scottb59e6de2015-09-18 14:46:30 -0600173 $('#treeSearch').on('click', '.treeSearch', function(){
174 var t = $(this);
175
176 scope.clearResults();
177
178 var path = t.parent().parent().attr('id');
179
180 console.log("Stringing tree search:", path);
181
182 scope.query(scope.catalog, {'??': path},
183 function(interest, data){ //Success
184 console.log("Tree search response", interest, data);
185
186 scope.name = data.getContent().toString().replace(/[\n\0]+/g,'');
187
188 scope.getResults(0);
189 },
190 function(interest){ //Failure
191 console.warn("Request failed! Timeout", interest);
192 scope.createAlert("Request timed out.\""+ interest.getName().toUri() + "\" See console for details.");
193 });
194
195 });
196
Tyler Scottcdfcde82015-09-14 16:13:29 -0600197 this.setupRequestForm();
198
199 }
200
201 Atmos.prototype.clearResults = function(){
202 this.results = []; //Drop any old results.
203 this.retrievedSegments = 0;
204 this.resultCount = Infinity;
205 this.page = 0;
206 this.resultTable.empty();
207 }
208
209 Atmos.prototype.pathSearch = function(){
210 var value = this.searchInput.val();
211
212 this.clearResults();
213
214 var scope = this;
215
216 this.query(this.catalog, {"??": value},
217 function(interest, data){
218 console.log("Query response:", interest, data);
219
220 scope.name = data.getContent().toString().replace(/[\n\0]/g,"");
221
222 scope.getResults(0);
223
224 },
225 function(interest){
226 console.warn("Request failed! Timeout", interest);
227 scope.createAlert("Request timed out. \"" + interest.getName().toUri() + "\" See console for details.");
228 });
229
230 }
231
232 Atmos.prototype.search = function(){
233
234 var filters = this.getFilters();
235
236 console.log("Search started!", this.searchInput.val(), filters);
237
238 console.log("Initiating query");
239
240 this.clearResults();
241
242 var scope = this;
243
244 this.query(this.catalog, filters,
245 function(interest, data){ //Response function
246 console.log("Query Response:", interest, data);
247
248 scope.name = data.getContent().toString().replace(/[\n\0]/g,"");
249
250 scope.getResults(0);
251
252 }, function(interest){ //Timeout function
253 console.warn("Request failed! Timeout");
254 scope.createAlert("Request timed out. \"" + interest.getName().toUri() + "\" See console for details.");
255 });
256
257 }
258
259 Atmos.prototype.autoComplete = function(field, callback){
260
261 var scope = this;
262
263 this.query(this.catalog, {"?": field},
264 function(interest, data){
265
266 var name = new Name(data.getContent().toString().replace(/[\n\0]/g,""));
267
268 var interest = new Interest(name);
269 interest.setInterestLifetimeMilliseconds(5000);
270 interest.setMustBeFresh(true);
271
272 scope.face.expressInterest(interest,
273 function(interest, data){
274
275 if (data.getContent().length !== 0){
Tyler Scottb59e6de2015-09-18 14:46:30 -0600276 callback(JSON.parse(data.getContent().toString().replace(/[\n\0]/g, "")));
Tyler Scottcdfcde82015-09-14 16:13:29 -0600277 } else {
278 callback([]);
279 }
280
281 }, function(interest){
282 console.warn("Interest timed out!", interest);
283 scope.createAlert("Request timed out. \"" + interest.getName().toUri() + "\" See console for details.");
284 });
285
286 }, function(interest){
287 console.error("Request failed! Timeout", interest);
288 scope.createAlert("Request timed out. \"" + interest.getName().toUri() + "\" See console for details.");
289 });
290
291 }
292
293 Atmos.prototype.showResults = function(resultIndex) {
294
295 var results = this.results.slice(this.resultsPerPage * resultIndex, this.resultsPerPage * (resultIndex + 1));
296
297 var resultDOM = $(
298 results.reduce(function(prev, current){
299 prev.push('<tr><td><input class="resultSelector" type="checkbox"></td><td>');
300 prev.push(current);
301 prev.push('</td></tr>');
302 return prev;
303 }, ['<tr><th><input id="resultSelectAll" type="checkbox" title="Select All"> Select</th><th>Name</th></tr>']).join('')
304 );
305
306 resultDOM.find('#resultSelectAll').click(function(){
307 if ($(this).is(':checked')){
308 resultDOM.find('.resultSelector:not([disabled])').prop('checked', true);
309 } else {
310 resultDOM.find('.resultSelector:not([disabled])').prop('checked', false);
311 }
312 });
313
314 this.resultTable.hide().empty().append(resultDOM).slideDown('slow');
315
316 this.resultMenu.find('.pageNumber').text(resultIndex + 1);
317 this.resultMenu.find('.pageLength').text(this.resultsPerPage * resultIndex + results.length);
318
319 if (this.resultsPerPage * (resultIndex + 1) >= this.resultCount) {
320 this.resultMenu.find('.next').addClass('disabled');
321 } else if (resultIndex === 0){
322 this.resultMenu.find('.next').removeClass('disabled');
323 }
324
325 if (resultIndex === 0){
326 this.resultMenu.find('.previous').addClass('disabled');
327 } else if (resultIndex === 1) {
328 this.resultMenu.find('.previous').removeClass('disabled');
329 }
330
331 }
332
333 Atmos.prototype.getResults = function(index){
334
335 if ($('#results').hasClass('hidden')){
336 $('#results').removeClass('hidden').slideDown();
337 }
338
Tyler Scottb59e6de2015-09-18 14:46:30 -0600339 $.scrollTo("#results", 700);
340
Tyler Scottcdfcde82015-09-14 16:13:29 -0600341 if ((this.results.length === this.resultCount) || (this.resultsPerPage * (index + 1) < this.results.length)){
342 //console.log("We already have index", index);
343 this.page = index;
344 this.showResults(index);
345 return;
346 }
347
348 if (this.name === null) {
349 console.error("This shouldn't be reached! We are getting results before a search has occured!");
350 throw new Error("Illegal State");
351 }
352
353 var first = new Name(this.name).appendSegment(this.retrievedSegments++);
354
355 console.log("Requesting data index: (", this.retrievedSegments - 1, ") at ", first.toUri());
356
357 var scope = this;
358
359 var interest = new Interest(first)
360 interest.setInterestLifetimeMilliseconds(5000);
361 interest.setMustBeFresh(true);
362
363 this.face.expressInterest(interest,
364 function(interest, data){ //Response
365
366 if (data.getContent().length === 0){
367 scope.resultMenu.find('.totalResults').text(0);
368 scope.resultMenu.find('.pageNumber').text(0);
369 scope.resultMenu.find('.pageLength').text(0);
370 console.log("Empty response.");
371 return;
372 }
373
374 var content = JSON.parse(data.getContent().toString().replace(/[\n\0]/g,""));
375
376 if (!content.results){
377 scope.resultMenu.find('.totalResults').text(0);
378 scope.resultMenu.find('.pageNumber').text(0);
379 scope.resultMenu.find('.pageLength').text(0);
380 console.log("No results were found!");
381 return;
382 }
383
384 scope.results = scope.results.concat(content.results);
385
386 scope.resultCount = content.resultCount;
387
388 scope.resultMenu.find('.totalResults').text(scope.resultCount);
389
390 scope.page = index;
391
392 scope.getResults(index); //Keep calling this until we have enough data.
393
394 },
395 function(interest){ //Timeout
396 console.error("Failed to retrieve results: timeout", interest);
397 scope.createAlert("Request timed out. \"" + interest.getName().toUri() + "\" See console for details.");
398 }
399 );
400
401 }
402
403 Atmos.prototype.query = function(prefix, parameters, callback, timeout) {
404
405 var queryPrefix = new Name(prefix);
406 queryPrefix.append("query");
407
408 var jsonString = JSON.stringify(parameters);
409 queryPrefix.append(jsonString);
410
411 var queryInterest = new Interest(queryPrefix);
412 queryInterest.setInterestLifetimeMilliseconds(4000);
413 queryInterest.setMustBeFresh(true);
414
415 this.face.expressInterest(queryInterest, callback, timeout);
416
417 }
418
419 /**
420 * This function returns a map of all the categories active filters.
421 * @return {Object<string, string>}
422 */
423 Atmos.prototype.getFilters = function(){
424 var filters = this.filters.children().toArray().reduce(function(prev, current){
425 var data = $(current).text().split(/:/);
426 prev[data[0]] = data[1];
427 return prev;
428 }, {}); //Collect a map<category, filter>.
429 //TODO Make the return value map<category, Array<filter>>
430 return filters;
431 }
432
433 /**
434 * Creates a closable alert for the user.
435 *
436 * @param {string} message
437 * @param {string} type - Override the alert type.
438 */
439 Atmos.prototype.createAlert = function(message, type) {
440
441 var alert = $('<div class="alert"><div>');
442 alert.addClass(type?type:'alert-info');
443 alert.text(message);
444 alert.append(closeButton);
445
446 this.alerts.append(alert);
447 }
448
449 /**
450 * Requests all of the names represented by the buttons in the elements list.
451 *
452 * @param elements {Array<jQuery>} A list of the table row elements
453 */
454 Atmos.prototype.request = function(){
455
456 //Pseudo globals.
457 var keyChain;
458 var certificateName;
459 var keyAdded = false;
460
461 return function(elements){
462
463 var names = [];
464 var destination = $('#requestDest .active').text();
465 $(elements).find('>*:nth-child(2)').each(function(){
466 var name = $(this).text();
467 names.push(name);
468 });//.append('<span class="badge">Requested!</span>')
469 //Disabling the checkbox doesn't make sense anymore with the ability to request to multiple destinations.
470 //$(elements).find('.resultSelector').prop('disabled', true).prop('checked', false);
471
472 var scope = this;
473 this.requestForm.on('submit', function(e){ //This will be registered for the next submit from the form.
474 e.preventDefault();
475
476 //Form checking
477 var dest = scope.requestForm.find('#requestDest .active');
478 if (dest.length !== 1){
479 $('#requestForm').append($('<div class="alert alert-warning">A destination is required!' + closeButton + '<div>'));
480 return;
481 }
482
483 $('#request').modal('hide')//Initial params are ok. We can close the form.
484 .remove('.alert') //Remove any alerts
Tyler Scottb59e6de2015-09-18 14:46:30 -0600485
486 scope.cleanRequestForm();
Tyler Scottcdfcde82015-09-14 16:13:29 -0600487
488 $(this).off(e); //Don't fire this again, the request must be regenerated
489
490 //Key setup
491 if (!keyAdded){
492 if (!scope.config.retrieval.demoKey || !scope.config.retrieval.demoKey.pub || !scope.config.retrieval.demoKey.priv){
493 scope.createAlert("This host was not configured to handle retrieval! See console for details.", 'alert-danger');
494 console.error("Missing/invalid key! This must be configured in the config on the server.", scope.config.demoKey);
495 return;
496 }
497
498 //FIXME base64 may or may not exist in other browsers. Need a new polyfill.
499 var pub = new Buffer(base64.toByteArray(scope.config.retrieval.demoKey.pub)); //MUST be a Buffer (Buffer != Uint8Array)
500 var priv = new Buffer(base64.toByteArray(scope.config.retrieval.demoKey.priv));
501
502 var identityStorage = new MemoryIdentityStorage();
503 var privateKeyStorage = new MemoryPrivateKeyStorage();
504 keyChain = new KeyChain(new IdentityManager(identityStorage, privateKeyStorage),
505 new SelfVerifyPolicyManager(identityStorage));
506
507 var keyName = new Name("/retrieve/DSK-123");
508 certificateName = keyName.getSubName(0, keyName.size() - 1)
509 .append("KEY").append(keyName.get(-1))
510 .append("ID-CERT").append("0");
511
512 identityStorage.addKey(keyName, KeyType.RSA, new Blob(pub, false));
513 privateKeyStorage.setKeyPairForKeyName(keyName, KeyType.RSA, pub, priv);
514
515 scope.face.setCommandSigningInfo(keyChain, certificateName);
516
517 keyAdded = true;
518
519 }
520
521 //Retrieval
522 var retrievePrefix = new Name("/catalog/ui/" + guid());
523
524 //Due to a lack of success callback in the register prefix function, we have to pretend we
525 //know it succeeded with an arbitrary timeout.
526 var sendTimer = setTimeout(function(){
527 var prefix = new Name(dest.text());
528 prefix.append(retrievePrefix);
529 var interest = new Interest(prefix);
530 interest.setInterestLifetimeMilliseconds(3000);
531 scope.face.expressInterest(interest,
532 function(interest, data){ //Success
533 console.log("Request for", prefix.toUri(), "succeeded.", interest, data);
Tyler Scottb59e6de2015-09-18 14:46:30 -0600534 scope.createAlert("Data retrieval has initiated.", "alert-success");
Tyler Scottcdfcde82015-09-14 16:13:29 -0600535 }, function(interest){ //Failure
Tyler Scottb59e6de2015-09-18 14:46:30 -0600536 console.error("Request for", prefix.toUri(), "timed out.", interest);
537 scope.createAlert("Request for " + prefix.toUri() + " timed out. This means that the retrieve failed! See console for more details.");
Tyler Scottcdfcde82015-09-14 16:13:29 -0600538 }
539 );
Tyler Scottb59e6de2015-09-18 14:46:30 -0600540 }, 5000); //Wait 5 seconds
Tyler Scottcdfcde82015-09-14 16:13:29 -0600541
542 scope.face.registerPrefix(retrievePrefix,
543 function(prefix, interest, face, interestFilterId, filter){ //On Interest
544 //This function will exist until the page exits but will likely only be used once.
545
546 var data = new Data(interest.getName());
547 var content = JSON.stringify(names);
548 data.setContent(content);
549 keyChain.sign(data, certificateName);
550
551 try {
552 face.putData(data);
553 console.log("Responded for", interest.getName().toUri(), data);
Tyler Scottcdfcde82015-09-14 16:13:29 -0600554 } catch (e) {
555 console.error("Failed to respond to", interest.getName().toUri(), data);
556 scope.createAlert("Data retrieval failed.");
557 }
558
559 }, function(prefix){ //On fail
560 clearTimeout(sendTimer); //Cancel the earlier request timer
561 scope.createAlert("Failed to register the retrieval URI! See console for details.", "alert-danger");
562 console.error("Failed to register URI:", prefix.toUri(), prefix);
563
564 }
565 );
566
567 });
568 $('#request').modal(); //This forces the form to be the only option.
569
570 }
571 }();
572
573 Atmos.prototype.filterSetup = function() {
574 //Filter setup
575
576 var prefix = new Name(this.catalog).append("filters-initialization");
577
578 var scope = this;
579
580 this.getAll(prefix, function(data) { //Success
581 var raw = JSON.parse(data.replace(/[\n\0]/g, '')); //Remove null byte and parse
582
583 console.log("Filter categories:", raw);
584
585 $.each(raw, function(index, object){ //Unpack list of objects
586 $.each(object, function(category, searchOptions) { //Unpack category from object (We don't know what it is called)
587 //Create the category
588 var e = $('<li><a href="#">' + category.replace(/_/g, " ") + '</a><ul class="subnav nav nav-pills nav-stacked"></ul></li>');
589
590 var sub = e.find('ul.subnav');
591 $.each(searchOptions, function(index, name){
592 //Create the filter list inside the category
593 var item = $('<li><a href="#">' + name + '</a></li>');
594 sub.append(item);
595 item.click(function(){ //Click on the side menu filters
596 if (item.hasClass('active')){ //Does the filter already exist?
597 item.removeClass('active');
598 scope.filters.find(':contains(' + category + ':' + name + ')').remove();
599 } else { //Add a filter
600 item.addClass('active');
601 var filter = $('<span class="label label-default"></span>');
602 filter.text(category + ':' + name);
603
604 scope.filters.append(filter);
605
606 filter.click(function(){ //Click on a filter
607 filter.remove();
608 item.removeClass('active');
609 });
610 }
611
612 });
613 });
614
615 //Toggle the menus. (Only respond when the immediate tab is clicked.)
616 e.find('> a').click(function(){
617 scope.categories.find('.subnav').slideUp();
618 var t = $(this).siblings('.subnav');
619 if ( !t.is(':visible') ){ //If the sub menu is not visible
620 t.slideDown(function(){
621 t.triggerHandler('focus');
622 }); //Make it visible and look at it.
623 }
624 });
625
626 scope.categories.append(e);
627
628 });
629 });
630
631 }, function(interest){ //Timeout
632 scope.createAlert("Failed to initialize the filters!", "alert-danger");
633 console.error("Failed to initialize filters!", interest);
634 ga('send', 'event', 'error', 'filters');
635 });
636
637 }
638
639 /**
640 * This function retrieves all segments in order until it knows it has reached the last one.
641 * It then returns the final joined result.
642 */
643 Atmos.prototype.getAll = function(prefix, callback, timeout){
644
645 var scope = this;
646 var d = [];
647
648 var request = function(segment){
649
650 var name = new Name(prefix);
651 name.appendSegment(segment);
652
653 var interest = new Interest(name);
654 interest.setInterestLifetimeMilliseconds(1000);
655 interest.setMustBeFresh(true); //Is this needed?
656
657 scope.face.expressInterest(interest, handleData, timeout);
658
659 }
660
661
662 var handleData = function(interest, data){
663
664 d.push(data.getContent().toString());
665
666 if (interest.getName().get(-1).toSegment() == data.getMetaInfo().getFinalBlockId().toSegment()){
667 callback(d.join(""));
668 } else {
669 request(interest.getName().toSegment()++);
670 }
671
672 }
673
674 request(0);
675
676 }
677
Tyler Scottb59e6de2015-09-18 14:46:30 -0600678 Atmos.prototype.cleanRequestForm = function(){
679 $('#requestDest').prev().removeClass('btn-success').addClass('btn-default');
680 $('#requestDropText').text('Destination');
681 $('#requestDest .active').removeClass('active');
682 }
683
Tyler Scottcdfcde82015-09-14 16:13:29 -0600684 Atmos.prototype.setupRequestForm = function(){
Tyler Scottb59e6de2015-09-18 14:46:30 -0600685
686 var scope = this;
687
Tyler Scottcdfcde82015-09-14 16:13:29 -0600688 this.requestForm.find('#requestCancel').click(function(){
689 $('#request').unbind('submit') //Removes all event handlers.
690 .modal('hide'); //Hides the form.
Tyler Scottb59e6de2015-09-18 14:46:30 -0600691 scope.cleanRequestForm();
Tyler Scottcdfcde82015-09-14 16:13:29 -0600692 });
693
694 var dests = $(this.config['retrieval']['destinations'].reduce(function(prev, current){
695 prev.push('<li><a href="#">');
696 prev.push(current);
697 prev.push("</a></li>");
698 return prev;
699 }, []).join(""));
700
701 this.requestForm.find('#requestDest').append(dests)
702 .on('click', 'a', function(e){
703 $('#requestDest .active').removeClass('active');
Tyler Scottb59e6de2015-09-18 14:46:30 -0600704 var t = $(this);
705 t.parent().addClass('active');
706 $('#requestDropText').text(t.text());
707 $('#requestDest').prev().removeClass('btn-default').addClass('btn-success');
Tyler Scottcdfcde82015-09-14 16:13:29 -0600708 });
709
710 //This code will remain unused until users must use their own keys instead of the demo key.
711// var scope = this;
712
713// var warning = '<div class="alert alert-warning">' + closeButton + '<div>';
714
715// var handleFile = function(e){
716// var t = $(this);
717// if (e.target.files.length > 1){
718// var el = $(warning);
719// t.append(el.append("We are looking for a single file, we will try the first only!"));
720// } else if (e.target.files.length === 0) {
721// var el = $(warning.replace("alert-warning", "alert-danger"));
722// t.append(el.append("No file was supplied!"));
723// return;
724// }
725
726// var reader = new FileReader();
727// reader.onload = function(e){
728// var key;
729// try {
730// key = JSON.parse(e.target.result);
731// } catch (e) {
732// console.error("Could not parse the key! (", key, ")");
733// var el = $(warning.replace("alert-warning", "alert-danger"));
734// t.append(el.append("Failed to parse the key file, is it a valid json key?"));
735// }
736
737// if (!key.DEFAULT_RSA_PUBLIC_KEY_DER || !key.DEFAULT_RSA_PRIVATE_KEY_DER) {
738// console.warn("Invalid key", key);
739// var el = $(warning.replace("alert-warning", "alert-danger"));
740// t.append(el.append("Failed to parse the key file, it is missing required attributes."));
741// }
742
743
744// };
745
746// }
747
748// this.requestForm.find('#requestDrop').on('dragover', function(e){
749// e.dataTransfer.dropEffect = 'copy';
750// }).on('drop', handleFile);
751
752// this.requestForm.find('input[type=file]').change(handleFile);
753
754 }
755
756 return Atmos;
757
758})();