commit/galaxy-central: guerler: ToolForm: Improve form update and job submission
1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/17933aef1d35/ Changeset: 17933aef1d35 User: guerler Date: 2014-12-16 16:45:40+00:00 Summary: ToolForm: Improve form update and job submission Affected #: 15 files diff -r bd380f15c1b3b8a8b81d2759eaacd30e94c58d68 -r 17933aef1d3527d22211ff7bf0e47bbbac66c4ac 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 @@ -17,9 +17,6 @@ // log options console.debug(options); - // link this - var self = this; - // link galaxy modal or create one var galaxy = parent.Galaxy; if (galaxy && galaxy.modal) { @@ -52,38 +49,35 @@ this._buildForm(); }, - // reciept shows the final message usually upon successful job submission + /** Shows the final message (usually upon successful job submission) + */ reciept: function($el) { $(this.container).empty(); $(this.container).append($el); }, - - // reset form - reset: function() { - for (var i in this.element_list) { - this.element_list[i].reset(); + + /** Highlight and scroll to input element (currently only used for error notifications) + */ + highlight: function (input_id, message, silent) { + // get input field + var input_element = this.element_list[input_id]; + + // check input element + if (input_element) { + // mark error + input_element.error(message || 'Please verify this parameter.'); + + // scroll to first input element + if (!silent) { + $(this.container).animate({ + scrollTop: input_element.$el.offset().top - 20 + }, 500); + } } }, - // rebuild underlying data structure representation for the tool form - // this happens i.e. when repeat blocks are added or removed and on initialization - rebuild: function() { - this.tree.refresh(); - console.debug('tools-form::rebuild() - Rebuilding data structures.'); - }, - - // refreshes input states i.e. for dynamic parameters - refresh: function() { - // only refresh the state if the form contains dynamic parameters - // by using/reseting the deferred ajax queue the number of redundant calls is reduced - if (this.is_dynamic) { - var self = this; - this.deferred.reset(); - this.deferred.execute(function(){self._updateModel()}); - }; - }, - - // build tool model through api call + /** Builds a new model through api call and recreates the entire form + */ _buildModel: function() { // link this var self = this; @@ -156,7 +150,8 @@ }); }, - // request a new model and update the form inputs + /** Request a new model for an already created tool form and updates the form inputs + */ _updateModel: function() { // create the request dictionary var self = this; @@ -202,9 +197,39 @@ type : 'GET', url : model_url, data : current_state, - success : function(response) { - // rebuild form - self._updateForm(response); + success : function(new_model) { + // update form + self.tree.matchModel(new_model, function(input_id, node) { + var input = self.input_list[input_id]; + if (input && input.options) { + if (!_.isEqual(input.options, node.options)) { + // backup new options + input.options = node.options; + + // get/update field + var field = self.field_list[input_id]; + if (field.update) { + var new_options = []; + if ((['data', 'data_collection', 'drill_down']).indexOf(input.type) != -1) { + new_options = input.options; + } else { + for (var i in node.options) { + var opt = node.options[i]; + if (opt.length > 2) { + new_options.push({ + 'label': opt[0], + 'value': opt[1] + }); + } + } + } + field.update(new_options); + field.trigger('change'); + console.debug('Updating options for ' + input_id); + } + } + } + }); // unset wait mode wait(false); @@ -214,7 +239,7 @@ // log success console.debug('tools-form::_refreshForm() - States refreshed.'); - console.debug(response); + console.debug(new_model); }, error : function(response) { // process completed @@ -227,47 +252,16 @@ }); }, - // update form inputs - _updateForm: function(new_model) { - var self = this; - this.tree.matchModel(new_model, function(input_id, node) { - var input = self.input_list[input_id]; - if (input && input.options) { - if (!_.isEqual(input.options, node.options)) { - // backup new options - input.options = node.options; - - // get/update field - var field = self.field_list[input_id]; - if (field.update) { - var new_options = []; - if ((['data', 'data_collection', 'drill_down']).indexOf(input.type) != -1) { - new_options = input.options; - } else { - for (var i in node.options) { - var opt = node.options[i]; - if (opt.length > 2) { - new_options.push({ - 'label': opt[0], - 'value': opt[1] - }); - } - } - } - field.update(new_options); - field.trigger('change'); - console.debug('Updating options for ' + input_id); - } - } - } - }); - }, - - // builds the tool form + /** Main tool form build function. This function is called once a new model is available. + */ _buildForm: function() { // link this var self = this; + // reset events + this.off('refresh'); + this.off('reset'); + // reset field list, which contains the input field elements this.field_list = {}; @@ -289,6 +283,41 @@ // link model options var options = this.options; + // create ui elements + this._renderForm(options); + + // rebuild the underlying data structure + this.tree.finalize(); + + // show errors + if (options.errors) { + var error_messages = this.tree.matchResponse(options.errors); + for (var input_id in error_messages) { + this.highlight(input_id, error_messages[input_id], true); + } + } + + // add refresh listener + this.on('refresh', function() { + // by using/reseting the deferred ajax queue the number of redundant calls is reduced + self.deferred.reset(); + self.deferred.execute(function(){self._updateModel()}); + }); + + // add reset listener + this.on('reset', function() { + for (var i in this.element_list) { + this.element_list[i].reset(); + } + }); + }, + + /** Renders the UI elements required for the form + */ + _renderForm: function(options) { + // link this + var self = this; + // create message view this.message = new Ui.Message(); @@ -454,6 +483,12 @@ } }); + // append message + this.portlet.append(this.message.$el, true); + + // append tool section + this.portlet.append(this.section.$el); + // start form this.$el.empty(); this.$el.append(this.portlet.$el); @@ -474,15 +509,6 @@ this.$el.append($citations); } - // append message - this.portlet.append(this.message.$el, true); - - // append tool section - this.portlet.append(this.section.$el); - - // rebuild the underlying data structure - this.rebuild(); - // show message if available in model if (options.message) { this.message.update({ @@ -491,38 +517,6 @@ message : options.message }); } - - // show errors - this._showErrors(options); - }, - - /** Highlight all errors - */ - _showErrors: function(options) { - if (options.errors) { - this.tree.finalize(); - var error_messages = this.tree.matchResponse(options.errors); - for (var input_id in error_messages) { - this.foundError(input_id, error_messages[input_id], true); - } - } - }, - - /** Highlight and scroll to error - */ - foundError: function (input_id, message, silent) { - // get input field - var input_element = this.element_list[input_id]; - - // mark error - input_element.error(message || 'Please verify this parameter.'); - - // scroll to first input element - if (!silent) { - $(this.container).animate({ - scrollTop: input_element.$el.offset().top - 20 - }, 500); - } } }); diff -r bd380f15c1b3b8a8b81d2759eaacd30e94c58d68 -r 17933aef1d3527d22211ff7bf0e47bbbac66c4ac client/galaxy/scripts/mvc/tools/tools-input.js --- a/client/galaxy/scripts/mvc/tools/tools-input.js +++ b/client/galaxy/scripts/mvc/tools/tools-input.js @@ -63,7 +63,7 @@ if (!this.field.skip) { this.$field.fadeIn('fast'); this.$title_optional.html('Disable'); - this.app.refresh(); + this.app.trigger('refresh'); } else { this.$field.hide(); this.$title_optional.html('Enable'); diff -r bd380f15c1b3b8a8b81d2759eaacd30e94c58d68 -r 17933aef1d3527d22211ff7bf0e47bbbac66c4ac 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 @@ -22,7 +22,7 @@ } // reset - this.app.reset(); + this.app.trigger('reset'); // validate job definition if (!this._validation(job_def)) { @@ -51,7 +51,7 @@ if (response && response.message && response.message.data) { var error_messages = self.app.tree.matchResponse(response.message.data); for (var input_id in error_messages) { - self.app.foundError(input_id, error_messages[input_id]); + self.app.highlight(input_id, error_messages[input_id]); break; } } else { @@ -99,7 +99,7 @@ // validate non-optional fields if (!input_def.optional && input_field.validate && !input_field.validate()) { - this.app.foundError(input_id); + this.app.highlight(input_id); return false; } @@ -120,7 +120,7 @@ batch_src = src; } else { if (batch_src !== src) { - this.app.foundError(input_id, 'Please select either dataset or dataset list fields for all batch mode fields.'); + this.app.highlight(input_id, 'Please select either dataset or dataset list fields for all batch mode fields.'); return false; } } @@ -131,7 +131,7 @@ batch_n = n; } else { if (batch_n !== n) { - this.app.foundError(input_id, 'Please make sure that you select the same number of inputs for all batch mode fields. This field contains <b>' + n + '</b> selection(s) while a previous field contains <b>' + batch_n + '</b>.'); + this.app.highlight(input_id, 'Please make sure that you select the same number of inputs for all batch mode fields. This field contains <b>' + n + '</b> selection(s) while a previous field contains <b>' + batch_n + '</b>.'); return false; } } diff -r bd380f15c1b3b8a8b81d2759eaacd30e94c58d68 -r 17933aef1d3527d22211ff7bf0e47bbbac66c4ac 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 @@ -119,7 +119,7 @@ } // refresh form inputs - self.app.refresh(); + self.app.trigger('refresh'); }; // add conditional sub sections @@ -172,8 +172,7 @@ repeat.retitle(input_def.title); // trigger refresh - self.app.rebuild(); - self.app.refresh(); + self.app.trigger('refresh'); } } @@ -206,8 +205,7 @@ create(input_def.inputs, true); // trigger refresh - self.app.rebuild(); - self.app.refresh(); + self.app.trigger('refresh'); } }); @@ -255,11 +253,6 @@ // create input field var field = this._createField(input_def); - // flagging this form as dynamic will trigger api-driven refresh events - if (input_def.is_dynamic) { - this.app.is_dynamic = true; - } - // add to field list this.app.field_list[id] = field; @@ -392,7 +385,7 @@ type : input_def.type, data : input_def.options, onchange : function() { - self.app.refresh(); + self.app.trigger('refresh'); } }); }, @@ -430,7 +423,7 @@ multiple : input_def.multiple, searchable : input_def.searchable, onchange : function() { - self.app.refresh(); + self.app.trigger('refresh'); } }); }, @@ -444,7 +437,7 @@ data : input_def.options, display : input_def.display, onchange : function() { - self.app.refresh(); + self.app.trigger('refresh'); } }); }, @@ -457,7 +450,7 @@ id : 'field-' + input_def.id, area : input_def.area, onchange: function() { - self.app.refresh(); + self.app.trigger('refresh'); } }); }, diff -r bd380f15c1b3b8a8b81d2759eaacd30e94c58d68 -r 17933aef1d3527d22211ff7bf0e47bbbac66c4ac 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 @@ -1,5 +1,5 @@ /* - This class maps the tool form to javascript datastructures. Once refreshed it converts the tool form (including sub sections) into a xml (containing only ids) and a detailed dictionary representation. The xml object is a jquery element and can be searched/filtered e.g. in order to hierarchically identify referenced fields. Once the job is ready for submission, the finalize function will transform the generic dictionary representation into the specific flat dictionary format required by the tools api. + This class maps the tool form dom to an api compatible javascript dictionary. */ // dependencies define([], function() { @@ -11,43 +11,39 @@ this.app = app; }, - /** Refresh the datastructures representing the ToolForm. + /** Convert dictionary representation into tool api specific flat dictionary format. */ - refresh: function() { - // create dictionary - this.dict = {}; + finalize: function(patch) { + // link this + var self = this; - // create xml object - this.xml = $('<div/>'); - + // dictionary with api specific identifiers + this.map_dict = {}; + // check if section is available if (!this.app.section) { return {}; } - // fill dictionary - this._iterate(this.app.section.$el, this.dict, this.xml); - }, - - /** Convert dictionary representation into tool api specific flat dictionary format. - */ - finalize: function(patch) { - // initialize + // ensure that dictionary with patching functions exists patch = patch || {}; - // link this - var self = this; + // dictionary formatted for job submission or tool form update + var result_dict = {}; + + // prepare full dictionary + var dict = {}; - // dictionary formatted for job submission - this.job_def = {}; - - // dictionary with api specific identifiers - this.job_ids = {}; - + // fill dictionary from dom + this._iterate(this.app.section.$el, dict); + // add identifier and value to job definition function add(job_input_id, input_id, input_value) { - self.job_def[job_input_id] = input_value; - self.job_ids[job_input_id] = input_id; + // add entry to result dictionary + result_dict[job_input_id] = input_value; + + // backup id mapping + self.map_dict[job_input_id] = input_id; }; // converter between raw dictionary and job dictionary @@ -135,16 +131,16 @@ } // start conversion - convert('', this.dict); + convert('', dict); // return result - return this.job_def; + return result_dict; }, /** Match job definition identifier to input element identifier */ match: function (job_input_id) { - return this.job_ids && this.job_ids[job_input_id]; + return this.map_dict && this.map_dict[job_input_id]; }, /** Match conditional values to selected cases @@ -201,7 +197,7 @@ } break; default: - var input_id = self.job_ids[index]; + var input_id = self.map_dict[index]; if (input_id) { callback(input_id, node); } @@ -228,7 +224,7 @@ // search throughout response function search (id, head) { if (typeof head === 'string') { - var input_id = self.job_ids[id]; + var input_id = self.map_dict[id]; if (input_id) { result[input_id] = head; } @@ -254,83 +250,9 @@ return result; }, - /** Find referenced elements. + /** Iterate through the tool form dom and map it to the dictionary. */ - references: function(identifier, type) { - // referenced elements - var referenced = []; - - // link this - var self = this; - - // iterate - function search (name, parent) { - // get child nodes - var children = $(parent).children(); - - // create list of referenced elements - var list = []; - - // a node level is skipped if a reference of higher priority was found - var skip = false; - - // verify that hierarchy level is referenced by target identifier - children.each(function() { - // get child element - var child = this; - - // get id - var id = $(child).attr('id'); - - // skip target element - if (id !== identifier) { - // get input element - var input = self.app.input_list[id]; - if (input) { - // check for new reference definition with higher priority - if (input.name == name) { - // skip iteration for this branch - skip = true; - return false; - } - - // check for referenced element - if (input.data_ref == name && input.type == type) { - list.push(id); - } - } - } - }); - - // skip iteration - if (!skip) { - // merge temporary list with result - referenced = referenced.concat(list); - - // continue iteration - children.each(function() { - search(name, this); - }); - } - } - - // get initial node - var node = this.xml.find('#' + identifier); - if (node.length > 0) { - // get parent input element - var input = this.app.input_list[identifier]; - if (input) { - search(input.name, node.parent()); - } - } - - // return - return referenced; - }, - - /** Iterate through the tool form dom and map it to the dictionary and xml representation. - */ - _iterate: function(parent, dict, xml) { + _iterate: function(parent, dict) { // get child nodes var self = this; var children = $(parent).children(); @@ -354,16 +276,10 @@ } } - // create xml element - var $el = $('<div id="' + id + '"/>'); - - // append xml - xml.append($el); - // fill sub dictionary - self._iterate(child, dict[id], $el); + self._iterate(child, dict[id]); } else { - self._iterate(child, dict, xml); + self._iterate(child, dict); } }); } diff -r bd380f15c1b3b8a8b81d2759eaacd30e94c58d68 -r 17933aef1d3527d22211ff7bf0e47bbbac66c4ac static/scripts/mvc/tools/tools-form.js --- a/static/scripts/mvc/tools/tools-form.js +++ b/static/scripts/mvc/tools/tools-form.js @@ -17,9 +17,6 @@ // log options console.debug(options); - // link this - var self = this; - // link galaxy modal or create one var galaxy = parent.Galaxy; if (galaxy && galaxy.modal) { @@ -52,38 +49,35 @@ this._buildForm(); }, - // reciept shows the final message usually upon successful job submission + /** Shows the final message (usually upon successful job submission) + */ reciept: function($el) { $(this.container).empty(); $(this.container).append($el); }, - - // reset form - reset: function() { - for (var i in this.element_list) { - this.element_list[i].reset(); + + /** Highlight and scroll to input element (currently only used for error notifications) + */ + highlight: function (input_id, message, silent) { + // get input field + var input_element = this.element_list[input_id]; + + // check input element + if (input_element) { + // mark error + input_element.error(message || 'Please verify this parameter.'); + + // scroll to first input element + if (!silent) { + $(this.container).animate({ + scrollTop: input_element.$el.offset().top - 20 + }, 500); + } } }, - // rebuild underlying data structure representation for the tool form - // this happens i.e. when repeat blocks are added or removed and on initialization - rebuild: function() { - this.tree.refresh(); - console.debug('tools-form::rebuild() - Rebuilding data structures.'); - }, - - // refreshes input states i.e. for dynamic parameters - refresh: function() { - // only refresh the state if the form contains dynamic parameters - // by using/reseting the deferred ajax queue the number of redundant calls is reduced - if (this.is_dynamic) { - var self = this; - this.deferred.reset(); - this.deferred.execute(function(){self._updateModel()}); - }; - }, - - // build tool model through api call + /** Builds a new model through api call and recreates the entire form + */ _buildModel: function() { // link this var self = this; @@ -156,7 +150,8 @@ }); }, - // request a new model and update the form inputs + /** Request a new model for an already created tool form and updates the form inputs + */ _updateModel: function() { // create the request dictionary var self = this; @@ -202,9 +197,39 @@ type : 'GET', url : model_url, data : current_state, - success : function(response) { - // rebuild form - self._updateForm(response); + success : function(new_model) { + // update form + self.tree.matchModel(new_model, function(input_id, node) { + var input = self.input_list[input_id]; + if (input && input.options) { + if (!_.isEqual(input.options, node.options)) { + // backup new options + input.options = node.options; + + // get/update field + var field = self.field_list[input_id]; + if (field.update) { + var new_options = []; + if ((['data', 'data_collection', 'drill_down']).indexOf(input.type) != -1) { + new_options = input.options; + } else { + for (var i in node.options) { + var opt = node.options[i]; + if (opt.length > 2) { + new_options.push({ + 'label': opt[0], + 'value': opt[1] + }); + } + } + } + field.update(new_options); + field.trigger('change'); + console.debug('Updating options for ' + input_id); + } + } + } + }); // unset wait mode wait(false); @@ -214,7 +239,7 @@ // log success console.debug('tools-form::_refreshForm() - States refreshed.'); - console.debug(response); + console.debug(new_model); }, error : function(response) { // process completed @@ -227,47 +252,16 @@ }); }, - // update form inputs - _updateForm: function(new_model) { - var self = this; - this.tree.matchModel(new_model, function(input_id, node) { - var input = self.input_list[input_id]; - if (input && input.options) { - if (!_.isEqual(input.options, node.options)) { - // backup new options - input.options = node.options; - - // get/update field - var field = self.field_list[input_id]; - if (field.update) { - var new_options = []; - if ((['data', 'data_collection', 'drill_down']).indexOf(input.type) != -1) { - new_options = input.options; - } else { - for (var i in node.options) { - var opt = node.options[i]; - if (opt.length > 2) { - new_options.push({ - 'label': opt[0], - 'value': opt[1] - }); - } - } - } - field.update(new_options); - field.trigger('change'); - console.debug('Updating options for ' + input_id); - } - } - } - }); - }, - - // builds the tool form + /** Main tool form build function. This function is called once a new model is available. + */ _buildForm: function() { // link this var self = this; + // reset events + this.off('refresh'); + this.off('reset'); + // reset field list, which contains the input field elements this.field_list = {}; @@ -289,6 +283,41 @@ // link model options var options = this.options; + // create ui elements + this._renderForm(options); + + // rebuild the underlying data structure + this.tree.finalize(); + + // show errors + if (options.errors) { + var error_messages = this.tree.matchResponse(options.errors); + for (var input_id in error_messages) { + this.highlight(input_id, error_messages[input_id], true); + } + } + + // add refresh listener + this.on('refresh', function() { + // by using/reseting the deferred ajax queue the number of redundant calls is reduced + self.deferred.reset(); + self.deferred.execute(function(){self._updateModel()}); + }); + + // add reset listener + this.on('reset', function() { + for (var i in this.element_list) { + this.element_list[i].reset(); + } + }); + }, + + /** Renders the UI elements required for the form + */ + _renderForm: function(options) { + // link this + var self = this; + // create message view this.message = new Ui.Message(); @@ -454,6 +483,12 @@ } }); + // append message + this.portlet.append(this.message.$el, true); + + // append tool section + this.portlet.append(this.section.$el); + // start form this.$el.empty(); this.$el.append(this.portlet.$el); @@ -474,15 +509,6 @@ this.$el.append($citations); } - // append message - this.portlet.append(this.message.$el, true); - - // append tool section - this.portlet.append(this.section.$el); - - // rebuild the underlying data structure - this.rebuild(); - // show message if available in model if (options.message) { this.message.update({ @@ -491,38 +517,6 @@ message : options.message }); } - - // show errors - this._showErrors(options); - }, - - /** Highlight all errors - */ - _showErrors: function(options) { - if (options.errors) { - this.tree.finalize(); - var error_messages = this.tree.matchResponse(options.errors); - for (var input_id in error_messages) { - this.foundError(input_id, error_messages[input_id], true); - } - } - }, - - /** Highlight and scroll to error - */ - foundError: function (input_id, message, silent) { - // get input field - var input_element = this.element_list[input_id]; - - // mark error - input_element.error(message || 'Please verify this parameter.'); - - // scroll to first input element - if (!silent) { - $(this.container).animate({ - scrollTop: input_element.$el.offset().top - 20 - }, 500); - } } }); diff -r bd380f15c1b3b8a8b81d2759eaacd30e94c58d68 -r 17933aef1d3527d22211ff7bf0e47bbbac66c4ac static/scripts/mvc/tools/tools-input.js --- a/static/scripts/mvc/tools/tools-input.js +++ b/static/scripts/mvc/tools/tools-input.js @@ -63,7 +63,7 @@ if (!this.field.skip) { this.$field.fadeIn('fast'); this.$title_optional.html('Disable'); - this.app.refresh(); + this.app.trigger('refresh'); } else { this.$field.hide(); this.$title_optional.html('Enable'); diff -r bd380f15c1b3b8a8b81d2759eaacd30e94c58d68 -r 17933aef1d3527d22211ff7bf0e47bbbac66c4ac static/scripts/mvc/tools/tools-jobs.js --- a/static/scripts/mvc/tools/tools-jobs.js +++ b/static/scripts/mvc/tools/tools-jobs.js @@ -22,7 +22,7 @@ } // reset - this.app.reset(); + this.app.trigger('reset'); // validate job definition if (!this._validation(job_def)) { @@ -51,7 +51,7 @@ if (response && response.message && response.message.data) { var error_messages = self.app.tree.matchResponse(response.message.data); for (var input_id in error_messages) { - self.app.foundError(input_id, error_messages[input_id]); + self.app.highlight(input_id, error_messages[input_id]); break; } } else { @@ -99,7 +99,7 @@ // validate non-optional fields if (!input_def.optional && input_field.validate && !input_field.validate()) { - this.app.foundError(input_id); + this.app.highlight(input_id); return false; } @@ -120,7 +120,7 @@ batch_src = src; } else { if (batch_src !== src) { - this.app.foundError(input_id, 'Please select either dataset or dataset list fields for all batch mode fields.'); + this.app.highlight(input_id, 'Please select either dataset or dataset list fields for all batch mode fields.'); return false; } } @@ -131,7 +131,7 @@ batch_n = n; } else { if (batch_n !== n) { - this.app.foundError(input_id, 'Please make sure that you select the same number of inputs for all batch mode fields. This field contains <b>' + n + '</b> selection(s) while a previous field contains <b>' + batch_n + '</b>.'); + this.app.highlight(input_id, 'Please make sure that you select the same number of inputs for all batch mode fields. This field contains <b>' + n + '</b> selection(s) while a previous field contains <b>' + batch_n + '</b>.'); return false; } } diff -r bd380f15c1b3b8a8b81d2759eaacd30e94c58d68 -r 17933aef1d3527d22211ff7bf0e47bbbac66c4ac static/scripts/mvc/tools/tools-section.js --- a/static/scripts/mvc/tools/tools-section.js +++ b/static/scripts/mvc/tools/tools-section.js @@ -119,7 +119,7 @@ } // refresh form inputs - self.app.refresh(); + self.app.trigger('refresh'); }; // add conditional sub sections @@ -172,8 +172,7 @@ repeat.retitle(input_def.title); // trigger refresh - self.app.rebuild(); - self.app.refresh(); + self.app.trigger('refresh'); } } @@ -206,8 +205,7 @@ create(input_def.inputs, true); // trigger refresh - self.app.rebuild(); - self.app.refresh(); + self.app.trigger('refresh'); } }); @@ -255,11 +253,6 @@ // create input field var field = this._createField(input_def); - // flagging this form as dynamic will trigger api-driven refresh events - if (input_def.is_dynamic) { - this.app.is_dynamic = true; - } - // add to field list this.app.field_list[id] = field; @@ -392,7 +385,7 @@ type : input_def.type, data : input_def.options, onchange : function() { - self.app.refresh(); + self.app.trigger('refresh'); } }); }, @@ -430,7 +423,7 @@ multiple : input_def.multiple, searchable : input_def.searchable, onchange : function() { - self.app.refresh(); + self.app.trigger('refresh'); } }); }, @@ -444,7 +437,7 @@ data : input_def.options, display : input_def.display, onchange : function() { - self.app.refresh(); + self.app.trigger('refresh'); } }); }, @@ -457,7 +450,7 @@ id : 'field-' + input_def.id, area : input_def.area, onchange: function() { - self.app.refresh(); + self.app.trigger('refresh'); } }); }, diff -r bd380f15c1b3b8a8b81d2759eaacd30e94c58d68 -r 17933aef1d3527d22211ff7bf0e47bbbac66c4ac static/scripts/mvc/tools/tools-tree.js --- a/static/scripts/mvc/tools/tools-tree.js +++ b/static/scripts/mvc/tools/tools-tree.js @@ -1,5 +1,5 @@ /* - This class maps the tool form to javascript datastructures. Once refreshed it converts the tool form (including sub sections) into a xml (containing only ids) and a detailed dictionary representation. The xml object is a jquery element and can be searched/filtered e.g. in order to hierarchically identify referenced fields. Once the job is ready for submission, the finalize function will transform the generic dictionary representation into the specific flat dictionary format required by the tools api. + This class maps the tool form dom to an api compatible javascript dictionary. */ // dependencies define([], function() { @@ -11,43 +11,39 @@ this.app = app; }, - /** Refresh the datastructures representing the ToolForm. + /** Convert dictionary representation into tool api specific flat dictionary format. */ - refresh: function() { - // create dictionary - this.dict = {}; + finalize: function(patch) { + // link this + var self = this; - // create xml object - this.xml = $('<div/>'); - + // dictionary with api specific identifiers + this.map_dict = {}; + // check if section is available if (!this.app.section) { return {}; } - // fill dictionary - this._iterate(this.app.section.$el, this.dict, this.xml); - }, - - /** Convert dictionary representation into tool api specific flat dictionary format. - */ - finalize: function(patch) { - // initialize + // ensure that dictionary with patching functions exists patch = patch || {}; - // link this - var self = this; + // dictionary formatted for job submission or tool form update + var result_dict = {}; + + // prepare full dictionary + var dict = {}; - // dictionary formatted for job submission - this.job_def = {}; - - // dictionary with api specific identifiers - this.job_ids = {}; - + // fill dictionary from dom + this._iterate(this.app.section.$el, dict); + // add identifier and value to job definition function add(job_input_id, input_id, input_value) { - self.job_def[job_input_id] = input_value; - self.job_ids[job_input_id] = input_id; + // add entry to result dictionary + result_dict[job_input_id] = input_value; + + // backup id mapping + self.map_dict[job_input_id] = input_id; }; // converter between raw dictionary and job dictionary @@ -135,16 +131,16 @@ } // start conversion - convert('', this.dict); + convert('', dict); // return result - return this.job_def; + return result_dict; }, /** Match job definition identifier to input element identifier */ match: function (job_input_id) { - return this.job_ids && this.job_ids[job_input_id]; + return this.map_dict && this.map_dict[job_input_id]; }, /** Match conditional values to selected cases @@ -201,7 +197,7 @@ } break; default: - var input_id = self.job_ids[index]; + var input_id = self.map_dict[index]; if (input_id) { callback(input_id, node); } @@ -228,7 +224,7 @@ // search throughout response function search (id, head) { if (typeof head === 'string') { - var input_id = self.job_ids[id]; + var input_id = self.map_dict[id]; if (input_id) { result[input_id] = head; } @@ -254,83 +250,9 @@ return result; }, - /** Find referenced elements. + /** Iterate through the tool form dom and map it to the dictionary. */ - references: function(identifier, type) { - // referenced elements - var referenced = []; - - // link this - var self = this; - - // iterate - function search (name, parent) { - // get child nodes - var children = $(parent).children(); - - // create list of referenced elements - var list = []; - - // a node level is skipped if a reference of higher priority was found - var skip = false; - - // verify that hierarchy level is referenced by target identifier - children.each(function() { - // get child element - var child = this; - - // get id - var id = $(child).attr('id'); - - // skip target element - if (id !== identifier) { - // get input element - var input = self.app.input_list[id]; - if (input) { - // check for new reference definition with higher priority - if (input.name == name) { - // skip iteration for this branch - skip = true; - return false; - } - - // check for referenced element - if (input.data_ref == name && input.type == type) { - list.push(id); - } - } - } - }); - - // skip iteration - if (!skip) { - // merge temporary list with result - referenced = referenced.concat(list); - - // continue iteration - children.each(function() { - search(name, this); - }); - } - } - - // get initial node - var node = this.xml.find('#' + identifier); - if (node.length > 0) { - // get parent input element - var input = this.app.input_list[identifier]; - if (input) { - search(input.name, node.parent()); - } - } - - // return - return referenced; - }, - - /** Iterate through the tool form dom and map it to the dictionary and xml representation. - */ - _iterate: function(parent, dict, xml) { + _iterate: function(parent, dict) { // get child nodes var self = this; var children = $(parent).children(); @@ -354,16 +276,10 @@ } } - // create xml element - var $el = $('<div id="' + id + '"/>'); - - // append xml - xml.append($el); - // fill sub dictionary - self._iterate(child, dict[id], $el); + self._iterate(child, dict[id]); } else { - self._iterate(child, dict, xml); + self._iterate(child, dict); } }); } diff -r bd380f15c1b3b8a8b81d2759eaacd30e94c58d68 -r 17933aef1d3527d22211ff7bf0e47bbbac66c4ac 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(["utils/utils","utils/deferred","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-content","mvc/tools/tools-section","mvc/tools/tools-tree","mvc/tools/tools-jobs"],function(i,j,h,m,k,a,e,d,f,l,c,g){var b=Backbone.View.extend({container:"body",initialize:function(o){console.debug(o);var n=this;var p=parent.Galaxy;if(p&&p.modal){this.modal=p.modal}else{this.modal=new m.Modal.View()}if(p&&p.currUser){this.is_admin=p.currUser.get("is_admin")}else{this.is_admin=false}this.options=o;this.deferred=new j();this.setElement("<div/>");$(this.container).append(this.$el);this._buildForm()},reciept:function(n){$(this.container).empty();$(this.container).append(n)},reset:function(){for(var n in this.element_list){this.element_list[n].reset()}},rebuild:function(){this.tree.refresh();console.debug("tools-form::rebuild() - Rebuilding data structures.")},refresh:function(){if(this.is_dynamic){var n=this;this.deferred.reset();this.deferred.execute(function(){n._updateModel()})}},_buildModel:function(){var n=this;var o=galaxy_config.root+"api/tools/"+this.options.id+"/build?";if(this.options.job_id){o+="job_id="+this.options.job_id}else{if(this.options.dataset_id){o+="dataset_id="+this.options.dataset_id}else{o+="tool_version="+this.options.version+"&";var q=top.location.href;var r=q.indexOf("?");if(q.indexOf("tool_id=")!=-1&&r!==-1){o+=q.slice(r+1)}}}var p=this.deferred.register();i.request({type:"GET",url:o,success:function(s){n.options=s;n._buildForm();n.message.update({status:"success",message:"Now you are using '"+n.options.name+"' version "+n.options.version+".",persistent:false});n.deferred.done(p);console.debug("tools-form::initialize() - Initial tool model ready.");console.debug(s)},error:function(s){n.deferred.done(p);console.debug("tools-form::initialize() - Initial tool model request failed.");console.debug(s);var t=s.error||"Uncaught error.";n.modal.show({title:"Tool cannot be executed",body:t,buttons:{Close:function(){n.modal.hide()}}})}})},_updateModel:function(){var n=this;var o=this.tree.finalize({data:function(s){if(s.values.length>0&&s.values[0]&&s.values[0].src==="hda"){return n.content.get({id:s.values[0].id,src:"hda"}).id_uncoded}return null}});console.debug("tools-form::_refreshForm() - Refreshing states.");console.debug(o);function r(v){for(var t in n.input_list){var u=n.field_list[t];var s=n.input_list[t];if(s.is_dynamic&&u.wait&&u.unwait){if(v){u.wait()}else{u.unwait()}}}}r(true);var q=this.deferred.register();var p=galaxy_config.root+"api/tools/"+this.options.id+"/build?tool_version="+this.options.version;i.request({type:"GET",url:p,data:o,success:function(s){n._updateForm(s);r(false);n.deferred.done(q);console.debug("tools-form::_refreshForm() - States refreshed.");console.debug(s)},error:function(s){n.deferred.done(q);console.debug("tools-form::_refreshForm() - Refresh request failed.");console.debug(s)}})},_updateForm:function(n){var o=this;this.tree.matchModel(n,function(q,u){var p=o.input_list[q];if(p&&p.options){if(!_.isEqual(p.options,u.options)){p.options=u.options;var v=o.field_list[q];if(v.update){var t=[];if((["data","data_collection","drill_down"]).indexOf(p.type)!=-1){t=p.options}else{for(var s in u.options){var r=u.options[s];if(r.length>2){t.push({label:r[0],value:r[1]})}}}v.update(t);v.trigger("change");console.debug("Updating options for "+q)}}}})},_buildForm:function(){var x=this;this.field_list={};this.input_list={};this.element_list={};this.tree=new c(this);this.job_handler=new g(this);this.content=new f(this);var y=this.options;this.message=new m.Message();var n="This tool requires ";for(var r in y.requirements){var w=y.requirements[r];n+=w.name;if(w.version){n+=" (Version "+w.version+")"}if(r<y.requirements.length-2){n+=", "}if(r==y.requirements.length-2){n+=" and "}}n+=".";var t=new m.ButtonIcon({icon:"fa-info-circle",title:"Requirements",tooltip:"Display tool requirements",onclick:function(){if(!this.visible){this.visible=true;x.message.update({persistent:true,message:n,status:"warning"})}else{this.visible=false;x.message.update({message:""})}}});if(!y.requirements||y.requirements.length==0){t.$el.hide()}var p=new m.ButtonMenu({icon:"fa-cubes",title:"Versions",tooltip:"Select another tool version"});if(y.versions&&y.versions.length>1){for(var r in y.versions){var u=y.versions[r];if(u!=y.version){p.addMenu({title:"Switch to "+u,version:u,icon:"fa-cube",onclick:function(){y.id=y.id.replace(y.version,this.version);y.version=this.version;x.deferred.reset();x.deferred.execute(function(){x._buildModel()})}})}}}else{p.$el.hide()}var s=new m.ButtonMenu({icon:"fa-gear",title:"Options",tooltip:"View available options"});if(y.biostar_url){s.addMenu({icon:"fa-question-circle",title:"Question?",tooltip:"Ask a question about this tool (Biostar)",onclick:function(){window.open(y.biostar_url+"/p/new/post/")}});s.addMenu({icon:"fa-search",title:"Search",tooltip:"Search help for this tool (Biostar)",onclick:function(){window.open(y.biostar_url+"/t/"+y.id+"/")}})}s.addMenu({icon:"fa-share",title:"Share",tooltip:"Share this tool",onclick:function(){prompt("Copy to clipboard: Ctrl+C, Enter",window.location.origin+galaxy_config.root+"root?tool_id="+y.id)}});if(this.is_admin){s.addMenu({icon:"fa-download",title:"Download",tooltip:"Download this tool",onclick:function(){window.location.href=galaxy_config.root+"api/tools/"+y.id+"/download"}})}this.section=new l.View(x,{inputs:y.inputs,cls:"ui-table-plain"});if(this.incompatible){this.$el.hide();$("#tool-form-classic").show();return}this.portlet=new h.View({icon:"fa-wrench",title:"<b>"+y.name+"</b> "+y.description+" (Version "+y.version+")",cls:"ui-portlet-slim",operations:{requirements:t,menu:s,versions:p},buttons:{execute:new m.Button({icon:"fa-check",tooltip:"Execute: "+y.name,title:"Execute",cls:"btn btn-primary",floating:"clear",onclick:function(){x.job_handler.submit()}})}});this.$el.empty();this.$el.append(this.portlet.$el);if(y.help!=""){this.$el.append(d.help(y.help))}if(y.citations){var v=$("<div/>");var o=new k.ToolCitationCollection();o.tool_id=y.id;var q=new a.CitationListView({el:v,collection:o});q.render();o.fetch();this.$el.append(v)}this.portlet.append(this.message.$el,true);this.portlet.append(this.section.$el);this.rebuild();if(y.message){this.message.update({persistent:true,status:"warning",message:y.message})}this._showErrors(y)},_showErrors:function(o){if(o.errors){this.tree.finalize();var p=this.tree.matchResponse(o.errors);for(var n in p){this.foundError(n,p[n],true)}}},foundError:function(o,p,n){var q=this.element_list[o];q.error(p||"Please verify this parameter.");if(!n){$(this.container).animate({scrollTop:q.$el.offset().top-20},500)}}});return{View:b}}); \ No newline at end of file +define(["utils/utils","utils/deferred","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-content","mvc/tools/tools-section","mvc/tools/tools-tree","mvc/tools/tools-jobs"],function(i,j,h,m,k,a,e,d,f,l,c,g){var b=Backbone.View.extend({container:"body",initialize:function(n){console.debug(n);var o=parent.Galaxy;if(o&&o.modal){this.modal=o.modal}else{this.modal=new m.Modal.View()}if(o&&o.currUser){this.is_admin=o.currUser.get("is_admin")}else{this.is_admin=false}this.options=n;this.deferred=new j();this.setElement("<div/>");$(this.container).append(this.$el);this._buildForm()},reciept:function(n){$(this.container).empty();$(this.container).append(n)},highlight:function(o,p,n){var q=this.element_list[o];if(q){q.error(p||"Please verify this parameter.");if(!n){$(this.container).animate({scrollTop:q.$el.offset().top-20},500)}}},_buildModel:function(){var n=this;var o=galaxy_config.root+"api/tools/"+this.options.id+"/build?";if(this.options.job_id){o+="job_id="+this.options.job_id}else{if(this.options.dataset_id){o+="dataset_id="+this.options.dataset_id}else{o+="tool_version="+this.options.version+"&";var q=top.location.href;var r=q.indexOf("?");if(q.indexOf("tool_id=")!=-1&&r!==-1){o+=q.slice(r+1)}}}var p=this.deferred.register();i.request({type:"GET",url:o,success:function(s){n.options=s;n._buildForm();n.message.update({status:"success",message:"Now you are using '"+n.options.name+"' version "+n.options.version+".",persistent:false});n.deferred.done(p);console.debug("tools-form::initialize() - Initial tool model ready.");console.debug(s)},error:function(s){n.deferred.done(p);console.debug("tools-form::initialize() - Initial tool model request failed.");console.debug(s);var t=s.error||"Uncaught error.";n.modal.show({title:"Tool cannot be executed",body:t,buttons:{Close:function(){n.modal.hide()}}})}})},_updateModel:function(){var n=this;var o=this.tree.finalize({data:function(s){if(s.values.length>0&&s.values[0]&&s.values[0].src==="hda"){return n.content.get({id:s.values[0].id,src:"hda"}).id_uncoded}return null}});console.debug("tools-form::_refreshForm() - Refreshing states.");console.debug(o);function r(v){for(var t in n.input_list){var u=n.field_list[t];var s=n.input_list[t];if(s.is_dynamic&&u.wait&&u.unwait){if(v){u.wait()}else{u.unwait()}}}}r(true);var q=this.deferred.register();var p=galaxy_config.root+"api/tools/"+this.options.id+"/build?tool_version="+this.options.version;i.request({type:"GET",url:p,data:o,success:function(s){n.tree.matchModel(s,function(u,y){var t=n.input_list[u];if(t&&t.options){if(!_.isEqual(t.options,y.options)){t.options=y.options;var z=n.field_list[u];if(z.update){var x=[];if((["data","data_collection","drill_down"]).indexOf(t.type)!=-1){x=t.options}else{for(var w in y.options){var v=y.options[w];if(v.length>2){x.push({label:v[0],value:v[1]})}}}z.update(x);z.trigger("change");console.debug("Updating options for "+u)}}}});r(false);n.deferred.done(q);console.debug("tools-form::_refreshForm() - States refreshed.");console.debug(s)},error:function(s){n.deferred.done(q);console.debug("tools-form::_refreshForm() - Refresh request failed.");console.debug(s)}})},_buildForm:function(){var n=this;this.off("refresh");this.off("reset");this.field_list={};this.input_list={};this.element_list={};this.tree=new c(this);this.job_handler=new g(this);this.content=new f(this);var p=this.options;this._renderForm(p);this.tree.finalize();if(p.errors){var q=this.tree.matchResponse(p.errors);for(var o in q){this.highlight(o,q[o],true)}}this.on("refresh",function(){n.deferred.reset();n.deferred.execute(function(){n._updateModel()})});this.on("reset",function(){for(var r in this.element_list){this.element_list[r].reset()}})},_renderForm:function(y){var x=this;this.message=new m.Message();var n="This tool requires ";for(var r in y.requirements){var w=y.requirements[r];n+=w.name;if(w.version){n+=" (Version "+w.version+")"}if(r<y.requirements.length-2){n+=", "}if(r==y.requirements.length-2){n+=" and "}}n+=".";var t=new m.ButtonIcon({icon:"fa-info-circle",title:"Requirements",tooltip:"Display tool requirements",onclick:function(){if(!this.visible){this.visible=true;x.message.update({persistent:true,message:n,status:"warning"})}else{this.visible=false;x.message.update({message:""})}}});if(!y.requirements||y.requirements.length==0){t.$el.hide()}var p=new m.ButtonMenu({icon:"fa-cubes",title:"Versions",tooltip:"Select another tool version"});if(y.versions&&y.versions.length>1){for(var r in y.versions){var u=y.versions[r];if(u!=y.version){p.addMenu({title:"Switch to "+u,version:u,icon:"fa-cube",onclick:function(){y.id=y.id.replace(y.version,this.version);y.version=this.version;x.deferred.reset();x.deferred.execute(function(){x._buildModel()})}})}}}else{p.$el.hide()}var s=new m.ButtonMenu({icon:"fa-gear",title:"Options",tooltip:"View available options"});if(y.biostar_url){s.addMenu({icon:"fa-question-circle",title:"Question?",tooltip:"Ask a question about this tool (Biostar)",onclick:function(){window.open(y.biostar_url+"/p/new/post/")}});s.addMenu({icon:"fa-search",title:"Search",tooltip:"Search help for this tool (Biostar)",onclick:function(){window.open(y.biostar_url+"/t/"+y.id+"/")}})}s.addMenu({icon:"fa-share",title:"Share",tooltip:"Share this tool",onclick:function(){prompt("Copy to clipboard: Ctrl+C, Enter",window.location.origin+galaxy_config.root+"root?tool_id="+y.id)}});if(this.is_admin){s.addMenu({icon:"fa-download",title:"Download",tooltip:"Download this tool",onclick:function(){window.location.href=galaxy_config.root+"api/tools/"+y.id+"/download"}})}this.section=new l.View(x,{inputs:y.inputs,cls:"ui-table-plain"});if(this.incompatible){this.$el.hide();$("#tool-form-classic").show();return}this.portlet=new h.View({icon:"fa-wrench",title:"<b>"+y.name+"</b> "+y.description+" (Version "+y.version+")",cls:"ui-portlet-slim",operations:{requirements:t,menu:s,versions:p},buttons:{execute:new m.Button({icon:"fa-check",tooltip:"Execute: "+y.name,title:"Execute",cls:"btn btn-primary",floating:"clear",onclick:function(){x.job_handler.submit()}})}});this.portlet.append(this.message.$el,true);this.portlet.append(this.section.$el);this.$el.empty();this.$el.append(this.portlet.$el);if(y.help!=""){this.$el.append(d.help(y.help))}if(y.citations){var v=$("<div/>");var o=new k.ToolCitationCollection();o.tool_id=y.id;var q=new a.CitationListView({el:v,collection:o});q.render();o.fetch();this.$el.append(v)}if(y.message){this.message.update({persistent:true,status:"warning",message:y.message})}}});return{View:b}}); \ No newline at end of file diff -r bd380f15c1b3b8a8b81d2759eaacd30e94c58d68 -r 17933aef1d3527d22211ff7bf0e47bbbac66c4ac static/scripts/packed/mvc/tools/tools-input.js --- a/static/scripts/packed/mvc/tools/tools-input.js +++ b/static/scripts/packed/mvc/tools/tools-input.js @@ -1,1 +1,1 @@ -define([],function(){return Backbone.View.extend({initialize:function(c,b){this.app=c;this.field=b.field;this.setElement(this._template(b));this.$field=this.$el.find(".ui-table-form-field");this.$title_optional=this.$el.find(".ui-table-form-title-optional");this.$error_text=this.$el.find(".ui-table-form-error-text");this.$error=this.$el.find(".ui-table-form-error");this.$field.prepend(this.field.$el);this.field.skip=false;this._refresh();var a=this;this.$title_optional.on("click",function(){a.field.skip=!a.field.skip;a._refresh()})},error:function(a){this.$error_text.html(a);this.$error.fadeIn();this.$el.addClass("ui-error")},reset:function(){this.$error.hide();this.$el.removeClass("ui-error")},_refresh:function(){if(!this.field.skip){this.$field.fadeIn("fast");this.$title_optional.html("Disable");this.app.refresh()}else{this.$field.hide();this.$title_optional.html("Enable")}},_template:function(a){var b='<div class="ui-table-form-element"><div class="ui-table-form-error ui-error"><span class="fa fa-arrow-down"/><span class="ui-table-form-error-text"/></div><div class="ui-table-form-title-strong">';if(a.optional){b+="Optional: "+a.label+'<span> [<span class="ui-table-form-title-optional"/>]</span>'}else{b+=a.label}b+='</div><div class="ui-table-form-field">';if(a.help){b+='<div class="ui-table-form-info">'+a.help+"</div>"}b+="</div></div>";return b}})}); \ No newline at end of file +define([],function(){return Backbone.View.extend({initialize:function(c,b){this.app=c;this.field=b.field;this.setElement(this._template(b));this.$field=this.$el.find(".ui-table-form-field");this.$title_optional=this.$el.find(".ui-table-form-title-optional");this.$error_text=this.$el.find(".ui-table-form-error-text");this.$error=this.$el.find(".ui-table-form-error");this.$field.prepend(this.field.$el);this.field.skip=false;this._refresh();var a=this;this.$title_optional.on("click",function(){a.field.skip=!a.field.skip;a._refresh()})},error:function(a){this.$error_text.html(a);this.$error.fadeIn();this.$el.addClass("ui-error")},reset:function(){this.$error.hide();this.$el.removeClass("ui-error")},_refresh:function(){if(!this.field.skip){this.$field.fadeIn("fast");this.$title_optional.html("Disable");this.app.trigger("refresh")}else{this.$field.hide();this.$title_optional.html("Enable")}},_template:function(a){var b='<div class="ui-table-form-element"><div class="ui-table-form-error ui-error"><span class="fa fa-arrow-down"/><span class="ui-table-form-error-text"/></div><div class="ui-table-form-title-strong">';if(a.optional){b+="Optional: "+a.label+'<span> [<span class="ui-table-form-title-optional"/>]</span>'}else{b+=a.label}b+='</div><div class="ui-table-form-field">';if(a.help){b+='<div class="ui-table-form-info">'+a.help+"</div>"}b+="</div></div>";return b}})}); \ No newline at end of file diff -r bd380f15c1b3b8a8b81d2759eaacd30e94c58d68 -r 17933aef1d3527d22211ff7bf0e47bbbac66c4ac 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","mvc/tools/tools-template"],function(b,a){return Backbone.Model.extend({initialize:function(c){this.app=c},submit:function(){var c=this;var d={tool_id:this.app.options.id,tool_version:this.app.options.version,inputs:this.app.tree.finalize()};this.app.reset();if(!this._validation(d)){console.debug("tools-jobs::submit - Submission canceled. Validation failed.");return}console.debug(d);this.app.modal.show({title:"Please wait...",body:"progress",closing_events:true,buttons:{Close:function(){c.app.modal.hide()}}});b.request({type:"POST",url:galaxy_config.root+"api/tools",data:d,success:function(e){c.app.modal.hide();c.app.reciept(a.success(e));c._refreshHdas()},error:function(e,g){c.app.modal.hide();if(e&&e.message&&e.message.data){var h=c.app.tree.matchResponse(e.message.data);for(var f in h){c.app.foundError(f,h[f]);break}}else{console.debug(e);c.app.modal.show({title:"Job submission failed",body:a.error(d),buttons:{Close:function(){c.app.modal.hide()}}})}}})},_validation:function(h){var d=h.inputs;var m=-1;var i=null;for(var k in d){var f=d[k];var l=this.app.tree.match(k);var e=this.app.field_list[l];var j=this.app.input_list[l];if(!l||!j||!e){console.debug("tools-jobs::_validation - Retrieving input objects failed.");continue}if(!j.optional&&e.validate&&!e.validate()){this.app.foundError(l);return false}if(f&&f.batch){var g=f.values.length;var c=null;if(g>0){c=f.values[0]&&f.values[0].src}if(c){if(i===null){i=c}else{if(i!==c){this.app.foundError(l,"Please select either dataset or dataset list fields for all batch mode fields.");return false}}}if(m===-1){m=g}else{if(m!==g){this.app.foundError(l,"Please make sure that you select the same number of inputs for all batch mode fields. This field contains <b>"+g+"</b> selection(s) while a previous field contains <b>"+m+"</b>.");return false}}}}return true},_refreshHdas:function(){if(parent.Galaxy&&parent.Galaxy.currHistoryPanel){parent.Galaxy.currHistoryPanel.refreshContents()}}})}); \ No newline at end of file +define(["utils/utils","mvc/tools/tools-template"],function(b,a){return Backbone.Model.extend({initialize:function(c){this.app=c},submit:function(){var c=this;var d={tool_id:this.app.options.id,tool_version:this.app.options.version,inputs:this.app.tree.finalize()};this.app.trigger("reset");if(!this._validation(d)){console.debug("tools-jobs::submit - Submission canceled. Validation failed.");return}console.debug(d);this.app.modal.show({title:"Please wait...",body:"progress",closing_events:true,buttons:{Close:function(){c.app.modal.hide()}}});b.request({type:"POST",url:galaxy_config.root+"api/tools",data:d,success:function(e){c.app.modal.hide();c.app.reciept(a.success(e));c._refreshHdas()},error:function(e,g){c.app.modal.hide();if(e&&e.message&&e.message.data){var h=c.app.tree.matchResponse(e.message.data);for(var f in h){c.app.highlight(f,h[f]);break}}else{console.debug(e);c.app.modal.show({title:"Job submission failed",body:a.error(d),buttons:{Close:function(){c.app.modal.hide()}}})}}})},_validation:function(h){var d=h.inputs;var m=-1;var i=null;for(var k in d){var f=d[k];var l=this.app.tree.match(k);var e=this.app.field_list[l];var j=this.app.input_list[l];if(!l||!j||!e){console.debug("tools-jobs::_validation - Retrieving input objects failed.");continue}if(!j.optional&&e.validate&&!e.validate()){this.app.highlight(l);return false}if(f&&f.batch){var g=f.values.length;var c=null;if(g>0){c=f.values[0]&&f.values[0].src}if(c){if(i===null){i=c}else{if(i!==c){this.app.highlight(l,"Please select either dataset or dataset list fields for all batch mode fields.");return false}}}if(m===-1){m=g}else{if(m!==g){this.app.highlight(l,"Please make sure that you select the same number of inputs for all batch mode fields. This field contains <b>"+g+"</b> selection(s) while a previous field contains <b>"+m+"</b>.");return false}}}}return true},_refreshHdas:function(){if(parent.Galaxy&&parent.Galaxy.currHistoryPanel){parent.Galaxy.currHistoryPanel.refreshContents()}}})}); \ No newline at end of file diff -r bd380f15c1b3b8a8b81d2759eaacd30e94c58d68 -r 17933aef1d3527d22211ff7bf0e47bbbac66c4ac static/scripts/packed/mvc/tools/tools-section.js --- a/static/scripts/packed/mvc/tools/tools-section.js +++ b/static/scripts/packed/mvc/tools/tools-section.js @@ -1,1 +1,1 @@ -define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/tools/tools-repeat","mvc/tools/tools-select-content","mvc/tools/tools-input"],function(d,b,g,c,a,e){var f=Backbone.View.extend({initialize:function(i,h){this.app=i;this.inputs=h.inputs;h.cls_tr="section-row";this.table=new b.View(h);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();for(var h in this.inputs){this._add(this.inputs[h])}},_add:function(j){var i=this;var h=jQuery.extend(true,{},j);h.id=j.id=d.uuid();this.app.input_list[h.id]=h;var k=h.type;switch(k){case"conditional":this._addConditional(h);break;case"repeat":this._addRepeat(h);break;default:this._addRow(h)}},_addConditional:function(h){var j=this;h.test_param.id=h.id;var m=this._addRow(h.test_param);m.options.onchange=function(t){var p=j.app.tree.matchCase(h,t);for(var r in h.cases){var w=h.cases[r];var u=h.id+"-section-"+r;var o=j.table.get(u);var v=false;for(var q in w.inputs){var s=w.inputs[q].type;if(s&&s!=="hidden"){v=true;break}}if(r==p&&v){o.fadeIn("fast")}else{o.hide()}}j.app.refresh()};for(var l in h.cases){var k=h.id+"-section-"+l;var n=new f(this.app,{inputs:h.cases[l].inputs,cls:"ui-table-plain"});n.$el.addClass("ui-table-form-section");this.table.add(n.$el);this.table.append(k)}m.trigger("change")},_addRepeat:function(o){var r=this;var p=0;function m(i,t){var s=o.id+"-section-"+(p++);var u=null;if(t){u=function(){k.del(s);k.retitle(o.title);r.app.rebuild();r.app.refresh()}}var v=new f(r.app,{inputs:i,cls:"ui-table-plain"});k.add({id:s,title:o.title,$el:v.$el,ondel:u});k.retitle(o.title)}var k=new c.View({title_new:o.title,max:o.max,onnew:function(){m(o.inputs,true);r.app.rebuild();r.app.refresh()}});var h=o.min;var q=_.size(o.cache);for(var l=0;l<Math.max(q,h);l++){var n=null;if(l<q){n=o.cache[l]}else{n=o.inputs}m(n,l>=h)}var j=new e(this.app,{label:o.title,help:o.help,field:k});j.$el.addClass("ui-table-form-section");this.table.add(j.$el);this.table.append(o.id)},_addRow:function(h){var k=h.id;var i=this._createField(h);if(h.is_dynamic){this.app.is_dynamic=true}this.app.field_list[k]=i;var j=new e(this.app,{label:h.label,optional:h.optional,help:h.help,field:i});this.app.element_list[k]=j;this.table.add(j.$el);this.table.append(k);return i},_createField:function(h){var i=null;switch(h.type){case"text":i=this._fieldText(h);break;case"select":i=this._fieldSelect(h);break;case"data":i=this._fieldData(h);break;case"data_collection":i=this._fieldData(h);break;case"data_column":h.error_text="Missing columns in referenced dataset.";i=this._fieldSelect(h);break;case"hidden":i=this._fieldHidden(h);break;case"integer":i=this._fieldSlider(h);break;case"float":i=this._fieldSlider(h);break;case"boolean":i=this._fieldBoolean(h);break;case"genomebuild":h.searchable=true;i=this._fieldSelect(h);break;case"drill_down":i=this._fieldDrilldown(h);break;case"baseurl":i=this._fieldHidden(h);break;default:this.app.incompatible=true;if(h.options){i=this._fieldSelect(h)}else{i=this._fieldText(h)}console.debug("tools-form::_addRow() : Auto matched field type ("+h.type+").")}if(h.value!==undefined){i.value(h.value)}return i},_fieldData:function(h){var i=this;return new a.View(this.app,{id:"field-"+h.id,extensions:h.extensions,multiple:h.multiple,type:h.type,data:h.options,onchange:function(){i.app.refresh()}})},_fieldSelect:function(h){var k=[];for(var l in h.options){var m=h.options[l];k.push({label:m[0],value:m[1]})}var n=g.Select;switch(h.display){case"checkboxes":n=g.Checkbox;break;case"radio":n=g.Radio;break}var j=this;return new n.View({id:"field-"+h.id,data:k,error_text:h.error_text||"No options available",multiple:h.multiple,searchable:h.searchable,onchange:function(){j.app.refresh()}})},_fieldDrilldown:function(h){var i=this;return new g.Drilldown.View({id:"field-"+h.id,data:h.options,display:h.display,onchange:function(){i.app.refresh()}})},_fieldText:function(h){var i=this;return new g.Input({id:"field-"+h.id,area:h.area,onchange:function(){i.app.refresh()}})},_fieldSlider:function(h){return new g.Slider.View({id:"field-"+h.id,precise:h.type=="float",min:h.min,max:h.max})},_fieldHidden:function(h){return new g.Hidden({id:"field-"+h.id})},_fieldBoolean:function(h){return new g.RadioButton.View({id:"field-"+h.id,data:[{label:"Yes",value:"true"},{label:"No",value:"false"}]})}});return{View:f}}); \ No newline at end of file +define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/tools/tools-repeat","mvc/tools/tools-select-content","mvc/tools/tools-input"],function(d,b,g,c,a,e){var f=Backbone.View.extend({initialize:function(i,h){this.app=i;this.inputs=h.inputs;h.cls_tr="section-row";this.table=new b.View(h);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();for(var h in this.inputs){this._add(this.inputs[h])}},_add:function(j){var i=this;var h=jQuery.extend(true,{},j);h.id=j.id=d.uuid();this.app.input_list[h.id]=h;var k=h.type;switch(k){case"conditional":this._addConditional(h);break;case"repeat":this._addRepeat(h);break;default:this._addRow(h)}},_addConditional:function(h){var j=this;h.test_param.id=h.id;var m=this._addRow(h.test_param);m.options.onchange=function(t){var p=j.app.tree.matchCase(h,t);for(var r in h.cases){var w=h.cases[r];var u=h.id+"-section-"+r;var o=j.table.get(u);var v=false;for(var q in w.inputs){var s=w.inputs[q].type;if(s&&s!=="hidden"){v=true;break}}if(r==p&&v){o.fadeIn("fast")}else{o.hide()}}j.app.trigger("refresh")};for(var l in h.cases){var k=h.id+"-section-"+l;var n=new f(this.app,{inputs:h.cases[l].inputs,cls:"ui-table-plain"});n.$el.addClass("ui-table-form-section");this.table.add(n.$el);this.table.append(k)}m.trigger("change")},_addRepeat:function(o){var r=this;var p=0;function m(i,t){var s=o.id+"-section-"+(p++);var u=null;if(t){u=function(){k.del(s);k.retitle(o.title);r.app.trigger("refresh")}}var v=new f(r.app,{inputs:i,cls:"ui-table-plain"});k.add({id:s,title:o.title,$el:v.$el,ondel:u});k.retitle(o.title)}var k=new c.View({title_new:o.title,max:o.max,onnew:function(){m(o.inputs,true);r.app.trigger("refresh")}});var h=o.min;var q=_.size(o.cache);for(var l=0;l<Math.max(q,h);l++){var n=null;if(l<q){n=o.cache[l]}else{n=o.inputs}m(n,l>=h)}var j=new e(this.app,{label:o.title,help:o.help,field:k});j.$el.addClass("ui-table-form-section");this.table.add(j.$el);this.table.append(o.id)},_addRow:function(h){var k=h.id;var i=this._createField(h);this.app.field_list[k]=i;var j=new e(this.app,{label:h.label,optional:h.optional,help:h.help,field:i});this.app.element_list[k]=j;this.table.add(j.$el);this.table.append(k);return i},_createField:function(h){var i=null;switch(h.type){case"text":i=this._fieldText(h);break;case"select":i=this._fieldSelect(h);break;case"data":i=this._fieldData(h);break;case"data_collection":i=this._fieldData(h);break;case"data_column":h.error_text="Missing columns in referenced dataset.";i=this._fieldSelect(h);break;case"hidden":i=this._fieldHidden(h);break;case"integer":i=this._fieldSlider(h);break;case"float":i=this._fieldSlider(h);break;case"boolean":i=this._fieldBoolean(h);break;case"genomebuild":h.searchable=true;i=this._fieldSelect(h);break;case"drill_down":i=this._fieldDrilldown(h);break;case"baseurl":i=this._fieldHidden(h);break;default:this.app.incompatible=true;if(h.options){i=this._fieldSelect(h)}else{i=this._fieldText(h)}console.debug("tools-form::_addRow() : Auto matched field type ("+h.type+").")}if(h.value!==undefined){i.value(h.value)}return i},_fieldData:function(h){var i=this;return new a.View(this.app,{id:"field-"+h.id,extensions:h.extensions,multiple:h.multiple,type:h.type,data:h.options,onchange:function(){i.app.trigger("refresh")}})},_fieldSelect:function(h){var k=[];for(var l in h.options){var m=h.options[l];k.push({label:m[0],value:m[1]})}var n=g.Select;switch(h.display){case"checkboxes":n=g.Checkbox;break;case"radio":n=g.Radio;break}var j=this;return new n.View({id:"field-"+h.id,data:k,error_text:h.error_text||"No options available",multiple:h.multiple,searchable:h.searchable,onchange:function(){j.app.trigger("refresh")}})},_fieldDrilldown:function(h){var i=this;return new g.Drilldown.View({id:"field-"+h.id,data:h.options,display:h.display,onchange:function(){i.app.trigger("refresh")}})},_fieldText:function(h){var i=this;return new g.Input({id:"field-"+h.id,area:h.area,onchange:function(){i.app.trigger("refresh")}})},_fieldSlider:function(h){return new g.Slider.View({id:"field-"+h.id,precise:h.type=="float",min:h.min,max:h.max})},_fieldHidden:function(h){return new g.Hidden({id:"field-"+h.id})},_fieldBoolean:function(h){return new g.RadioButton.View({id:"field-"+h.id,data:[{label:"Yes",value:"true"},{label:"No",value:"false"}]})}});return{View:f}}); \ No newline at end of file diff -r bd380f15c1b3b8a8b81d2759eaacd30e94c58d68 -r 17933aef1d3527d22211ff7bf0e47bbbac66c4ac static/scripts/packed/mvc/tools/tools-tree.js --- a/static/scripts/packed/mvc/tools/tools-tree.js +++ b/static/scripts/packed/mvc/tools/tools-tree.js @@ -1,1 +1,1 @@ -define([],function(){return Backbone.Model.extend({initialize:function(a){this.app=a},refresh:function(){this.dict={};this.xml=$("<div/>");if(!this.app.section){return{}}this._iterate(this.app.section.$el,this.dict,this.xml)},finalize:function(d){d=d||{};var a=this;this.job_def={};this.job_ids={};function c(g,f,e){a.job_def[g]=e;a.job_ids[g]=f}function b(l,o){for(var j in o){var g=o[j];if(g.input){var q=g.input;var k=l;if(l!=""){k+="|"}k+=q.name;switch(q.type){case"repeat":var f="section-";var t=[];var n=null;for(var s in g){var m=s.indexOf(f);if(m!=-1){m+=f.length;t.push(parseInt(s.substr(m)));if(!n){n=s.substr(0,m)}}}t.sort(function(u,i){return u-i});var j=0;for(var h in t){b(k+"_"+j++,g[n+t[h]])}break;case"conditional":var r=a.app.field_list[q.id].value();if(d[q.test_param.type]){r=d[q.test_param.type](r)}c(k+"|"+q.test_param.name,q.id,r);var e=a.matchCase(q,r);if(e!=-1){b(k,o[q.id+"-section-"+e])}break;default:var p=a.app.field_list[q.id];var r=p.value();if(d[q.type]){r=d[q.type](r)}if(!p.skip){if(q.optional&&p.validate&&!p.validate()){r=null}c(k,q.id,r)}}}}}b("",this.dict);return this.job_def},match:function(a){return this.job_ids&&this.job_ids[a]},matchCase:function(a,c){if(a.test_param.type=="boolean"){if(c=="true"){c=a.test_param.truevalue||"true"}else{c=a.test_param.falsevalue||"false"}}for(var b in a.cases){if(a.cases[b].value==c){return b}}return -1},matchModel:function(c,e){var a={};var b=this;function d(f,o){for(var l in o){var h=o[l];var m=h.name;if(f!=""){m=f+"|"+m}switch(h.type){case"repeat":for(var k in h.cache){d(m+"_"+k,h.cache[k])}break;case"conditional":var p=h.test_param&&h.test_param.value;var g=b.matchCase(h,p);if(g!=-1){d(m,h.cases[g].inputs)}break;default:var n=b.job_ids[m];if(n){e(n,h)}}}}d("",c.inputs);return a},matchResponse:function(c){var a={};var b=this;function d(k,h){if(typeof h==="string"){var f=b.job_ids[k];if(f){a[f]=h}}else{for(var g in h){var e=g;if(k!==""){var j="|";if(h instanceof Array){j="_"}e=k+j+e}d(e,h[g])}}}d("",c);return a},references:function(c,e){var g=[];var b=this;function d(h,j){var i=$(j).children();var l=[];var k=false;i.each(function(){var o=this;var n=$(o).attr("id");if(n!==c){var m=b.app.input_list[n];if(m){if(m.name==h){k=true;return false}if(m.data_ref==h&&m.type==e){l.push(n)}}}});if(!k){g=g.concat(l);i.each(function(){d(h,this)})}}var f=this.xml.find("#"+c);if(f.length>0){var a=this.app.input_list[c];if(a){d(a.name,f.parent())}}return g},_iterate:function(d,e,b){var a=this;var c=$(d).children();c.each(function(){var i=this;var h=$(i).attr("id");if($(i).hasClass("section-row")){e[h]={};var f=a.app.input_list[h];if(f){e[h]={input:f}}var g=$('<div id="'+h+'"/>');b.append(g);a._iterate(i,e[h],g)}else{a._iterate(i,e,b)}})}})}); \ No newline at end of file +define([],function(){return Backbone.Model.extend({initialize:function(a){this.app=a},finalize:function(f){var a=this;this.map_dict={};if(!this.app.section){return{}}f=f||{};var e={};var d={};this._iterate(this.app.section.$el,d);function c(i,h,g){e[i]=g;a.map_dict[i]=h}function b(n,q){for(var l in q){var j=q[l];if(j.input){var s=j.input;var m=n;if(n!=""){m+="|"}m+=s.name;switch(s.type){case"repeat":var h="section-";var v=[];var p=null;for(var u in j){var o=u.indexOf(h);if(o!=-1){o+=h.length;v.push(parseInt(u.substr(o)));if(!p){p=u.substr(0,o)}}}v.sort(function(w,i){return w-i});var l=0;for(var k in v){b(m+"_"+l++,j[p+v[k]])}break;case"conditional":var t=a.app.field_list[s.id].value();if(f[s.test_param.type]){t=f[s.test_param.type](t)}c(m+"|"+s.test_param.name,s.id,t);var g=a.matchCase(s,t);if(g!=-1){b(m,q[s.id+"-section-"+g])}break;default:var r=a.app.field_list[s.id];var t=r.value();if(f[s.type]){t=f[s.type](t)}if(!r.skip){if(s.optional&&r.validate&&!r.validate()){t=null}c(m,s.id,t)}}}}}b("",d);return e},match:function(a){return this.map_dict&&this.map_dict[a]},matchCase:function(a,c){if(a.test_param.type=="boolean"){if(c=="true"){c=a.test_param.truevalue||"true"}else{c=a.test_param.falsevalue||"false"}}for(var b in a.cases){if(a.cases[b].value==c){return b}}return -1},matchModel:function(c,e){var a={};var b=this;function d(f,o){for(var l in o){var h=o[l];var m=h.name;if(f!=""){m=f+"|"+m}switch(h.type){case"repeat":for(var k in h.cache){d(m+"_"+k,h.cache[k])}break;case"conditional":var p=h.test_param&&h.test_param.value;var g=b.matchCase(h,p);if(g!=-1){d(m,h.cases[g].inputs)}break;default:var n=b.map_dict[m];if(n){e(n,h)}}}}d("",c.inputs);return a},matchResponse:function(c){var a={};var b=this;function d(k,h){if(typeof h==="string"){var f=b.map_dict[k];if(f){a[f]=h}}else{for(var g in h){var e=g;if(k!==""){var j="|";if(h instanceof Array){j="_"}e=k+j+e}d(e,h[g])}}}d("",c);return a},_iterate:function(c,d){var a=this;var b=$(c).children();b.each(function(){var g=this;var f=$(g).attr("id");if($(g).hasClass("section-row")){d[f]={};var e=a.app.input_list[f];if(e){d[f]={input:e}}a._iterate(g,d[f])}else{a._iterate(g,d)}})}})}); \ No newline at end of file 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