1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/5636e8ac71d5/ Changeset: 5636e8ac71d5 User: guerler Date: 2014-09-22 20:41:51+00:00 Summary: ToolForm: Ensure correct order of repeat blocks, adjust to api changes, add validation, fix minor issues Affected #: 28 files diff -r f9e429b15b0eacada3a248d14e9b9dcc9be67ed5 -r 5636e8ac71d5955501e333dc6fa4693cc5905c1c client/galaxy/scripts/mvc/tools/tools-datasets.js --- a/client/galaxy/scripts/mvc/tools/tools-datasets.js +++ b/client/galaxy/scripts/mvc/tools/tools-datasets.js @@ -24,7 +24,8 @@ }); }, - // filter datasets by data type + /** Filters datasets by data type. + */ filterType: function(options) { options = options || {}; return this.currHistoryContents.filter(function(content){ @@ -43,7 +44,8 @@ }); }, - // filter datasets by id + /** Filter datasets by id. + */ filter: function(filter_id) { return _.first( this.currHistoryContents.filter( function( content ){ return content.get( 'id' ) === filter_id; }) ); } diff -r f9e429b15b0eacada3a248d14e9b9dcc9be67ed5 -r 5636e8ac71d5955501e333dc6fa4693cc5905c1c client/galaxy/scripts/mvc/tools/tools-form.js --- a/client/galaxy/scripts/mvc/tools/tools-form.js +++ b/client/galaxy/scripts/mvc/tools/tools-form.js @@ -1,4 +1,4 @@ -/* +/** This is the main class of the tool form plugin. It is referenced as 'app' in all lower level modules. */ define(['mvc/ui/ui-portlet', 'mvc/ui/ui-misc', @@ -37,14 +37,14 @@ // creates the job handler this.job_handler = new ToolJobs(this); - - // reset field list + + // reset field list, which contains the input field elements this.field_list = {}; - // reset sequential input definition list + // reset sequential input definition list, which contains the input definitions as provided from the api this.input_list = {}; - // reset input element definition list + // reset input element list, which contains the dom elements of each input element (includes also the input field) this.element_list = {}; // initialize datasets @@ -190,8 +190,6 @@ // trigger refresh self.refresh(); - //self.job_handler.submit(); - self.tree.finalize(); } }); } diff -r f9e429b15b0eacada3a248d14e9b9dcc9be67ed5 -r 5636e8ac71d5955501e333dc6fa4693cc5905c1c client/galaxy/scripts/mvc/tools/tools-jobs.js --- a/client/galaxy/scripts/mvc/tools/tools-jobs.js +++ b/client/galaxy/scripts/mvc/tools/tools-jobs.js @@ -1,4 +1,4 @@ -/* +/** This class handles job submissions and the error handling. */ define(['utils/utils'], function(Utils) { @@ -12,7 +12,8 @@ this.options = Utils.merge(options, this.optionsDefault); }, - // create job + /** Creates and submits a job request to the api + */ submit: function() { // link this var self = this; @@ -26,6 +27,12 @@ // reset this.app.reset(); + // validate job definition + if (!this._validation(job_def)) { + console.debug('tools-jobs::submit - Submission canceled. Validation failed.'); + return; + } + // post job Utils.request('POST', galaxy_config.root + 'api/tools', job_def, // success handler @@ -42,7 +49,7 @@ function(response) { console.debug(response); if (response && response.message && response.message.data) { - var error_messages = self.app.tree.match(response.message.data); + var error_messages = self.app.tree.matchResponse(response.message.data); for (var id in error_messages) { var error_text = error_messages[id]; if (!error_text) { @@ -55,7 +62,35 @@ ); }, - // refresh history panel + /** Validate job definition + */ + _validation: function(job_def) { + // get input parameters + var job_inputs = job_def.inputs; + + // validation flag + var valid = true; + + // check inputs + for (var job_input_id in job_inputs) { + // collect input field properties + var input = job_inputs[job_input_id]; + var input_id = this.app.tree.match(job_input_id); + var input_field = this.app.field_list[input_id]; + + // check field validation + //if (input_field && input_field.validate && !input_field.validate()) { + this.app.element_list[input_id].error('Please verify this parameter.'); + valid = false; + //} + } + + // return result + return false; + }, + + /** Refreshes the history panel + */ _refreshHdas: function() { if (parent.Galaxy && parent.Galaxy.currHistoryPanel) { parent.Galaxy.currHistoryPanel.refreshContents(); diff -r f9e429b15b0eacada3a248d14e9b9dcc9be67ed5 -r 5636e8ac71d5955501e333dc6fa4693cc5905c1c client/galaxy/scripts/mvc/tools/tools-repeat.js --- a/client/galaxy/scripts/mvc/tools/tools-repeat.js +++ b/client/galaxy/scripts/mvc/tools/tools-repeat.js @@ -1,14 +1,16 @@ // dependencies define(['utils/utils', 'mvc/ui/ui-table', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc'], function(Utils, Table, Portlet, Ui) { -// return +/** This class creates a ui component which enables the dynamic creation of portlets +*/ var View = Backbone.View.extend({ // default options optionsDefault : { max : null }, - // initialize + /** Initialize + */ initialize : function(options) { // configure options this.options = Utils.merge(options, this.optionsDefault); @@ -48,12 +50,14 @@ this.list = {}; }, - // size + /** Number of repeat blocks + */ size: function() { return _.size(this.list); }, - // append + /** Add new repeat block + */ add: function(options) { // delete button var button_delete = new Ui.ButtonIcon({ @@ -101,12 +105,15 @@ } }, - // delete + /** Delete repeat block + */ del: function(id) { if (this.list[id]) { // delete table row var table_row = this.table.get('row_' + id); table_row.remove(); + + // remove from list delete this.list[id]; // enable new button @@ -114,7 +121,8 @@ } }, - // retitle + /** Retitle/Enumerate repeat blocks + */ retitle: function(new_title) { var index = 0; for (var id in this.list) { diff -r f9e429b15b0eacada3a248d14e9b9dcc9be67ed5 -r 5636e8ac71d5955501e333dc6fa4693cc5905c1c client/galaxy/scripts/mvc/tools/tools-section.js --- a/client/galaxy/scripts/mvc/tools/tools-section.js +++ b/client/galaxy/scripts/mvc/tools/tools-section.js @@ -1,4 +1,4 @@ -/* +/** This class creates a tool form section and populates it with input elements. It also handles repeat blocks and conditionals by recursively creating new sub sections. New input elements can be plugged in by adding cases to the switch block defined in the _addRow() function. */ define(['utils/utils', 'mvc/ui/ui-table', 'mvc/ui/ui-misc', 'mvc/tools/tools-repeat', 'mvc/tools/tools-select-dataset'], @@ -11,19 +11,24 @@ this.setElement(this._template(options)); }, - // set error text + /** Set error text + */ error: function(text) { // set text this.$el.find('.ui-table-form-error-text').html(text); this.$el.find('.ui-table-form-error').fadeIn(); + this.$el.addClass('ui-error'); }, - // reset + /** Reset this view + */ reset: function() { this.$el.find('.ui-table-form-error').hide(); + this.$el.removeClass('ui-error'); }, - // template + /** Main Template + */ _template: function(options) { // create table element var $input = $('<div class="ui-table-element"/>'); @@ -73,7 +78,8 @@ this.render(); }, - // update + /** Render section view + */ render: function() { // reset table this.table.delAll(); @@ -84,7 +90,8 @@ } }, - // add table row + /** Add a new input element + */ _add: function(input) { // link this var self = this; @@ -115,7 +122,8 @@ } }, - // add conditional block + /** Add a conditional block + */ _addConditional: function(input_def) { // add label to input definition root input_def.label = input_def.test_param.label; @@ -148,11 +156,15 @@ } }, - // add repeat block + /** Add a repeat block + */ _addRepeat: function(input_def) { // link this var self = this; + // block index + var block_index = 0; + // // create tab field // @@ -161,7 +173,7 @@ max : input_def.max, onnew : function() { // create id tag - var sub_section_id = input_def.id + '-section-' + Utils.uuid(); + var sub_section_id = input_def.id + '-section-' + (block_index++); // create sub section var sub_section = new View(self.app, { @@ -199,7 +211,7 @@ // for (var i = 0; i < input_def.min; i++) { // create id tag - var sub_section_id = input_def.id + '-section-' + Utils.uuid(); + var sub_section_id = input_def.id + '-section-' + (block_index++); // create sub section var sub_section = new View(self.app, { @@ -235,7 +247,8 @@ this.table.append(input_def.id); }, - // add table row + /** Add a single field element + */ _addRow: function(field_type, input_def) { // get id var id = input_def.id; @@ -333,7 +346,8 @@ return this.table.get(id) }, - // conditional input field + /** Conditional input field selector + */ _field_conditional : function(input_def) { // link this var self = this; @@ -385,7 +399,8 @@ }); }, - // data input field + /** Data input field + */ _field_data : function(input_def) { // link this var self = this; @@ -398,16 +413,19 @@ id : 'field-' + id, extensions : input_def.extensions, multiple : input_def.multiple, - onchange : function(value) { + onchange : function(dict) { // pick the first dataset if multiple might be selected - // TODO: iterate over all datasets and filter common/consistent columns - if (value instanceof Array) { - value = value[0]; - } + var value = dict.values[0].id; // get referenced columns var column_list = self.app.tree.references(id, 'data_column'); + // check data column list + if (column_list.length <= 0) { + console.debug('tool-form::field_data() - Data column parameters unavailable.'); + return; + } + // find selected dataset var dataset = self.app.datasets.filter(value); @@ -415,7 +433,7 @@ var meta = null; // check dataset - if (dataset && column_list.length > 0) { + if (dataset) { // log selection console.debug('tool-form::field_data() - Selected dataset ' + value + '.'); @@ -427,7 +445,6 @@ console.debug('tool-form::field_data() - FAILED: Could not find metadata for dataset ' + value + '.'); } } else { - // log failure console.debug('tool-form::field_data() - FAILED: Could not find dataset ' + value + '.'); } @@ -479,7 +496,8 @@ }); }, - // select field + /** Select/Checkbox/Radio options field + */ _field_select : function (input_def) { // configure options fields var options = []; @@ -510,7 +528,8 @@ }); }, - // text input field + /** Text input field + */ _field_text : function(input_def) { return new Ui.Input({ id : 'field-' + input_def.id, @@ -518,7 +537,8 @@ }); }, - // slider field + /** Slider field + */ _field_slider: function(input_def) { // calculate step size var step = 1; @@ -535,14 +555,16 @@ }); }, - // hidden field + /** Hidden field + */ _field_hidden : function(input_def) { return new Ui.Hidden({ id : 'field-' + input_def.id }); }, - // boolean field + /** Boolean field + */ _field_boolean : function(input_def) { return new Ui.RadioButton.View({ id : 'field-' + input_def.id, diff -r f9e429b15b0eacada3a248d14e9b9dcc9be67ed5 -r 5636e8ac71d5955501e333dc6fa4693cc5905c1c client/galaxy/scripts/mvc/tools/tools-select-dataset.js --- a/client/galaxy/scripts/mvc/tools/tools-select-dataset.js +++ b/client/galaxy/scripts/mvc/tools/tools-select-dataset.js @@ -11,13 +11,13 @@ this.setElement('<div/>'); // current selection - this.current = 'dataset'; + this.current = 'hda'; // create button this.button_new = new Ui.RadioButton.View({ value : this.current, - data : [ { icon: 'fa-file-o', label : 'Select datasets', value : 'dataset' }, - { icon: 'fa-files-o', label : 'Select a collection', value : 'collection' }], + data : [ { icon: 'fa-file-o', label : 'Select datasets', value : 'hda' }, + { icon: 'fa-files-o', label : 'Select a collection', value : 'hdca' }], onchange: function(value) { self.current = value; self.refresh(); @@ -94,29 +94,62 @@ }); }, - // value + /** Return the currently selected dataset values */ value : function () { + // identify select element + var select = null; switch(this.current) { - case 'dataset': - return this.select_datasets.value(); - case 'collection': - return this.select_collection.value(); + case 'hda': + select = this.select_datasets; + break; + case 'hdca': + select = this.select_collection; + break; + } + + // transform into an array + var id_list = select.value(); + if (!(id_list instanceof Array)) { + id_list = [id_list]; + } + + // prepare result dict + var result = { + batch : !this.options.multiple, + values : [] + } + + // append to dataset ids + for (var i in id_list) { + result.values.push({ + id : id_list[i], + src : this.current + }); + } + + // return + return result; + }, + + /** Validate current selection + */ + validate: function() { + switch(this.current) { + case 'hda': + return this.select_datasets.validate(); + case 'hdca': + return this.select_collection.validate(); } }, - // render - update: function(options) { - this.select.update(options); - }, - - // refresh + /** Refreshes data selection view */ refresh: function() { switch (this.current) { - case 'dataset': + case 'hda': this.select_datasets.$el.fadeIn(); this.select_collection.$el.hide(); break; - case 'collection': + case 'hdca': this.select_datasets.$el.hide(); this.select_collection.$el.fadeIn(); break; diff -r f9e429b15b0eacada3a248d14e9b9dcc9be67ed5 -r 5636e8ac71d5955501e333dc6fa4693cc5905c1c client/galaxy/scripts/mvc/tools/tools-tree.js --- a/client/galaxy/scripts/mvc/tools/tools-tree.js +++ b/client/galaxy/scripts/mvc/tools/tools-tree.js @@ -67,11 +67,30 @@ switch (input.type) { // handle repeats case 'repeat': + // section identifier + var section_label = 'section-'; + + // collect repeat block identifiers + var block_indices = []; + var block_prefix = null; + for (var block_label in node) { + var pos = block_label.indexOf(section_label); + if (pos != -1) { + pos += section_label.length; + block_indices.push(parseInt(block_label.substr(pos))); + if (!block_prefix) { + block_prefix = block_label.substr(0, pos); + } + } + } + + // sort repeat blocks + block_indices.sort(function(a,b) { return a - b; }); + + // add to response dictionary in created order var index = 0; - for (var i in node) { - if (i.indexOf('section') != -1) { - convert(job_input_id + '_' + index++, node[i]); - } + for (var i in block_indices) { + convert(job_input_id + '_' + index++, node[block_prefix + block_indices[i]]); } break; // handle conditionals @@ -90,32 +109,6 @@ } } break; - // handle data inputs - case 'data': - // create array for dataset ids - var dataset_selection = null; - - // collect dataset ids from input field - var value = self.app.field_list[input.id].value(); - if (typeof value === 'string') { - dataset_selection = { - id : value, - src : 'hda' - }; - } else { - // create array of dataset dictionaries for api submission - dataset_selection = []; - for (var i in value) { - dataset_selection.push({ - id : value[i], - src : 'hda' - }); - } - } - - // add final array to job definition - add(job_input_id, input.id, dataset_selection); - break; // handle boolean input case 'boolean': var value = self.app.field_list[input.id].value(); @@ -136,14 +129,20 @@ // start conversion convert('', this.dict); - console.log(this.job_def); + // return result return this.job_def; }, + /** Match job definition identifier to input element identifier + */ + match: function (job_input_id) { + return this.job_ids && this.job_ids[job_input_id]; + }, + /** Matches identifier from api response to input element */ - match: function(response) { + matchResponse: function(response) { // final result dictionary var result = {}; @@ -263,7 +262,7 @@ var id = $(child).attr('id'); // create new branch - if ($(child).hasClass('section-row') || $(child).hasClass('tab-pane')) { + if ($(child).hasClass('section-row')) { // create sub dictionary dict[id] = {}; diff -r f9e429b15b0eacada3a248d14e9b9dcc9be67ed5 -r 5636e8ac71d5955501e333dc6fa4693cc5905c1c client/galaxy/scripts/mvc/ui/ui-options.js --- a/client/galaxy/scripts/mvc/ui/ui-options.js +++ b/client/galaxy/scripts/mvc/ui/ui-options.js @@ -1,7 +1,7 @@ // dependencies define(['utils/utils'], function(Utils) { -/** base class for options based ui elements **/ +/** Base class for options based ui elements **/ var OptionsBase = Backbone.View.extend({ // initialize initialize: function(options) { @@ -48,7 +48,8 @@ }); }, - // update options + /** Update options + */ update: function(options) { // backup current value var current = this._getValue(); @@ -80,7 +81,8 @@ this.value(current); }, - // check if selected value exists (or any if multiple) + /** Check if selected value exists (or any if multiple) + */ exists: function(value) { if (typeof value === 'string') { value = [value]; @@ -93,7 +95,8 @@ return false; }, - // first + /** Return first available option + */ first: function() { var options = this.$el.find('input'); if (options.length > 0) { @@ -103,14 +106,31 @@ } }, - // change + /** Validate the selected option/options + */ + validate: function() { + var current = this.value(); + if (!(current instanceof Array)) { + current = [current]; + } + for (var i in current) { + if (current[i] === 'null' || !current[i]) { + return false; + } + } + return true; + }, + + /** Trigger custom onchange callback function + */ _change: function() { if (this.options.onchange) { this.options.onchange(this._getValue()); } }, - // refresh + /** Refresh options view + */ _refresh: function() { // count remaining options var remaining = this.$el.find('.ui-option').length; @@ -123,7 +143,8 @@ } }, - // get value + /** Return current selection + */ _getValue: function() { // get selected values var selected = this.$el.find(':checked'); @@ -148,7 +169,7 @@ } }); -/** radio button field **/ +/** Radio button field **/ var Radio = {}; Radio.View = OptionsBase.extend({ // initialize @@ -156,7 +177,8 @@ OptionsBase.prototype.initialize.call(this, options); }, - // value + /** Return/Set current value + */ value: function (new_val) { // check if its an array if (typeof new_val === 'string') { @@ -178,20 +200,22 @@ return this._getValue(); }, - // template for options + /** Template for options + */ _templateOption: function(pair) { return '<div>' + '<input type="radio" name="' + this.options.id + '" value="' + pair.value + '"/>' + pair.label + '<br>' + '</div>'; }, - // template + /** Main template function + */ _template: function() { return '<div class="ui-options"/>'; } }); -/** checkbox options field **/ +/** Checkbox options field **/ var Checkbox = {}; Checkbox.View = Radio.View.extend({ // initialize @@ -200,7 +224,8 @@ Radio.View.prototype.initialize.call(this, options); }, - // template for options + /** Template for options + */ _templateOption: function(pair) { return '<div>' + '<input type="checkbox" name="' + this.options.id + '" value="' + pair.value + '"/>' + pair.label + '<br>' + @@ -208,7 +233,7 @@ } }); -/** radio button options field styled as classic buttons **/ +/** Radio button options field styled as classic buttons **/ var RadioButton = {}; RadioButton.View = OptionsBase.extend({ // initialize @@ -216,7 +241,8 @@ OptionsBase.prototype.initialize.call(this, options); }, - // value + /** Return/Set current value + */ value: function (new_val) { // set new value if (new_val !== undefined) { @@ -229,7 +255,8 @@ return this._getValue(); }, - // template for options + /** Template for options + */ _templateOption: function(pair) { var tmpl = '<label class="btn btn-default">'; if (pair.icon) { @@ -240,7 +267,8 @@ return tmpl; }, - // template + /** Main template function + */ _template: function() { return '<div class="btn-group ui-radiobutton" data-toggle="buttons"/>'; } diff -r f9e429b15b0eacada3a248d14e9b9dcc9be67ed5 -r 5636e8ac71d5955501e333dc6fa4693cc5905c1c client/galaxy/scripts/mvc/ui/ui-portlet.js --- a/client/galaxy/scripts/mvc/ui/ui-portlet.js +++ b/client/galaxy/scripts/mvc/ui/ui-portlet.js @@ -153,7 +153,7 @@ // fill regular modal template _template: function(options) { - var tmpl = '<div class="' + options.cls + '">'; + var tmpl = '<div id="' + options.id + '" class="' + options.cls + '">'; if (options.title) { tmpl += '<div id="portlet-header" class="portlet-header">' + diff -r f9e429b15b0eacada3a248d14e9b9dcc9be67ed5 -r 5636e8ac71d5955501e333dc6fa4693cc5905c1c client/galaxy/scripts/mvc/ui/ui-select-default.js --- a/client/galaxy/scripts/mvc/ui/ui-select-default.js +++ b/client/galaxy/scripts/mvc/ui/ui-select-default.js @@ -63,7 +63,8 @@ }); }, - // value + /** Return/Set current selection + */ value : function (new_value) { if (new_value !== undefined) { this.$select.val(new_value); @@ -71,7 +72,8 @@ return this.$select.val(); }, - // first + /** Return the first select option + */ first: function() { var options = this.$select.find('option'); if (options.length > 0) { @@ -81,12 +83,29 @@ } }, - // label + /** Validate the current selection + */ + validate: function() { + var current = this.value(); + if (!(current instanceof Array)) { + current = [current]; + } + for (var i in current) { + if (current[i] === 'null' || !current[i]) { + return false; + } + } + return true; + }, + + /** Return the label/text of the current selection + */ text : function () { return this.$select.find('option:selected').text(); }, - // show + /** Show the select field + */ show: function() { this.$icon.removeClass(); this.$icon.addClass('fa fa-caret-down'); @@ -94,34 +113,40 @@ this.$el.show(); }, - // hide + /** Hide the select field + */ hide: function() { this.$el.hide(); }, - // wait + /** Show a spinner indicating that the select options are currently loaded + */ wait: function() { this.$icon.removeClass(); this.$icon.addClass('fa fa-spinner fa-spin'); this.$select.hide(); }, - // disabled + /** Returns true if the field is disabled + */ disabled: function() { return this.$select.is(':disabled'); }, - // enable + /** Enable the select field + */ enable: function() { this.$select.prop('disabled', false); }, - // disable + /** Disable the select field + */ disable: function() { this.$select.prop('disabled', true); }, - // add + /** Add a select option + */ add: function(options) { // add options this.$select.append(this._templateOption(options)); @@ -130,7 +155,8 @@ this._refresh(); }, - // remove + /** Delete a select option + */ del: function(value) { // remove option this.$select.find('option[value=' + value + ']').remove(); @@ -140,7 +166,8 @@ this._refresh(); }, - // render + /** Update select options + */ update: function(options) { // backup current value var current = this.$select.val(); @@ -165,24 +192,28 @@ } }, - // set on change event + /** Set the custom onchange callback function + */ setOnChange: function(callback) { this.options.onchange = callback; }, - // check if selected value exists + /** Check if a value is an existing option + */ exists: function(value) { return this.$select.find('option[value="' + value + '"]').length > 0; }, - // change + /** Trigger custom onchange callback + */ _change: function() { if (this.options.onchange) { this.options.onchange(this.$select.val()); } }, - // refresh + /** Refresh the select view + */ _refresh: function() { // remove placeholder this.$select.find('option[value=null]').remove(); @@ -201,12 +232,14 @@ } }, - // template option + /** Template for select options + */ _templateOption: function(options) { return '<option value="' + options.value + '">' + options.label + '</option>'; }, - // template + /** Template for select view + */ _template: function(options) { return '<div id="' + options.id + '">' + '<div class="button">' + diff -r f9e429b15b0eacada3a248d14e9b9dcc9be67ed5 -r 5636e8ac71d5955501e333dc6fa4693cc5905c1c static/scripts/mvc/tools/tools-datasets.js --- a/static/scripts/mvc/tools/tools-datasets.js +++ b/static/scripts/mvc/tools/tools-datasets.js @@ -24,7 +24,8 @@ }); }, - // filter datasets by data type + /** Filters datasets by data type. + */ filterType: function(options) { options = options || {}; return this.currHistoryContents.filter(function(content){ @@ -43,7 +44,8 @@ }); }, - // filter datasets by id + /** Filter datasets by id. + */ filter: function(filter_id) { return _.first( this.currHistoryContents.filter( function( content ){ return content.get( 'id' ) === filter_id; }) ); } diff -r f9e429b15b0eacada3a248d14e9b9dcc9be67ed5 -r 5636e8ac71d5955501e333dc6fa4693cc5905c1c static/scripts/mvc/tools/tools-form.js --- a/static/scripts/mvc/tools/tools-form.js +++ b/static/scripts/mvc/tools/tools-form.js @@ -1,4 +1,4 @@ -/* +/** This is the main class of the tool form plugin. It is referenced as 'app' in all lower level modules. */ define(['mvc/ui/ui-portlet', 'mvc/ui/ui-misc', @@ -37,14 +37,14 @@ // creates the job handler this.job_handler = new ToolJobs(this); - - // reset field list + + // reset field list, which contains the input field elements this.field_list = {}; - // reset sequential input definition list + // reset sequential input definition list, which contains the input definitions as provided from the api this.input_list = {}; - // reset input element definition list + // reset input element list, which contains the dom elements of each input element (includes also the input field) this.element_list = {}; // initialize datasets @@ -190,8 +190,6 @@ // trigger refresh self.refresh(); - //self.job_handler.submit(); - self.tree.finalize(); } }); } diff -r f9e429b15b0eacada3a248d14e9b9dcc9be67ed5 -r 5636e8ac71d5955501e333dc6fa4693cc5905c1c static/scripts/mvc/tools/tools-jobs.js --- a/static/scripts/mvc/tools/tools-jobs.js +++ b/static/scripts/mvc/tools/tools-jobs.js @@ -1,4 +1,4 @@ -/* +/** This class handles job submissions and the error handling. */ define(['utils/utils'], function(Utils) { @@ -12,7 +12,8 @@ this.options = Utils.merge(options, this.optionsDefault); }, - // create job + /** Creates and submits a job request to the api + */ submit: function() { // link this var self = this; @@ -26,6 +27,12 @@ // reset this.app.reset(); + // validate job definition + if (!this._validation(job_def)) { + console.debug('tools-jobs::submit - Submission canceled. Validation failed.'); + return; + } + // post job Utils.request('POST', galaxy_config.root + 'api/tools', job_def, // success handler @@ -42,7 +49,7 @@ function(response) { console.debug(response); if (response && response.message && response.message.data) { - var error_messages = self.app.tree.match(response.message.data); + var error_messages = self.app.tree.matchResponse(response.message.data); for (var id in error_messages) { var error_text = error_messages[id]; if (!error_text) { @@ -55,7 +62,35 @@ ); }, - // refresh history panel + /** Validate job definition + */ + _validation: function(job_def) { + // get input parameters + var job_inputs = job_def.inputs; + + // validation flag + var valid = true; + + // check inputs + for (var job_input_id in job_inputs) { + // collect input field properties + var input = job_inputs[job_input_id]; + var input_id = this.app.tree.match(job_input_id); + var input_field = this.app.field_list[input_id]; + + // check field validation + //if (input_field && input_field.validate && !input_field.validate()) { + this.app.element_list[input_id].error('Please verify this parameter.'); + valid = false; + //} + } + + // return result + return false; + }, + + /** Refreshes the history panel + */ _refreshHdas: function() { if (parent.Galaxy && parent.Galaxy.currHistoryPanel) { parent.Galaxy.currHistoryPanel.refreshContents(); diff -r f9e429b15b0eacada3a248d14e9b9dcc9be67ed5 -r 5636e8ac71d5955501e333dc6fa4693cc5905c1c static/scripts/mvc/tools/tools-repeat.js --- a/static/scripts/mvc/tools/tools-repeat.js +++ b/static/scripts/mvc/tools/tools-repeat.js @@ -1,14 +1,16 @@ // dependencies define(['utils/utils', 'mvc/ui/ui-table', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc'], function(Utils, Table, Portlet, Ui) { -// return +/** This class creates a ui component which enables the dynamic creation of portlets +*/ var View = Backbone.View.extend({ // default options optionsDefault : { max : null }, - // initialize + /** Initialize + */ initialize : function(options) { // configure options this.options = Utils.merge(options, this.optionsDefault); @@ -48,12 +50,14 @@ this.list = {}; }, - // size + /** Number of repeat blocks + */ size: function() { return _.size(this.list); }, - // append + /** Add new repeat block + */ add: function(options) { // delete button var button_delete = new Ui.ButtonIcon({ @@ -101,12 +105,15 @@ } }, - // delete + /** Delete repeat block + */ del: function(id) { if (this.list[id]) { // delete table row var table_row = this.table.get('row_' + id); table_row.remove(); + + // remove from list delete this.list[id]; // enable new button @@ -114,7 +121,8 @@ } }, - // retitle + /** Retitle/Enumerate repeat blocks + */ retitle: function(new_title) { var index = 0; for (var id in this.list) { diff -r f9e429b15b0eacada3a248d14e9b9dcc9be67ed5 -r 5636e8ac71d5955501e333dc6fa4693cc5905c1c static/scripts/mvc/tools/tools-section.js --- a/static/scripts/mvc/tools/tools-section.js +++ b/static/scripts/mvc/tools/tools-section.js @@ -1,4 +1,4 @@ -/* +/** This class creates a tool form section and populates it with input elements. It also handles repeat blocks and conditionals by recursively creating new sub sections. New input elements can be plugged in by adding cases to the switch block defined in the _addRow() function. */ define(['utils/utils', 'mvc/ui/ui-table', 'mvc/ui/ui-misc', 'mvc/tools/tools-repeat', 'mvc/tools/tools-select-dataset'], @@ -11,19 +11,24 @@ this.setElement(this._template(options)); }, - // set error text + /** Set error text + */ error: function(text) { // set text this.$el.find('.ui-table-form-error-text').html(text); this.$el.find('.ui-table-form-error').fadeIn(); + this.$el.addClass('ui-error'); }, - // reset + /** Reset this view + */ reset: function() { this.$el.find('.ui-table-form-error').hide(); + this.$el.removeClass('ui-error'); }, - // template + /** Main Template + */ _template: function(options) { // create table element var $input = $('<div class="ui-table-element"/>'); @@ -73,7 +78,8 @@ this.render(); }, - // update + /** Render section view + */ render: function() { // reset table this.table.delAll(); @@ -84,7 +90,8 @@ } }, - // add table row + /** Add a new input element + */ _add: function(input) { // link this var self = this; @@ -115,7 +122,8 @@ } }, - // add conditional block + /** Add a conditional block + */ _addConditional: function(input_def) { // add label to input definition root input_def.label = input_def.test_param.label; @@ -148,11 +156,15 @@ } }, - // add repeat block + /** Add a repeat block + */ _addRepeat: function(input_def) { // link this var self = this; + // block index + var block_index = 0; + // // create tab field // @@ -161,7 +173,7 @@ max : input_def.max, onnew : function() { // create id tag - var sub_section_id = input_def.id + '-section-' + Utils.uuid(); + var sub_section_id = input_def.id + '-section-' + (block_index++); // create sub section var sub_section = new View(self.app, { @@ -199,7 +211,7 @@ // for (var i = 0; i < input_def.min; i++) { // create id tag - var sub_section_id = input_def.id + '-section-' + Utils.uuid(); + var sub_section_id = input_def.id + '-section-' + (block_index++); // create sub section var sub_section = new View(self.app, { @@ -235,7 +247,8 @@ this.table.append(input_def.id); }, - // add table row + /** Add a single field element + */ _addRow: function(field_type, input_def) { // get id var id = input_def.id; @@ -333,7 +346,8 @@ return this.table.get(id) }, - // conditional input field + /** Conditional input field selector + */ _field_conditional : function(input_def) { // link this var self = this; @@ -385,7 +399,8 @@ }); }, - // data input field + /** Data input field + */ _field_data : function(input_def) { // link this var self = this; @@ -398,16 +413,19 @@ id : 'field-' + id, extensions : input_def.extensions, multiple : input_def.multiple, - onchange : function(value) { + onchange : function(dict) { // pick the first dataset if multiple might be selected - // TODO: iterate over all datasets and filter common/consistent columns - if (value instanceof Array) { - value = value[0]; - } + var value = dict.values[0].id; // get referenced columns var column_list = self.app.tree.references(id, 'data_column'); + // check data column list + if (column_list.length <= 0) { + console.debug('tool-form::field_data() - Data column parameters unavailable.'); + return; + } + // find selected dataset var dataset = self.app.datasets.filter(value); @@ -415,7 +433,7 @@ var meta = null; // check dataset - if (dataset && column_list.length > 0) { + if (dataset) { // log selection console.debug('tool-form::field_data() - Selected dataset ' + value + '.'); @@ -427,7 +445,6 @@ console.debug('tool-form::field_data() - FAILED: Could not find metadata for dataset ' + value + '.'); } } else { - // log failure console.debug('tool-form::field_data() - FAILED: Could not find dataset ' + value + '.'); } @@ -479,7 +496,8 @@ }); }, - // select field + /** Select/Checkbox/Radio options field + */ _field_select : function (input_def) { // configure options fields var options = []; @@ -510,7 +528,8 @@ }); }, - // text input field + /** Text input field + */ _field_text : function(input_def) { return new Ui.Input({ id : 'field-' + input_def.id, @@ -518,7 +537,8 @@ }); }, - // slider field + /** Slider field + */ _field_slider: function(input_def) { // calculate step size var step = 1; @@ -535,14 +555,16 @@ }); }, - // hidden field + /** Hidden field + */ _field_hidden : function(input_def) { return new Ui.Hidden({ id : 'field-' + input_def.id }); }, - // boolean field + /** Boolean field + */ _field_boolean : function(input_def) { return new Ui.RadioButton.View({ id : 'field-' + input_def.id, diff -r f9e429b15b0eacada3a248d14e9b9dcc9be67ed5 -r 5636e8ac71d5955501e333dc6fa4693cc5905c1c static/scripts/mvc/tools/tools-select-dataset.js --- a/static/scripts/mvc/tools/tools-select-dataset.js +++ b/static/scripts/mvc/tools/tools-select-dataset.js @@ -11,13 +11,13 @@ this.setElement('<div/>'); // current selection - this.current = 'dataset'; + this.current = 'hda'; // create button this.button_new = new Ui.RadioButton.View({ value : this.current, - data : [ { icon: 'fa-file-o', label : 'Select datasets', value : 'dataset' }, - { icon: 'fa-files-o', label : 'Select a collection', value : 'collection' }], + data : [ { icon: 'fa-file-o', label : 'Select datasets', value : 'hda' }, + { icon: 'fa-files-o', label : 'Select a collection', value : 'hdca' }], onchange: function(value) { self.current = value; self.refresh(); @@ -94,29 +94,62 @@ }); }, - // value + /** Return the currently selected dataset values */ value : function () { + // identify select element + var select = null; switch(this.current) { - case 'dataset': - return this.select_datasets.value(); - case 'collection': - return this.select_collection.value(); + case 'hda': + select = this.select_datasets; + break; + case 'hdca': + select = this.select_collection; + break; + } + + // transform into an array + var id_list = select.value(); + if (!(id_list instanceof Array)) { + id_list = [id_list]; + } + + // prepare result dict + var result = { + batch : !this.options.multiple, + values : [] + } + + // append to dataset ids + for (var i in id_list) { + result.values.push({ + id : id_list[i], + src : this.current + }); + } + + // return + return result; + }, + + /** Validate current selection + */ + validate: function() { + switch(this.current) { + case 'hda': + return this.select_datasets.validate(); + case 'hdca': + return this.select_collection.validate(); } }, - // render - update: function(options) { - this.select.update(options); - }, - - // refresh + /** Refreshes data selection view */ refresh: function() { switch (this.current) { - case 'dataset': + case 'hda': this.select_datasets.$el.fadeIn(); this.select_collection.$el.hide(); break; - case 'collection': + case 'hdca': this.select_datasets.$el.hide(); this.select_collection.$el.fadeIn(); break; diff -r f9e429b15b0eacada3a248d14e9b9dcc9be67ed5 -r 5636e8ac71d5955501e333dc6fa4693cc5905c1c static/scripts/mvc/tools/tools-tree.js --- a/static/scripts/mvc/tools/tools-tree.js +++ b/static/scripts/mvc/tools/tools-tree.js @@ -67,11 +67,30 @@ switch (input.type) { // handle repeats case 'repeat': + // section identifier + var section_label = 'section-'; + + // collect repeat block identifiers + var block_indices = []; + var block_prefix = null; + for (var block_label in node) { + var pos = block_label.indexOf(section_label); + if (pos != -1) { + pos += section_label.length; + block_indices.push(parseInt(block_label.substr(pos))); + if (!block_prefix) { + block_prefix = block_label.substr(0, pos); + } + } + } + + // sort repeat blocks + block_indices.sort(function(a,b) { return a - b; }); + + // add to response dictionary in created order var index = 0; - for (var i in node) { - if (i.indexOf('section') != -1) { - convert(job_input_id + '_' + index++, node[i]); - } + for (var i in block_indices) { + convert(job_input_id + '_' + index++, node[block_prefix + block_indices[i]]); } break; // handle conditionals @@ -90,32 +109,6 @@ } } break; - // handle data inputs - case 'data': - // create array for dataset ids - var dataset_selection = null; - - // collect dataset ids from input field - var value = self.app.field_list[input.id].value(); - if (typeof value === 'string') { - dataset_selection = { - id : value, - src : 'hda' - }; - } else { - // create array of dataset dictionaries for api submission - dataset_selection = []; - for (var i in value) { - dataset_selection.push({ - id : value[i], - src : 'hda' - }); - } - } - - // add final array to job definition - add(job_input_id, input.id, dataset_selection); - break; // handle boolean input case 'boolean': var value = self.app.field_list[input.id].value(); @@ -136,14 +129,20 @@ // start conversion convert('', this.dict); - console.log(this.job_def); + // return result return this.job_def; }, + /** Match job definition identifier to input element identifier + */ + match: function (job_input_id) { + return this.job_ids && this.job_ids[job_input_id]; + }, + /** Matches identifier from api response to input element */ - match: function(response) { + matchResponse: function(response) { // final result dictionary var result = {}; @@ -263,7 +262,7 @@ var id = $(child).attr('id'); // create new branch - if ($(child).hasClass('section-row') || $(child).hasClass('tab-pane')) { + if ($(child).hasClass('section-row')) { // create sub dictionary dict[id] = {}; diff -r f9e429b15b0eacada3a248d14e9b9dcc9be67ed5 -r 5636e8ac71d5955501e333dc6fa4693cc5905c1c static/scripts/mvc/ui/ui-options.js --- a/static/scripts/mvc/ui/ui-options.js +++ b/static/scripts/mvc/ui/ui-options.js @@ -1,7 +1,7 @@ // dependencies define(['utils/utils'], function(Utils) { -/** base class for options based ui elements **/ +/** Base class for options based ui elements **/ var OptionsBase = Backbone.View.extend({ // initialize initialize: function(options) { @@ -48,7 +48,8 @@ }); }, - // update options + /** Update options + */ update: function(options) { // backup current value var current = this._getValue(); @@ -80,7 +81,8 @@ this.value(current); }, - // check if selected value exists (or any if multiple) + /** Check if selected value exists (or any if multiple) + */ exists: function(value) { if (typeof value === 'string') { value = [value]; @@ -93,7 +95,8 @@ return false; }, - // first + /** Return first available option + */ first: function() { var options = this.$el.find('input'); if (options.length > 0) { @@ -103,14 +106,31 @@ } }, - // change + /** Validate the selected option/options + */ + validate: function() { + var current = this.value(); + if (!(current instanceof Array)) { + current = [current]; + } + for (var i in current) { + if (current[i] === 'null' || !current[i]) { + return false; + } + } + return true; + }, + + /** Trigger custom onchange callback function + */ _change: function() { if (this.options.onchange) { this.options.onchange(this._getValue()); } }, - // refresh + /** Refresh options view + */ _refresh: function() { // count remaining options var remaining = this.$el.find('.ui-option').length; @@ -123,7 +143,8 @@ } }, - // get value + /** Return current selection + */ _getValue: function() { // get selected values var selected = this.$el.find(':checked'); @@ -148,7 +169,7 @@ } }); -/** radio button field **/ +/** Radio button field **/ var Radio = {}; Radio.View = OptionsBase.extend({ // initialize @@ -156,7 +177,8 @@ OptionsBase.prototype.initialize.call(this, options); }, - // value + /** Return/Set current value + */ value: function (new_val) { // check if its an array if (typeof new_val === 'string') { @@ -178,20 +200,22 @@ return this._getValue(); }, - // template for options + /** Template for options + */ _templateOption: function(pair) { return '<div>' + '<input type="radio" name="' + this.options.id + '" value="' + pair.value + '"/>' + pair.label + '<br>' + '</div>'; }, - // template + /** Main template function + */ _template: function() { return '<div class="ui-options"/>'; } }); -/** checkbox options field **/ +/** Checkbox options field **/ var Checkbox = {}; Checkbox.View = Radio.View.extend({ // initialize @@ -200,7 +224,8 @@ Radio.View.prototype.initialize.call(this, options); }, - // template for options + /** Template for options + */ _templateOption: function(pair) { return '<div>' + '<input type="checkbox" name="' + this.options.id + '" value="' + pair.value + '"/>' + pair.label + '<br>' + @@ -208,7 +233,7 @@ } }); -/** radio button options field styled as classic buttons **/ +/** Radio button options field styled as classic buttons **/ var RadioButton = {}; RadioButton.View = OptionsBase.extend({ // initialize @@ -216,7 +241,8 @@ OptionsBase.prototype.initialize.call(this, options); }, - // value + /** Return/Set current value + */ value: function (new_val) { // set new value if (new_val !== undefined) { @@ -229,7 +255,8 @@ return this._getValue(); }, - // template for options + /** Template for options + */ _templateOption: function(pair) { var tmpl = '<label class="btn btn-default">'; if (pair.icon) { @@ -240,7 +267,8 @@ return tmpl; }, - // template + /** Main template function + */ _template: function() { return '<div class="btn-group ui-radiobutton" data-toggle="buttons"/>'; } diff -r f9e429b15b0eacada3a248d14e9b9dcc9be67ed5 -r 5636e8ac71d5955501e333dc6fa4693cc5905c1c static/scripts/mvc/ui/ui-portlet.js --- a/static/scripts/mvc/ui/ui-portlet.js +++ b/static/scripts/mvc/ui/ui-portlet.js @@ -153,7 +153,7 @@ // fill regular modal template _template: function(options) { - var tmpl = '<div class="' + options.cls + '">'; + var tmpl = '<div id="' + options.id + '" class="' + options.cls + '">'; if (options.title) { tmpl += '<div id="portlet-header" class="portlet-header">' + diff -r f9e429b15b0eacada3a248d14e9b9dcc9be67ed5 -r 5636e8ac71d5955501e333dc6fa4693cc5905c1c static/scripts/mvc/ui/ui-select-default.js --- a/static/scripts/mvc/ui/ui-select-default.js +++ b/static/scripts/mvc/ui/ui-select-default.js @@ -63,7 +63,8 @@ }); }, - // value + /** Return/Set current selection + */ value : function (new_value) { if (new_value !== undefined) { this.$select.val(new_value); @@ -71,7 +72,8 @@ return this.$select.val(); }, - // first + /** Return the first select option + */ first: function() { var options = this.$select.find('option'); if (options.length > 0) { @@ -81,12 +83,29 @@ } }, - // label + /** Validate the current selection + */ + validate: function() { + var current = this.value(); + if (!(current instanceof Array)) { + current = [current]; + } + for (var i in current) { + if (current[i] === 'null' || !current[i]) { + return false; + } + } + return true; + }, + + /** Return the label/text of the current selection + */ text : function () { return this.$select.find('option:selected').text(); }, - // show + /** Show the select field + */ show: function() { this.$icon.removeClass(); this.$icon.addClass('fa fa-caret-down'); @@ -94,34 +113,40 @@ this.$el.show(); }, - // hide + /** Hide the select field + */ hide: function() { this.$el.hide(); }, - // wait + /** Show a spinner indicating that the select options are currently loaded + */ wait: function() { this.$icon.removeClass(); this.$icon.addClass('fa fa-spinner fa-spin'); this.$select.hide(); }, - // disabled + /** Returns true if the field is disabled + */ disabled: function() { return this.$select.is(':disabled'); }, - // enable + /** Enable the select field + */ enable: function() { this.$select.prop('disabled', false); }, - // disable + /** Disable the select field + */ disable: function() { this.$select.prop('disabled', true); }, - // add + /** Add a select option + */ add: function(options) { // add options this.$select.append(this._templateOption(options)); @@ -130,7 +155,8 @@ this._refresh(); }, - // remove + /** Delete a select option + */ del: function(value) { // remove option this.$select.find('option[value=' + value + ']').remove(); @@ -140,7 +166,8 @@ this._refresh(); }, - // render + /** Update select options + */ update: function(options) { // backup current value var current = this.$select.val(); @@ -165,24 +192,28 @@ } }, - // set on change event + /** Set the custom onchange callback function + */ setOnChange: function(callback) { this.options.onchange = callback; }, - // check if selected value exists + /** Check if a value is an existing option + */ exists: function(value) { return this.$select.find('option[value="' + value + '"]').length > 0; }, - // change + /** Trigger custom onchange callback + */ _change: function() { if (this.options.onchange) { this.options.onchange(this.$select.val()); } }, - // refresh + /** Refresh the select view + */ _refresh: function() { // remove placeholder this.$select.find('option[value=null]').remove(); @@ -201,12 +232,14 @@ } }, - // template option + /** Template for select options + */ _templateOption: function(options) { return '<option value="' + options.value + '">' + options.label + '</option>'; }, - // template + /** Template for select view + */ _template: function(options) { return '<div id="' + options.id + '">' + '<div class="button">' + diff -r f9e429b15b0eacada3a248d14e9b9dcc9be67ed5 -r 5636e8ac71d5955501e333dc6fa4693cc5905c1c static/scripts/packed/mvc/tools/tools-form.js --- a/static/scripts/packed/mvc/tools/tools-form.js +++ b/static/scripts/packed/mvc/tools/tools-form.js @@ -1,1 +1,1 @@ -define(["mvc/ui/ui-portlet","mvc/ui/ui-misc","mvc/citation/citation-model","mvc/citation/citation-view","mvc/tools","mvc/tools/tools-template","mvc/tools/tools-datasets","mvc/tools/tools-section","mvc/tools/tools-tree","mvc/tools/tools-jobs"],function(h,l,j,a,f,d,i,k,c,g){var e=Backbone.Model.extend({initialize:function(m){this.url=galaxy_config.root+"api/tools/"+m.id+"?io_details=true"}});var b=Backbone.View.extend({main_el:"body",initialize:function(n){var m=this;this.options=n;this.model=new e({id:n.id});this.tree=new c(this);this.job_handler=new g(this);this.field_list={};this.input_list={};this.element_list={};this.datasets=new i({history_id:this.options.history_id,success:function(){m._initializeToolForm()}})},message:function(m){$(this.main_el).empty();$(this.main_el).append(d.message(m))},reset:function(){for(var m in this.element_list){this.element_list[m].reset()}},refresh:function(){this.tree.refresh();for(var m in this.field_list){this.field_list[m].trigger("change")}console.debug("tools-form::refresh() - Recreated tree structure. Refresh.")},_initializeToolForm:function(){var n=this;var o=new l.ButtonIcon({icon:"fa-question-circle",title:"Question?",tooltip:"Ask a question about this tool (Biostar)",onclick:function(){window.open(n.options.biostar_url+"/p/new/post/")}});var p=new l.ButtonIcon({icon:"fa-search",title:"Search",tooltip:"Search help for this tool (Biostar)",onclick:function(){window.open(n.options.biostar_url+"/t/"+n.options.id+"/")}});var m=new l.ButtonIcon({icon:"fa-share",title:"Share",tooltip:"Share this tool",onclick:function(){prompt("Copy to clipboard: Ctrl+C, Enter",galaxy_config.root+"root?tool_id="+n.options.id)}});this.model.fetch({error:function(q){console.debug("tools-form::_initializeToolForm() : Attempt to fetch tool model failed.")},success:function(){n.inputs=n.model.get("inputs");n.portlet=new h.View({icon:"fa-wrench",title:"<b>"+n.model.get("name")+"</b> "+n.model.get("description"),buttons:{execute:new l.ButtonIcon({icon:"fa-check",tooltip:"Execute the tool",title:"Execute",floating:"clear",onclick:function(){n.job_handler.submit()}})},operations:{button_question:o,button_search:p,button_share:m}});if(!n.options.biostar_url){o.$el.hide();p.$el.hide()}$(n.main_el).append(n.portlet.$el);if(n.options.help!=""){$(n.main_el).append(d.help(n.options.help))}if(n.options.citations){$(n.main_el).append(d.citations());var q=new j.ToolCitationCollection();q.tool_id=n.options.id;var r=new a.CitationListView({collection:q});r.render();q.fetch()}n.setElement(n.portlet.content());n.section=new k.View(n,{inputs:n.model.get("inputs"),cls:"ui-table-plain"});n.portlet.append(n.section.$el);n.refresh();n.tree.finalize()}})}});return{View:b}}); \ No newline at end of file +define(["mvc/ui/ui-portlet","mvc/ui/ui-misc","mvc/citation/citation-model","mvc/citation/citation-view","mvc/tools","mvc/tools/tools-template","mvc/tools/tools-datasets","mvc/tools/tools-section","mvc/tools/tools-tree","mvc/tools/tools-jobs"],function(h,l,j,a,f,d,i,k,c,g){var e=Backbone.Model.extend({initialize:function(m){this.url=galaxy_config.root+"api/tools/"+m.id+"?io_details=true"}});var b=Backbone.View.extend({main_el:"body",initialize:function(n){var m=this;this.options=n;this.model=new e({id:n.id});this.tree=new c(this);this.job_handler=new g(this);this.field_list={};this.input_list={};this.element_list={};this.datasets=new i({history_id:this.options.history_id,success:function(){m._initializeToolForm()}})},message:function(m){$(this.main_el).empty();$(this.main_el).append(d.message(m))},reset:function(){for(var m in this.element_list){this.element_list[m].reset()}},refresh:function(){this.tree.refresh();for(var m in this.field_list){this.field_list[m].trigger("change")}console.debug("tools-form::refresh() - Recreated tree structure. Refresh.")},_initializeToolForm:function(){var n=this;var o=new l.ButtonIcon({icon:"fa-question-circle",title:"Question?",tooltip:"Ask a question about this tool (Biostar)",onclick:function(){window.open(n.options.biostar_url+"/p/new/post/")}});var p=new l.ButtonIcon({icon:"fa-search",title:"Search",tooltip:"Search help for this tool (Biostar)",onclick:function(){window.open(n.options.biostar_url+"/t/"+n.options.id+"/")}});var m=new l.ButtonIcon({icon:"fa-share",title:"Share",tooltip:"Share this tool",onclick:function(){prompt("Copy to clipboard: Ctrl+C, Enter",galaxy_config.root+"root?tool_id="+n.options.id)}});this.model.fetch({error:function(q){console.debug("tools-form::_initializeToolForm() : Attempt to fetch tool model failed.")},success:function(){n.inputs=n.model.get("inputs");n.portlet=new h.View({icon:"fa-wrench",title:"<b>"+n.model.get("name")+"</b> "+n.model.get("description"),buttons:{execute:new l.ButtonIcon({icon:"fa-check",tooltip:"Execute the tool",title:"Execute",floating:"clear",onclick:function(){n.job_handler.submit()}})},operations:{button_question:o,button_search:p,button_share:m}});if(!n.options.biostar_url){o.$el.hide();p.$el.hide()}$(n.main_el).append(n.portlet.$el);if(n.options.help!=""){$(n.main_el).append(d.help(n.options.help))}if(n.options.citations){$(n.main_el).append(d.citations());var q=new j.ToolCitationCollection();q.tool_id=n.options.id;var r=new a.CitationListView({collection:q});r.render();q.fetch()}n.setElement(n.portlet.content());n.section=new k.View(n,{inputs:n.model.get("inputs"),cls:"ui-table-plain"});n.portlet.append(n.section.$el);n.refresh()}})}});return{View:b}}); \ No newline at end of file diff -r f9e429b15b0eacada3a248d14e9b9dcc9be67ed5 -r 5636e8ac71d5955501e333dc6fa4693cc5905c1c static/scripts/packed/mvc/tools/tools-jobs.js --- a/static/scripts/packed/mvc/tools/tools-jobs.js +++ b/static/scripts/packed/mvc/tools/tools-jobs.js @@ -1,1 +1,1 @@ -define(["utils/utils"],function(a){return Backbone.Model.extend({initialize:function(c,b){this.app=c;this.options=a.merge(b,this.optionsDefault)},submit:function(){var b=this;var c={tool_id:this.app.options.id,inputs:this.app.tree.finalize()};this.app.reset();a.request("POST",galaxy_config.root+"api/tools",c,function(d){if(!d.outputs||d.outputs.length==0){console.debug(d)}b.app.message({text:"A job has been successfully added to the queue. You can check the status of queued jobs and view the resulting data by refreshing the History pane. When the job has been run the status will change from 'running' to 'finished' if completed successfully or 'error' if problems were encountered."});b._refreshHdas()},function(d){console.debug(d);if(d&&d.message&&d.message.data){var g=b.app.tree.match(d.message.data);for(var f in g){var e=g[f];if(!e){e="Please verify this parameter."}b.app.element_list[f].error(e)}}})},_refreshHdas:function(){if(parent.Galaxy&&parent.Galaxy.currHistoryPanel){parent.Galaxy.currHistoryPanel.refreshContents()}}})}); \ No newline at end of file +define(["utils/utils"],function(a){return Backbone.Model.extend({initialize:function(c,b){this.app=c;this.options=a.merge(b,this.optionsDefault)},submit:function(){var b=this;var c={tool_id:this.app.options.id,inputs:this.app.tree.finalize()};this.app.reset();if(!this._validation(c)){console.debug("tools-jobs::submit - Submission canceled. Validation failed.");return}a.request("POST",galaxy_config.root+"api/tools",c,function(d){if(!d.outputs||d.outputs.length==0){console.debug(d)}b.app.message({text:"A job has been successfully added to the queue. You can check the status of queued jobs and view the resulting data by refreshing the History pane. When the job has been run the status will change from 'running' to 'finished' if completed successfully or 'error' if problems were encountered."});b._refreshHdas()},function(d){console.debug(d);if(d&&d.message&&d.message.data){var g=b.app.tree.matchResponse(d.message.data);for(var f in g){var e=g[f];if(!e){e="Please verify this parameter."}b.app.element_list[f].error(e)}}})},_validation:function(g){var d=g.inputs;var f=true;for(var h in d){var c=d[h];var e=this.app.tree.match(h);var b=this.app.field_list[e];this.app.element_list[e].error("Please verify this parameter.");f=false}return false},_refreshHdas:function(){if(parent.Galaxy&&parent.Galaxy.currHistoryPanel){parent.Galaxy.currHistoryPanel.refreshContents()}}})}); \ No newline at end of file This diff is so big that we needed to truncate the remainder. 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.