commit/galaxy-central: guerler: Drag&drop multiple file upload: add status line, improve queueing, update select2
1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/72308af0df64/ Changeset: 72308af0df64 User: guerler Date: 2013-09-23 22:16:06 Summary: Drag&drop multiple file upload: add status line, improve queueing, update select2 Affected #: 6 files diff -r 4ef6df129520040017cfd4a287cb01558c6af35f -r 72308af0df6416a4cc888ee2cb5af90b3fd8f9fe static/scripts/galaxy.upload.js --- a/static/scripts/galaxy.upload.js +++ b/static/scripts/galaxy.upload.js @@ -17,6 +17,28 @@ // upload mod uploadbox: null, + // extension types + select_extension : { + '' : 'Auto-detect', + 'bed' : 'bed', + 'ab1' : 'ab1' + }, + + // counter + counter : { + // stats + announce : 0, + success : 0, + error : 0, + running : 0, + + // reset stats + reset : function() + { + this.announce = this.success = this.error = this.running = 0; + } + }, + // initialize initialize : function() { @@ -62,17 +84,14 @@ // start event_announce : function(index, file, message) { - // hide info - this.uploadbox.info().hide(); - // make id var id = '#upload-' + index; - + // add upload item - $(this.el).append(this.template_file(id)); + $(this.el).append(this.template_file(id, this.select_extension)); // scroll to bottom - $(this.el).scrollTop($(this.el).prop('scrollHeight')); + //$(this.el).scrollTop($(this.el).prop('scrollHeight')); // access upload item var it = this.get_upload_item(index); @@ -84,41 +103,7 @@ it.find('.title').html(file.name); // configure select field - it.find('#extension').select2( - { - placeholder: 'Auto-detect', - width: 'copy', - ajax: { - url: "http://www.weighttraining.com/sm/search", - dataType: 'jsonp', - quietMillis: 100, - data: function(term, page) - { - return { - types: ["exercise"], - limit: -1, - term: term - }; - }, - results: function(data, page) - { - return { results: data.results.exercise } - } - }, - formatResult: function(exercise) - { - return "<div class='select2-user-result'>" + exercise.term + "</div>"; - }, - formatSelection: function(exercise) - { - return exercise.term; - }, - initSelection : function (element, callback) - { - var elementText = $(element).attr('data-init-text'); - callback({"term":elementText}); - } - }); + //it.find('#extension').select2(); // add functionality to remove button var self = this; @@ -127,16 +112,18 @@ // initialize progress this.event_progress(index, file, 0); - // update button status - this.modal.enable('Upload'); - this.modal.enable('Reset'); + // update counter + this.counter.announce++; + + // update screen + this.update_screen(); }, // start event_initialize : function(index, file, message) { // update on screen counter - this.button_show.number(message); + this.button_show.number(this.counter.announce); // get element var it = this.get_upload_item(index); @@ -186,6 +173,13 @@ // update on screen counter this.button_show.number(''); + + // update counter + this.counter.announce--; + this.counter.success++; + + // update on screen info + this.update_screen(); }, // end @@ -209,11 +203,26 @@ // update on screen counter this.button_show.number(''); + + // update counter + this.counter.announce--; + this.counter.error++; + + // update on screen info + this.update_screen(); }, // start upload process event_upload : function() { + // check + if (this.counter.announce == 0 || this.counter.running > 0) + return; + + // update running + this.counter.running = this.counter.announce; + this.update_screen(); + // hide configuration $(this.el).find('.panel-body').hide(); @@ -223,10 +232,7 @@ $(this).removeClass('fa-icon-trash'); $(this).addClass('fa-icon-caret-down'); }); - - // update button status - this.modal.disable('Upload'); - + // configure url var current_history = Galaxy.currHistoryPanel.model.get('id'); this.uploadbox.configure({url : galaxy_config.root + "api/histories/" + current_history + "/contents"}); @@ -235,62 +241,61 @@ this.uploadbox.upload(); }, + // queue is done + event_complete: function() + { + // update running + this.counter.running = 0; + this.update_screen(); + }, + // remove all event_reset : function() { - // remove from screen - var panels = $(this.el).find('.panel'); - var self = this; - panels.fadeOut({complete: function() + // make sure queue is not running + if (this.counter.running == 0) { - // remove panels - panels.remove(); - + // remove from screen + var panels = $(this.el).find('.panel'); + panels.fadeOut({complete: function() { panels.remove(); }}); + + // reset counter + this.counter.reset(); + // show on screen info - self.uploadbox.info().fadeIn(); - }}); - - // update button status - this.modal.disable('Upload'); - this.modal.disable('Reset'); - - // remove from queue - this.uploadbox.reset(); + this.update_screen(); + + // remove from queue + this.uploadbox.reset(); + } }, // remove item from upload list event_remove : function(index) { - // remove - var self = this; - var it = this.get_upload_item(index); + // only remove from queue if paused + if (this.counter.running == 0) + { + // get item + var it = this.get_upload_item(index); - // fade out and update button status - it.fadeOut({complete: function() - { - // remove from screen + // reduce counter + if (it.hasClass('panel-default')) + this.counter.announce--; + else if (it.hasClass('panel-success')) + this.counter.success--; + else if (it.hasClass('panel-danger')) + this.counter.error--; + + // show on screen info + this.update_screen(); + + // remove from queue + this.uploadbox.remove(index); + + // remove element it.remove(); - - // remove from queue - self.uploadbox.remove(index); - - // update reset button - if ($(self.el).find('.panel').length > 0) - self.modal.enable('Reset'); - else { - // disable reset button - self.modal.disable('Reset'); - - // show on screen info - self.uploadbox.info().fadeIn(); - } - - // update upload button - if (self.uploadbox.length() > 0) - self.modal.enable('Upload'); - else - self.modal.disable('Upload'); - }}); + } }, // show/hide upload frame @@ -330,11 +335,11 @@ success : function(index, file, message) { self.event_success(index, file, message) }, progress : function(index, file, message) { self.event_progress(index, file, message) }, error : function(index, file, message) { self.event_error(index, file, message) }, + complete : function() { self.event_complete() }, }); - // update button status - this.modal.disable('Upload'); - this.modal.disable('Reset'); + // setup info + this.update_screen(); } // show modal @@ -362,34 +367,93 @@ return "<strong>" + (Math.round(size) / 10) + "</strong> " + unit; }, + // set screen + update_screen: function () + { + /* + update on screen info + */ + + // check default message + if(this.counter.announce == 0) + { + if (this.uploadbox.compatible) + message = 'Drag&drop files into this box or click \'Select\' to select files!'; + else + message = 'Unfortunately, your browser does not support multiple file uploads or drag&drop.<br>Please upgrade to i.e. Firefox 4+, Chrome 7+, IE 10+, Opera 12+ or Safari 6+.' + } else { + if (this.counter.running == 0) + message = 'You added ' + this.counter.announce + ' file(s) to the queue. Add more files or click "Upload" to proceed.'; + else + message = 'Please wait...' + this.counter.announce + ' out of ' + this.counter.running + ' remaining.'; + } + + // set html content + $('#upload-info').html(message); + + /* + update button status + */ + + // update reset button + if (this.counter.running == 0 && this.counter.announce + this.counter.success + this.counter.error > 0) + this.modal.enable('Reset'); + else + this.modal.disable('Reset'); + + // update upload button + if (this.counter.running == 0 && this.counter.announce > 0) + this.modal.enable('Upload'); + else + this.modal.disable('Upload'); + + // select upload button + if (this.counter.running == 0) + this.modal.enable('Select'); + else + this.modal.disable('Select'); + }, + // load html template template: function(id) { - return '<div id="' + id + '" class="upload-box"></div>'; + return '<div id="' + id + '" class="upload-box"></div><h6 id="upload-info" class="upload-info"></h6>'; }, // load html template - template_file: function(id) + template_file: function(id, select_extension) { - return '<div id="' + id.substr(1) + '" class="panel panel-default">' + - '<div class="panel-heading">' + - '<h5 class="title"></h5>' + - '<h5 class="info"></h5>' + - '<div class="remove fa-icon-trash"></div>' + - '</div>' + - '<div class="panel-body">' + - '<div class="menu">' + - //'<input id="extension" type="hidden" width="10px"/> ' + - '<span><input id="space_to_tabs" type="checkbox">Convert spaces to tabs</input></span>' + + // start template + var tmpl = '<div id="' + id.substr(1) + '" class="panel panel-default">' + + '<div class="panel-heading">' + + '<h5 class="title"></h5>' + + '<h5 class="info"></h5>' + + '<div class="remove fa-icon-trash"></div>' + '</div>' + - '</div>' + - '<div class="panel-footer">' + - '<div class="progress">' + - '<div class="progress-bar progress-bar-success"></div>' + + '<div class="panel-body">' + + '<div class="menu">' + + 'Select file type: ' + + '<select id="extension">'; + + // add file types to selection + for (key in select_extension) + tmpl += '<option value="' + key + '">' + select_extension[key] + '</option>'; + + // continue template + tmpl += '</select>, ' + + '<span>Convert space to tabs: <input id="space_to_tabs" type="checkbox"></input></span>' + + '</div>' + '</div>' + - '<h6 class="error"></h6>' + - '</div>' + - '</div>'; + '<div class="panel-footer">' + + '<div class="progress">' + + '<div class="progress-bar progress-bar-success"></div>' + + '</div>' + + '<h6 class="error"></h6>' + + '</div>' + + '</div>'; + + // return html string + return tmpl; } }); diff -r 4ef6df129520040017cfd4a287cb01558c6af35f -r 72308af0df6416a4cc888ee2cb5af90b3fd8f9fe static/scripts/libs/jquery/select2.js --- a/static/scripts/libs/jquery/select2.js +++ b/static/scripts/libs/jquery/select2.js @@ -1,7 +1,7 @@ /* Copyright 2012 Igor Vaynberg -Version: 3.4.2 Timestamp: Mon Aug 12 15:04:12 PDT 2013 +Version: 3.4.3 Timestamp: Tue Sep 17 06:47:14 PDT 2013 This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU General Public License version 2 (the "GPL License"). You may choose either license to govern your @@ -688,14 +688,18 @@ this.opts.element .data("select2", this) .attr("tabindex", "-1") - .before(this.container); + .before(this.container) + .on("click.select2", killEvent); // do not leak click events + this.container.data("select2", this); this.dropdown = this.container.find(".select2-drop"); + + syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass); + this.dropdown.addClass(evaluate(opts.dropdownCssClass)); this.dropdown.data("select2", this); - - syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass); + this.dropdown.on("click", killEvent); this.results = results = this.container.find(resultsSelector); this.search = search = this.container.find("input.select2-input"); @@ -707,6 +711,8 @@ // initialize the container this.initContainer(); + this.container.on("click", killEvent); + installFilteredMouseMove(this.results); this.dropdown.on("mousemove-filtered touchstart touchmove touchend", resultsSelector, this.bind(this.highlightUnderEvent)); @@ -968,10 +974,11 @@ opts.initSelection = function (element, callback) { var data = []; $(splitVal(element.val(), opts.separator)).each(function () { - var id = this, text = this, tags=opts.tags; + var obj = { id: this, text: this }, + tags = opts.tags; if ($.isFunction(tags)) tags=tags(); - $(tags).each(function() { if (equal(this.id, id)) { text = this.text; return false; } }); - data.push({id: id, text: text}); + $(tags).each(function() { if (equal(this.id, obj.id)) { obj = this; return false; } }); + data.push(obj); }); callback(data); @@ -1320,7 +1327,7 @@ $("#select2-drop-mask").hide(); this.dropdown.removeAttr("id"); // only the active dropdown has the select2-drop id this.dropdown.hide(); - this.container.removeClass("select2-dropdown-open"); + this.container.removeClass("select2-dropdown-open").removeClass("select2-container-active"); this.results.empty(); @@ -1395,7 +1402,7 @@ // abstract findHighlightableChoices: function() { - return this.results.find(".select2-result-selectable:not(.select2-selected):not(.select2-disabled)"); + return this.results.find(".select2-result-selectable:not(.select2-disabled)"); }, // abstract @@ -1926,10 +1933,7 @@ killEvent(e); return; case KEY.TAB: - // if selectOnBlur == true, select the currently highlighted option - if (this.opts.selectOnBlur) { - this.selectHighlighted({noFocus: true}); - } + this.selectHighlighted({noFocus: true}); return; case KEY.ESC: this.cancel(e); @@ -2046,6 +2050,11 @@ clear: function(triggerChange) { var data=this.selection.data("select2-data"); if (data) { // guard against queued quick consecutive clicks + var evt = $.Event("select2-clearing"); + this.opts.element.trigger(evt); + if (evt.isDefaultPrevented()) { + return; + } var placeholderOption = this.getPlaceholderOption(); this.opts.element.val(placeholderOption ? placeholderOption.val() : ""); this.selection.find(".select2-chosen").empty(); @@ -2083,7 +2092,7 @@ isPlaceholderOptionSelected: function() { var placeholderOption; - if (!this.opts.placeholder) return false; // no placeholder specified so no option should be considered + if (!this.getPlaceholder()) return false; // no placeholder specified so no option should be considered return ((placeholderOption = this.getPlaceholderOption()) !== undefined && placeholderOption.is(':selected')) || (this.opts.element.val() === "") || (this.opts.element.val() === undefined) @@ -2216,7 +2225,7 @@ this.close(); if (!options || !options.noFocus) - this.selection.focus(); + this.focusser.focus(); if (!equal(old, this.id(data))) { this.triggerChange({added:data,removed:oldData}); } }, @@ -2442,7 +2451,7 @@ this.selection = selection = this.container.find(selector); var _this = this; - this.selection.on("click", ".select2-search-choice", function (e) { + this.selection.on("click", ".select2-search-choice:not(.select2-locked)", function (e) { //killEvent(e); _this.search[0].focus(); _this.selectChoice($(this)); @@ -2521,10 +2530,7 @@ killEvent(e); return; case KEY.TAB: - // if selectOnBlur == true, select the currently highlighted option - if (this.opts.selectOnBlur) { - this.selectHighlighted({noFocus:true}); - } + this.selectHighlighted({noFocus:true}); this.close(); return; case KEY.ESC: @@ -2842,9 +2848,7 @@ return; } - index = indexOf(this.id(data), val); - - if (index >= 0) { + while((index = indexOf(this.id(data), val)) >= 0) { val.splice(index, 1); this.setVal(val); if (this.select) this.postprocessResults(); @@ -2925,7 +2929,7 @@ searchWidth = minimumWidth; } - this.search.width(searchWidth); + this.search.width(Math.floor(searchWidth)); }, // multi diff -r 4ef6df129520040017cfd4a287cb01558c6af35f -r 72308af0df6416a4cc888ee2cb5af90b3fd8f9fe static/scripts/utils/galaxy.uploadbox.js --- a/static/scripts/utils/galaxy.uploadbox.js +++ b/static/scripts/utils/galaxy.uploadbox.js @@ -19,11 +19,10 @@ progress : function() {}, success : function() {}, error : function(index, file, message) { alert(message); }, + complete : function() {}, error_browser : "Your browser does not support drag-and-drop file uploads.", error_filesize : "This file is too large (>250MB). Please use an FTP client to upload it.", - error_default : "Please make sure the file is available.", - text_default : "Drag&drop files into this box or click 'Select' to select files!", - text_degrade : "Unfortunately, your browser does not support multiple file uploads or drag&drop.<br>Please upgrade to i.e. Firefox 4+, Chrome 7+, IE 10+, Opera 12+ or Safari 6+." + error_default : "Please make sure the file is available." } // options @@ -32,7 +31,7 @@ // file queue var queue = {}; - // counter for file being currently processed + // queue index counter var queue_index = 0; // queue length @@ -50,21 +49,11 @@ // parse options opts = $.extend({}, default_opts, options); - // compatibility - var mode = window.File && window.FileReader && window.FormData && window.XMLHttpRequest; - // element el = this; // append upload button el.append('<input id="uploadbox_input" type="file" style="display: none" multiple>'); - el.append('<div id="uploadbox_info"></div>'); - - // set info text - if (mode) - el.find('#uploadbox_info').html(opts.text_default); - else - el.find('#uploadbox_info').html(opts.text_degrade); // attach events el.on('drop', drop); @@ -120,11 +109,15 @@ // respond to an upload request function add(files) { + // only allow adding file if current batch is complete + if (queue_status) + return; + // add new files to queue for (var i = 0; i < files.length; i++) { // new identifier - var index = String(++queue_index); + var index = String(queue_index++); // add to queue queue[index] = files[i]; @@ -153,6 +146,15 @@ // process an upload, recursive function process() { + // validate + if (queue_length == 0) + { + queue_status = false; + opts.complete(); + return; + } else + queue_status = true; + // get an identifier from the queue var index = -1; for (var key in queue) @@ -161,10 +163,6 @@ break; } - // validate - if (queue_length == 0) - return; - // get current file from queue var file = queue[index]; @@ -172,7 +170,7 @@ remove(index) // start - var data = opts.initialize(index, file, length); + var data = opts.initialize(index, file); // add file to queue try @@ -312,12 +310,6 @@ process(); } - // current queue length - function length() - { - return queue_length; - } - // set options function configure(options) { @@ -328,21 +320,20 @@ return opts; } - // visibility of on screen information - function info() + // verify browser compatibility + function compatible() { - return el.find('#uploadbox_info'); + return window.File && window.FileReader && window.FormData && window.XMLHttpRequest; } // export functions return { - 'select' : select, - 'remove' : remove, - 'upload' : upload, - 'reset' : reset, - 'length' : length, - 'configure' : configure, - 'info' : info + 'select' : select, + 'remove' : remove, + 'upload' : upload, + 'reset' : reset, + 'configure' : configure, + 'compatible' : compatible }; } })(jQuery); \ No newline at end of file diff -r 4ef6df129520040017cfd4a287cb01558c6af35f -r 72308af0df6416a4cc888ee2cb5af90b3fd8f9fe static/style/blue/base.css --- a/static/style/blue/base.css +++ b/static/style/blue/base.css @@ -1123,6 +1123,7 @@ .galaxy-frame .frame .f-close{right:5px;top:1px} .galaxy-frame .frame .f-pin{left:6px;top:1px} .galaxy-frame .frame .f-resize{background:#fff;width:16px;height:16px;color:#2c3143;right:0px;bottom:0px;text-align:center;line-height:16px;border:0px} +.upload-info{font-weight:normal;text-align:center} .upload-box{width:100%;height:250px;max-height:250px;text-align:center;overflow:scroll;font-size:12px;line-height:1.33;-moz-border-radius:5px;border-radius:5px;border:1px dashed #bfbfbf;padding:20px}.upload-box .panel{display:none}.upload-box .panel .panel-heading{position:relative;height:19px;padding:5px}.upload-box .panel .panel-heading .title{position:absolute;top:2px;font-weight:normal;text-align:left;margin:0px;max-width:300px;overflow:hidden} .upload-box .panel .panel-heading .info{position:absolute;top:3px;font-weight:normal;right:20px;text-align:right;margin:0px} .upload-box .panel .panel-heading .remove{position:absolute;cursor:pointer;top:0px;right:3px} @@ -1167,12 +1168,12 @@ .panel-warning-message{background-image:url(warn_small.png);background-color:#fce1ba} .panel-done-message{background-image:url(ok_small.png);background-color:#aff1af} .panel-info-message{background-image:url(info_small.png);background-color:#a6e4f7} -#masthead{position:absolute;top:0;left:0;width:100%;min-width:980px;padding:0}#masthead .nav{z-index:15001} +#masthead{position:absolute;top:0;left:0;width:100%;min-width:990px;padding:0}#masthead .nav{z-index:15001} #masthead .nav>li>a{cursor:pointer;text-decoration:none}#masthead .nav>li>a:hover{color:gold} #masthead li.dropdown>a:hover .caret{border-top-color:gold;border-bottom-color:gold} #masthead .navbar-brand{position:absolute;left:0;top:0;font-family:verdana;font-weight:bold;font-size:20px;line-height:1;color:white;padding:5px 20px 12px;margin-left:-15px;z-index:2000}#masthead .navbar-brand img{display:inline;width:26px;vertical-align:top} #masthead .navbar-brand a{color:white;text-decoration:none} -#masthead .iconbar{position:absolute;top:2px;right:110px;cursor:pointer;color:#999;overflow:hidden}#masthead .iconbar .symbol{float:left;margin:0px 8px} +#masthead .iconbar{position:absolute;top:2px;right:110px;cursor:pointer;color:#999;overflow:hidden}#masthead .iconbar .symbol{float:left;margin:0px 10px} #masthead .iconbar .symbol .number{font-weight:bold;font-size:12px;font-family:"Lucida Grande",verdana,arial,helvetica,sans-serif;position:relative;left:23px;top:-18px} #masthead .iconbar .toggle{color:#BCC800} .quota-meter-container{position:absolute;top:0;right:0;height:32px} diff -r 4ef6df129520040017cfd4a287cb01558c6af35f -r 72308af0df6416a4cc888ee2cb5af90b3fd8f9fe static/style/src/less/base.less --- a/static/style/src/less/base.less +++ b/static/style/src/less/base.less @@ -324,7 +324,7 @@ top:0; left:0; width:100%; - min-width:980px; + min-width:990px; padding: 0; .nav { @@ -387,7 +387,7 @@ .symbol { float : left; - margin : 0px 8px; + margin : 0px 10px; } .symbol .number diff -r 4ef6df129520040017cfd4a287cb01558c6af35f -r 72308af0df6416a4cc888ee2cb5af90b3fd8f9fe static/style/src/less/upload.less --- a/static/style/src/less/upload.less +++ b/static/style/src/less/upload.less @@ -1,3 +1,9 @@ +.upload-info +{ + font-weight: normal; + text-align: center; +} + .upload-box { width : 100%; Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.
participants (1)
-
commits-noreply@bitbucket.org