Forms: Separate re-usable/regular forms from tool forms

This commit is contained in:
guerler
2015-03-02 14:00:14 -05:00
parent 5c38a22063
commit c242f5d59f
36 changed files with 2274 additions and 662 deletions
@@ -1,49 +1,40 @@
/*
This class maps the tool form dom to an api compatible javascript dictionary.
This class maps the form dom to an api compatible javascript dictionary.
*/
// dependencies
define(['utils/utils'], function(Utils) {
// tool form tree
return Backbone.Model.extend({
// initialize
initialize: function(app) {
this.app = app;
},
/** Convert dictionary representation into tool api specific flat dictionary format.
/** Creates a checksum.
*/
finalize: function(patch) {
checksum: function() {
var sum = '';
for (var i in this.app.field_list) {
var field = this.app.field_list[i];
sum += JSON.stringify(field.value && field.value());
}
return sum;
},
/** Convert dom into dictionary.
*/
create: function() {
// link this
var self = this;
// dictionary with api specific identifiers
this.map_dict = {};
// check if section is available
if (!this.app.section) {
return {};
}
// ensure that dictionary with patching functions exists
patch = patch || {};
// dictionary formatted for job submission or tool form update
var result_dict = {};
// prepare full dictionary
// get raw dictionary from dom
var dict = {};
// fill dictionary from dom
this._iterate(this.app.section.$el, dict);
// add identifier and value to job definition
// add to result dictionary
var result_dict = {};
this.map_dict = {};
function add(job_input_id, input_id, input_value) {
// add entry to result dictionary
result_dict[job_input_id] = input_value;
// backup id mapping
self.map_dict[job_input_id] = input_id;
result_dict[job_input_id] = input_value;
};
// converter between raw dictionary and job dictionary
@@ -93,12 +84,9 @@ return Backbone.Model.extend({
break;
// handle conditionals
case 'conditional':
// get and patch conditional value
// get conditional value
var value = self.app.field_list[input.id].value();
if (patch[input.test_param.type]) {
value = patch[input.test_param.type](value);
}
// add conditional value
add (job_input_id + '|' + input.test_param.name, input.id, value);
@@ -119,11 +107,6 @@ return Backbone.Model.extend({
// validate field value
var value = field.value();
// get and patch field value
if (patch[input.type]) {
value = patch[input.type](value);
}
// ignore certain values
if (input.ignore === undefined || input.ignore != value) {
// add value to submission
@@ -144,7 +127,7 @@ return Backbone.Model.extend({
// start conversion
convert('', dict);
// return result
return result_dict;
},
@@ -262,7 +245,7 @@ return Backbone.Model.extend({
return result;
},
/** Iterate through the tool form dom and map it to the dictionary.
/** Iterate through the form dom and map it to the dictionary.
*/
_iterate: function(parent, dict) {
// get child nodes
@@ -1,11 +1,8 @@
/**
This class creates a tool form input element wrapper
This class creates a form input element wrapper
*/
define([], function() {
// input field element wrapper
return Backbone.View.extend({
// initialize input wrapper
initialize: function(app, options) {
// link app
this.app = app;
@@ -3,7 +3,7 @@
*/
define(['utils/utils',
'mvc/ui/ui-misc',
'mvc/tools/tools-select-content',
'mvc/form/form-select-content',
'mvc/ui/ui-color-picker'],
function(Utils, Ui, SelectContent, ColorPicker) {
@@ -24,7 +24,7 @@ define(['utils/utils',
'color' : '_fieldColor',
'hidden' : '_fieldHidden',
'hidden_data' : '_fieldHidden',
'baseurl' : '_fieldHidden',
'baseurl' : '_fieldHidden'
},
// initialize
@@ -81,7 +81,7 @@ define(['utils/utils',
/** Data input field
*/
_fieldData : function(input_def) {
_fieldData: function(input_def) {
if (!this.app.options.is_dynamic) {
input_def.info = 'Data input \'' + input_def.name + '\' (' + Utils.textify(input_def.extensions.toString()) + ')';
input_def.value = null;
@@ -96,14 +96,14 @@ define(['utils/utils',
type : input_def.type,
data : input_def.options,
onchange : function() {
self.app.trigger('refresh');
self.app.trigger('change');
}
});
},
/** Select/Checkbox/Radio options field
*/
_fieldSelect : function (input_def) {
_fieldSelect: function (input_def) {
// show text field in if dynamic fields are disabled e.g. in workflow editor
if (!this.app.options.is_dynamic && input_def.is_dynamic) {
return this._fieldText(input_def);
@@ -147,14 +147,14 @@ define(['utils/utils',
multiple : input_def.multiple,
searchable : input_def.searchable,
onchange : function() {
self.app.trigger('refresh');
self.app.trigger('change');
}
});
},
/** Drill down options field
*/
_fieldDrilldown : function (input_def) {
_fieldDrilldown: function (input_def) {
// show text field in if dynamic fields are disabled e.g. in workflow editor
if (!this.app.options.is_dynamic && input_def.is_dynamic) {
return this._fieldText(input_def);
@@ -167,14 +167,14 @@ define(['utils/utils',
data : input_def.options,
display : input_def.display,
onchange : function() {
self.app.trigger('refresh');
self.app.trigger('change');
}
});
},
/** Text input field
*/
_fieldText : function(input_def) {
_fieldText: function(input_def) {
// field replaces e.g. a select field
if (input_def.options) {
// show text area if selecting multiple entries is allowed
@@ -201,7 +201,7 @@ define(['utils/utils',
id : 'field-' + input_def.id,
area : input_def.area,
onchange : function() {
self.app.trigger('refresh');
self.app.trigger('change');
}
});
},
@@ -216,14 +216,14 @@ define(['utils/utils',
min : input_def.min,
max : input_def.max,
onchange : function() {
self.app.trigger('refresh');
self.app.trigger('change');
}
});
},
/** Hidden field
*/
_fieldHidden : function(input_def) {
_fieldHidden: function(input_def) {
return new Ui.Hidden({
id : 'field-' + input_def.id,
info : input_def.info
@@ -232,26 +232,26 @@ define(['utils/utils',
/** Boolean field
*/
_fieldBoolean : function(input_def) {
_fieldBoolean: function(input_def) {
var self = this;
return new Ui.RadioButton.View({
id : 'field-' + input_def.id,
data : [ { label : 'Yes', value : 'true' },
{ label : 'No', value : 'false' }],
onchange : function() {
self.app.trigger('refresh');
self.app.trigger('change');
}
});
},
/** Color picker field
*/
_fieldColor : function(input_def) {
_fieldColor: function(input_def) {
var self = this;
return new ColorPicker({
id : 'field-' + input_def.id,
onchange : function() {
self.app.trigger('refresh');
self.app.trigger('change');
}
});
}
@@ -1,5 +1,6 @@
// dependencies
define(['utils/utils', 'mvc/ui/ui-table', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc'], function(Utils, Table, Portlet, Ui) {
define(['utils/utils', 'mvc/ui/ui-table', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc'],
function(Utils, Table, Portlet, Ui) {
/** This class creates a ui component which enables the dynamic creation of portlets
*/
@@ -66,7 +67,7 @@ var View = Backbone.View.extend({
add: function(options) {
// repeat block already exists
if (!options.id || this.list[options.id]) {
console.debug('tools-repeat::add - Duplicate repeat block id.');
console.debug('form-repeat::add - Duplicate repeat block id.');
return;
}
@@ -122,7 +123,7 @@ var View = Backbone.View.extend({
del: function(id) {
// could not find element
if (!this.list[id]) {
console.debug('tools-repeat::del - Invalid repeat block id.');
console.debug('form-repeat::del - Invalid repeat block id.');
return;
}
@@ -1,13 +1,13 @@
/**
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.
This class creates a form section and populates it with input elements. It also handles repeat blocks and conditionals by recursively creating new sub sections.
*/
define(['utils/utils',
'mvc/ui/ui-table',
'mvc/ui/ui-misc',
'mvc/ui/ui-portlet',
'mvc/tools/tools-repeat',
'mvc/tools/tools-input',
'mvc/tools/tools-parameters'],
'mvc/form/form-repeat',
'mvc/form/form-input',
'mvc/form/form-parameters'],
function(Utils, Table, Ui, Portlet, Repeat, InputElement, Parameters) {
// create form view
@@ -26,7 +26,7 @@ define(['utils/utils',
// add table class for tr tag
// this assist in transforming the form into a json structure
options.cls_tr = 'section-row';
// create table
this.table = new Table.View(options);
@@ -36,7 +36,7 @@ define(['utils/utils',
// configure portlet and form table
this.setElement(this.table.$el);
// render tool section
// render section
this.render();
},
@@ -103,7 +103,7 @@ define(['utils/utils',
// set onchange event for test parameter
field.options.onchange = function(value) {
// identify the selected case
var selectedCase = self.app.tree.matchCase(input_def, value);
var selectedCase = self.app.data.matchCase(input_def, value);
// check value in order to hide/show options
for (var i in input_def.cases) {
@@ -134,7 +134,7 @@ define(['utils/utils',
}
// refresh form inputs
self.app.trigger('refresh');
self.app.trigger('change');
};
// add conditional sub sections
@@ -181,7 +181,7 @@ define(['utils/utils',
create(input_def.inputs);
// trigger refresh
self.app.trigger('refresh');
self.app.trigger('change');
}
});
@@ -204,7 +204,7 @@ define(['utils/utils',
repeat.del(sub_section_id);
// trigger refresh
self.app.trigger('refresh');
self.app.trigger('change');
}
});
}
@@ -1,5 +1,9 @@
// dependencies
define(['utils/utils', 'mvc/ui/ui-misc', 'mvc/ui/ui-tabs', 'mvc/tools/tools-template'], function(Utils, Ui, Tabs, ToolTemplate) {
define(['utils/utils', 'mvc/ui/ui-misc', 'mvc/ui/ui-tabs', 'mvc/tools/tools-template'],
function(Utils, Ui, Tabs, ToolTemplate) {
history = {};
var View = Backbone.View.extend({
// initialize
@@ -14,7 +18,7 @@ var View = Backbone.View.extend({
// add element
this.setElement('<div class="ui-select-content"/>');
// list of select fields
// list of select fieldsFormSection
this.list = {};
// radio button options
@@ -119,7 +123,7 @@ var View = Backbone.View.extend({
});
// add batch mode information
this.$batch = $(ToolTemplate.batchMode());
this.$batch = $(this.template_batch());
// number of radio buttons
var n_buttons = _.size(this.list);
@@ -191,7 +195,7 @@ var View = Backbone.View.extend({
value: item.id
});
// backup to local history
self.app.history[item.id + '_' + item.src] = item;
history[item.id + '_' + item.src] = item;
}
// update field
field.update(select_options);
@@ -266,7 +270,7 @@ var View = Backbone.View.extend({
// append to dataset ids
for (var i in id_list) {
var details = _.findWhere(this.app.history, {
var details = _.findWhere(history, {
id : id_list[i],
src : this.list[this.current].type
});
@@ -312,7 +316,7 @@ var View = Backbone.View.extend({
/** Assists in identifying the batch mode */
_batch: function() {
if (this.current == 'collection') {
var hdca = _.findWhere(this.app.history, {
var hdca = _.findWhere(history, {
id : this._select().value(),
src : 'hdca'
});
@@ -326,6 +330,14 @@ var View = Backbone.View.extend({
}
}
return false;
},
/** Batch message template */
template_batch: function() {
return '<div class="ui-table-form-info">' +
'<i class="fa fa-sitemap" style="font-size: 1.2em; padding: 2px 5px;"/>' +
'This is a batch mode input field. A separate job will be triggered for each dataset.' +
'</div>';
}
});
+199
View File
@@ -0,0 +1,199 @@
/**
This is the main class of the form plugin. It is referenced as 'app' in all lower level modules.
*/
define(['utils/utils', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
'mvc/form/form-section', 'mvc/form/form-data'],
function(Utils, Portlet, Ui, FormSection, FormData) {
// create form view
return Backbone.View.extend({
// initialize
initialize: function(options) {
// options
this.optionsDefault = {
// uses dynamic fields instead of text fields
is_dynamic : true,
// shows form in narrow view mode
narrow : false,
// shows errors on start
initial_errors : false,
// portlet style
cls : 'ui-portlet-limited'
};
// configure options
this.options = Utils.merge(options, this.optionsDefault);
// log options
console.debug(this.options);
// link galaxy modal or create one
var galaxy = parent.Galaxy;
if (galaxy && galaxy.modal) {
this.modal = galaxy.modal;
} else {
this.modal = new Ui.Modal.View();
}
// set element
this.setElement('<div/>');
// build this form
this._build();
},
/** Set form into wait mode */
wait: function(active) {
for (var i in this.input_list) {
var field = this.field_list[i];
var input = this.input_list[i];
if (input.is_dynamic && field.wait && field.unwait) {
if (active) {
field.wait();
} else {
field.unwait();
}
}
}
},
/** Shows the final message (usually upon successful job submission)
*/
reciept: function($el) {
this.$el.empty();
this.$el.append($el);
},
/** 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) {
$('html, body').animate({
scrollTop: input_element.$el.offset().top - 20
}, 500);
}
}
},
/** Highlights errors
*/
errors: function(options) {
// hide previous error statements
this.trigger('reset');
// highlight all errors
if (options && options.errors) {
var error_messages = this.data.matchResponse(options.errors);
for (var input_id in this.element_list) {
var input = this.element_list[input_id];
if (error_messages[input_id]) {
this.highlight(input_id, error_messages[input_id], true);
}
}
}
},
/** Main tool form build function. This function is called once a new model is available.
*/
_build: function() {
// link this
var self = this;
// reset events
this.off('change');
this.off('reset');
// reset field list, which contains the input field elements
this.field_list = {};
// reset sequential input definition list, which contains the input definitions as provided from the api
this.input_list = {};
// reset input element list, which contains the dom elements of each input element (includes also the input field)
this.element_list = {};
// creates a json data structure from the input form
this.data = new FormData(this);
// create ui elements
this._renderForm();
// refresh data
this.data.create();
// show errors on startup
if (this.options.initial_errors) {
this.errors(this.options);
}
// add listener which triggers on checksum change
var current_check = this.data.checksum();
this.on('change', function() {
var new_check = self.data.checksum();
if (new_check != current_check) {
current_check = new_check;
self.options.onchange && self.options.onchange();
}
});
// 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() {
// create message view
this.message = new Ui.Message();
// create tool form section
this.section = new FormSection.View(this, {
inputs : this.options.inputs
});
// create portlet
this.portlet = new Portlet.View({
icon : 'fa-wrench',
title : this.options.title,
cls : this.options.cls,
operations : this.options.operations,
buttons : this.options.buttons
});
// append message
this.portlet.append(this.message.$el.addClass('ui-margin-top'));
// append tool section
this.portlet.append(this.section.$el);
// start form
this.$el.empty();
this.$el.append(this.portlet.$el);
// show message if available in model
if (this.options.message) {
this.message.update({
persistent : true,
status : 'warning',
message : this.options.message
});
}
// log
console.debug('tools-form-base::initialize() - Completed.');
}
});
});
@@ -1,52 +1,22 @@
/**
This is the main class of the tool form plugin. It is referenced as 'app' in all lower level modules.
This is the base class of the tool form plugin. It is referenced as 'app' in all lower level modules.
*/
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-section', 'mvc/tools/tools-tree'],
function(Utils, Deferred, Portlet, Ui, CitationModel, CitationView,
Tools, ToolTemplate, ToolSection, ToolTree) {
define(['utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view',
'mvc/tools/tools-template', 'mvc/citation/citation-model', 'mvc/citation/citation-view'],
function(Utils, Deferred, Ui, Form, ToolTemplate, CitationModel, CitationView) {
// create form view
return Backbone.View.extend({
// initialize
initialize: function(options) {
// options
this.optionsDefault = {
// uses dynamic fields instead of text fields
is_dynamic : true,
// shows form in narrow view mode
narrow : false,
// shows errors on start
initial_errors : false,
// portlet style
cls_portlet : 'ui-portlet-limited'
};
// configure options
this.options = Utils.merge(options, this.optionsDefault);
// log options
console.debug(this.options);
// link galaxy modal or create one
var galaxy = parent.Galaxy;
if (galaxy && galaxy.modal) {
this.modal = galaxy.modal;
} else {
this.modal = new Ui.Modal.View();
}
// check if the user is an admin
var galaxy = parent.Galaxy;
if (galaxy && galaxy.currUser) {
this.is_admin = galaxy.currUser.get('is_admin');
} else {
this.is_admin = false;
}
// link container
this.container = this.options.container || 'body';
// create deferred processing queue handler
// this handler reduces the number of requests to the api by filtering redundant requests
this.deferred = new Deferred();
@@ -54,126 +24,52 @@ define(['utils/utils', 'utils/deferred', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
// set element
this.setElement('<div/>');
// add to main element
// append to body
this.container = options.container || 'body';
$(this.container).append(this.$el);
// build this form
this.build(this.options);
// create form
this._buildForm(options);
},
/** Main tool form build function. This function is called once a new model is available.
*/
build: function(options) {
/** Build form */
_buildForm: function(options) {
// link this
var self = this;
// reset events
this.off('refresh');
this.off('reset');
// configure options
this.options = Utils.merge(options, this.optionsDefault);
// reset field list, which contains the input field elements
this.field_list = {};
// reset sequential input definition list, which contains the input definitions as provided from the api
this.input_list = {};
// reset input element list, which contains the dom elements of each input element (includes also the input field)
this.element_list = {};
// creates a tree/json data structure from the input form
this.tree = new ToolTree(this);
// keeps track of history items
this.history = {};
// update model data
self.options.inputs = options && options.inputs;
// create ui elements
this._renderForm(options);
// rebuild the underlying data structure
var current_state = this.tree.finalize();
// show errors on startup
if (options.initial_errors) {
this._errors(options);
}
// add refresh listener
this.on('refresh', function() {
// by using/resetting the deferred ajax queue the number of redundant calls is reduced
self.deferred.reset();
self.deferred.execute(function(){
var new_state = self.tree.finalize();
if (!_.isEqual(new_state, current_state)) {
current_state = new_state;
self._updateModel($.extend(true, {}, current_state));
}
});
});
// add reset listener
this.on('reset', function() {
for (var i in this.element_list) {
this.element_list[i].reset();
// merge form options
var form_options = Utils.merge({
icon : 'fa-wrench',
title : '<b>' + options.name + '</b> ' + options.description + ' (Galaxy Tool Version ' + options.version + ')',
operations : this._operations(),
onchange : function(current_state) {
// by resetting the deferred ajax queue the number of redundant calls is reduced
self.deferred.reset();
self.deferred.execute(function(){
self._updateModel($.extend(true, {}, self.form.data.create()));
});
}
});
}, options);
// create form
this.form = new Form(form_options);
// create footer
this._footer();
// create element
this.$el.empty();
this.$el.append(this.form.$el);
},
/** Shows the final message (usually upon successful job submission)
*/
reciept: function($el) {
$(this.container).empty();
$(this.container).append($el);
},
/** 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) {
$('html, body').animate({
scrollTop: input_element.$el.offset().top - 20
}, 500);
}
}
},
/** Highlights errors
*/
_errors: function(options) {
// hide previous error statements
this.trigger('reset');
// highlight all errors
if (options && options.errors) {
var error_messages = this.tree.matchResponse(options.errors);
for (var input_id in this.element_list) {
var input = this.element_list[input_id];
if (error_messages[input_id]) {
this.highlight(input_id, error_messages[input_id], true);
}
}
}
},
/** Renders the UI elements required for the form
*/
_renderForm: function(options) {
// create tool operation menu
_operations: function() {
// link this
var self = this;
// create message view
this.message = new Ui.Message();
var options = self.options;
// button for version selection
var versions_button = new Ui.ButtonMenu({
@@ -191,8 +87,8 @@ define(['utils/utils', 'utils/deferred', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
icon : 'fa-cube',
onclick : function() {
// here we update the tool version (some tools encode the version also in the id)
self.options.id = self.options.id.replace(self.options.version, this.version);
self.options.version = this.version;
options.id = options.id.replace(options.version, this.version);
options.version = this.version;
// rebuild the model and form
self.deferred.reset();
@@ -223,7 +119,7 @@ define(['utils/utils', 'utils/deferred', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
window.open(options.biostar_url + '/p/new/post/');
}
});
// create search button
menu_button.addMenu({
icon : 'fa-search',
@@ -246,7 +142,7 @@ define(['utils/utils', 'utils/deferred', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
});
// add admin operations
if (this.is_admin) {
if (self.is_admin) {
// create download button
menu_button.addMenu({
icon : 'fa-download',
@@ -267,14 +163,14 @@ define(['utils/utils', 'utils/deferred', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
onclick : function() {
if (!this.visible) {
this.visible = true;
self.message.update({
self.form.message.update({
persistent : true,
message : ToolTemplate.requirements(options),
status : 'info'
});
} else {
this.visible = false;
self.message.update({
self.form.message.update({
message : ''
});
}
@@ -282,59 +178,36 @@ define(['utils/utils', 'utils/deferred', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
});
}
// add toolshed url
if (this.options.sharable_url) {
if (options.sharable_url) {
menu_button.addMenu({
icon : 'fa-external-link',
title : 'See in Tool Shed',
tooltip : 'Access the repository',
onclick : function() {
window.open(self.options.sharable_url);
window.open(options.sharable_url);
}
});
}
// create tool form section
this.section = new ToolSection.View(self, {
inputs : options.inputs
});
// switch to classic tool form mako if the form definition is incompatible
if (this.incompatible) {
this.$el.hide();
$('#tool-form-classic').show();
return;
// return operations
return {
menu : menu_button,
versions : versions_button
}
},
// create portlet
this.portlet = new Portlet.View({
icon : 'fa-wrench',
title : '<b>' + options.name + '</b> ' + options.description + ' (Galaxy Tool Version ' + options.version + ')',
cls : this.options.cls_portlet,
operations: {
menu : menu_button,
versions : versions_button
},
buttons : this.buttons
});
// append message
this.portlet.append(this.message.$el.addClass('ui-margin-top'));
// append tool section
this.portlet.append(this.section.$el);
// start form
this.$el.empty();
this.$el.append(this.portlet.$el);
// create footer
_footer: function() {
// link options
var options = this.options;
// append help
if (options.help != '') {
this.$el.append(ToolTemplate.help(options.help));
this.form.$el.append(ToolTemplate.help(options));
}
// append citations
// create and append tool citations
if (options.citations) {
var $citations = $('<div/>');
var citations = new CitationModel.ToolCitationCollection();
@@ -342,20 +215,8 @@ define(['utils/utils', 'utils/deferred', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
var citation_list_view = new CitationView.CitationListView({ el: $citations, collection: citations } );
citation_list_view.render();
citations.fetch();
this.$el.append($citations);
this.form.$el.append($citations);
}
// show message if available in model
if (options.message) {
this.message.update({
persistent : true,
status : 'warning',
message : options.message
});
}
// log
console.debug('tools-form-base::initialize() - Completed.');
}
});
});
@@ -278,7 +278,7 @@ define(['utils/utils', 'mvc/tools/tools-form-base'],
_updateModel: function(current_state) {
// link self
var self = this;
// create the request dictionary
current_state = {
tool_id : this.options.id,
@@ -306,7 +306,7 @@ define(['utils/utils', 'mvc/tools/tools-form-base'],
self.node.update_field_data(data);
// highlight errors
self._errors(data && data.tool_model);
self.form.errors(data && data.tool_model);
// process completed
self.deferred.done(process_id);
+16 -30
View File
@@ -9,8 +9,7 @@ define(['utils/utils', 'mvc/ui/ui-misc', 'mvc/tools/tools-form-base', 'mvc/tools
// initialize
initialize: function(options) {
var self = this;
this.job_handler = new ToolJobs(this);
this.buttons = {
options.buttons = {
execute : new Ui.Button({
icon : 'fa-check',
tooltip : 'Execute: ' + options.name,
@@ -18,11 +17,10 @@ define(['utils/utils', 'mvc/ui/ui-misc', 'mvc/tools/tools-form-base', 'mvc/tools
cls : 'btn btn-primary',
floating : 'clear',
onclick : function() {
self.job_handler.submit();
ToolJobs.submit(self.form, options);
}
})
}
options.initial_errors = options.job_id;
};
ToolFormBase.prototype.initialize.call(this, options);
},
@@ -58,10 +56,10 @@ define(['utils/utils', 'mvc/ui/ui-misc', 'mvc/tools/tools-form-base', 'mvc/tools
url : model_url,
success : function(response) {
// build new tool form
self.build(response);
self._buildForm(response);
// notification
self.message.update({
self.form.message.update({
status : 'success',
message : 'Now you are using \'' + self.options.name + '\' version ' + self.options.version + '.',
persistent : false
@@ -84,12 +82,12 @@ define(['utils/utils', 'mvc/ui/ui-misc', 'mvc/tools/tools-form-base', 'mvc/tools
// show error
var error_message = response.error || 'Uncaught error.';
self.modal.show({
self.form.modal.show({
title : 'Tool cannot be executed',
body : error_message,
buttons : {
'Close' : function() {
self.modal.hide();
self.form.modal.hide();
}
}
});
@@ -100,8 +98,11 @@ define(['utils/utils', 'mvc/ui/ui-misc', 'mvc/tools/tools-form-base', 'mvc/tools
/** Request a new model for an already created tool form and updates the form inputs
*/
_updateModel: function(current_state) {
// create the request dictionary
// link this
var self = this;
// create the request dictionary
var form = this.form;
// create the request dictionary
var current_state = {
@@ -110,23 +111,8 @@ define(['utils/utils', 'mvc/ui/ui-misc', 'mvc/tools/tools-form-base', 'mvc/tools
inputs : current_state
}
// activates/disables spinner for dynamic fields to indicate that they are currently being updated
function wait(active) {
for (var i in self.input_list) {
var field = self.field_list[i];
var input = self.input_list[i];
if (input.is_dynamic && field.wait && field.unwait) {
if (active) {
field.wait();
} else {
field.unwait();
}
}
}
}
// set wait mode
wait(true);
form.wait(true);
// register process
var process_id = this.deferred.register();
@@ -145,15 +131,15 @@ define(['utils/utils', 'mvc/ui/ui-misc', 'mvc/tools/tools-form-base', 'mvc/tools
data : current_state,
success : function(new_model) {
// update form
self.tree.matchModel(new_model, function(input_id, node) {
var input = self.input_list[input_id];
form.data.matchModel(new_model, function(input_id, node) {
var input = form.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];
var field = form.field_list[input_id];
if (field.update) {
var new_options = [];
if ((['data', 'data_collection', 'drill_down']).indexOf(input.type) != -1) {
@@ -178,7 +164,7 @@ define(['utils/utils', 'mvc/ui/ui-misc', 'mvc/tools/tools-form-base', 'mvc/tools
});
// unset wait mode
wait(false);
form.wait(false);
// log success
console.debug('tools-form::_refreshForm() - Received new model (see below).');
+43 -50
View File
@@ -1,74 +1,67 @@
/**
This class handles job submissions and the error handling.
This class handles job submissions and validations.
*/
define(['utils/utils', 'mvc/tools/tools-template'], function(Utils, ToolTemplate) {
return Backbone.Model.extend({
// initialize
initialize: function(app) {
this.app = app;
},
/** Creates and submits a job request to the api
*/
submit: function() {
return {
submit: function(form, options) {
// link this
var self = this;
// create job definition for submission to tools api
var job_def = {
tool_id : this.app.options.id,
tool_version : this.app.options.version,
inputs : this.app.tree.finalize()
tool_id : options.id,
tool_version : options.version,
inputs : form.data.create()
}
// reset
this.app.trigger('reset');
form.trigger('reset');
// validate job definition
if (!this._validation(job_def)) {
if (!this._validation(form, job_def)) {
console.debug('tools-jobs::submit - Submission canceled. Validation failed.');
return;
}
// debug
console.debug(job_def);
// show progress modal
var user_is_waiting = true;
this.app.modal.show({title: 'Please wait...', body: 'progress', buttons: {
form.modal.show({title: 'Please wait...', body: 'progress', buttons: {
'Close' : function () {
self.app.modal.hide();
form.modal.hide();
user_is_waiting = false;
}
}});
// post job
Utils.request({
type : 'POST',
url : galaxy_config.root + 'api/tools',
data : job_def,
success : function(response) {
self.app.modal.hide();
self.app.reciept(ToolTemplate.success(response));
form.modal.hide();
form.reciept(ToolTemplate.success(response));
self._refreshHdas();
},
error : function(response, response_full) {
self.app.modal.hide();
form.modal.hide();
if (response && response.message && response.message.data) {
var error_messages = self.app.tree.matchResponse(response.message.data);
var error_messages = form.data.matchResponse(response.message.data);
for (var input_id in error_messages) {
self.app.highlight(input_id, error_messages[input_id]);
form.highlight(input_id, error_messages[input_id]);
break;
}
} else {
// show error message with details
console.debug(response);
user_is_waiting && self.app.modal.show({
user_is_waiting && form.modal.show({
title : 'Job submission failed',
body : ToolTemplate.error(job_def),
buttons : {
'Close' : function() {
self.app.modal.hide();
form.modal.hide();
}
}
});
@@ -76,78 +69,78 @@ return Backbone.Model.extend({
}
});
},
/** Validate job definition
*/
_validation: function(job_def) {
_validation: function(form, job_def) {
// get input parameters
var job_inputs = job_def.inputs;
// counter for values declared in batch mode
var batch_n = -1;
var batch_src = null;
// validation
for (var job_input_id in job_inputs) {
// get current value
var input_value = job_inputs[job_input_id];
// collect input field properties
var input_id = this.app.tree.match(job_input_id);
var input_field = this.app.field_list[input_id];
var input_def = this.app.input_list[input_id];
var input_id = form.data.match(job_input_id);
var input_field = form.field_list[input_id];
var input_def = form.input_list[input_id];
// check if objects where properly identified
if (!input_id || !input_def || !input_field) {
console.debug('tools-jobs::_validation - Retrieving input objects failed.');
continue;
}
// validate non-optional fields
if (!input_def.optional && input_value == null) {
this.app.highlight(input_id);
form.highlight(input_id);
return false;
}
// check if input field is in batch mode
if (input_value && input_value.batch) {
// get values
var n = input_value.values.length;
// get source
var src = null;
if (n > 0) {
src = input_value.values[0] && input_value.values[0].src;
}
// check source type
if (src) {
if (batch_src === null) {
batch_src = src;
} else {
if (batch_src !== src) {
this.app.highlight(input_id, 'Please select either dataset or dataset list fields for all batch mode fields.');
form.highlight(input_id, 'Please select either dataset or dataset list fields for all batch mode fields.');
return false;
}
}
}
// check number of inputs
if (batch_n === -1) {
batch_n = n;
} else {
if (batch_n !== n) {
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>.');
form.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;
}
}
}
}
// return validation result
return true;
},
/** Refreshes the history panel
*/
_refreshHdas: function() {
@@ -155,6 +148,6 @@ return Backbone.Model.extend({
parent.Galaxy.currHistoryPanel.refreshContents();
}
}
});
};
});
@@ -3,14 +3,14 @@ define([], function() {
// tool form templates
return {
help: function(content) {
help: function(options) {
return '<div class="toolHelp" style="overflow: auto;">' +
'<div class="toolHelpBody">' +
content +
options.help +
'</div>' +
'</div>';
},
success: function(response) {
// check
if (!response.jobs || !response.jobs.length) {
@@ -52,13 +52,6 @@ return {
'</div>';
},
batchMode: function() {
return '<div class="ui-table-form-info">' +
'<i class="fa fa-sitemap" style="font-size: 1.2em; padding: 2px 5px;"/>' +
'This is a batch mode input field. A separate job will be triggered for each dataset.' +
'</div>';
},
requirements: function(options) {
var requirements_message = 'This tool requires ';
for (var i in options.requirements) {
+283
View File
@@ -0,0 +1,283 @@
/*
This class maps the form dom to an api compatible javascript dictionary.
*/
define(['utils/utils'], function(Utils) {
return Backbone.Model.extend({
// initialize
initialize: function(app) {
this.app = app;
},
/** Creates a checksum.
*/
checksum: function() {
var sum = '';
for (var i in this.app.field_list) {
var field = this.app.field_list[i];
sum += JSON.stringify(field.value && field.value());
}
return sum;
},
/** Convert dom into dictionary.
*/
create: function() {
// link this
var self = this;
// get raw dictionary from dom
var dict = {};
this._iterate(this.app.section.$el, dict);
// add to result dictionary
var result_dict = {};
this.map_dict = {};
function add(job_input_id, input_id, input_value) {
self.map_dict[job_input_id] = input_id;
result_dict[job_input_id] = input_value;
};
// converter between raw dictionary and job dictionary
function convert(identifier, head) {
for (var index in head) {
var node = head[index];
if (node.input) {
// get node
var input = node.input;
// create identifier
var job_input_id = identifier;
if (identifier != '') {
job_input_id += '|';
}
job_input_id += input.name;
// process input type
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 block_indices) {
convert(job_input_id + '_' + index++, node[block_prefix + block_indices[i]]);
}
break;
// handle conditionals
case 'conditional':
// get conditional value
var value = self.app.field_list[input.id].value();
// add conditional value
add (job_input_id + '|' + input.test_param.name, input.id, value);
// identify selected case
var selectedCase = self.matchCase(input, value);
if (selectedCase != -1) {
convert(job_input_id, head[input.id + '-section-' + selectedCase]);
}
break;
// handle custom sub sections
case 'section':
convert('', node);
break;
default:
// get field
var field = self.app.field_list[input.id];
if (field && field.value) {
// validate field value
var value = field.value();
// ignore certain values
if (input.ignore === undefined || input.ignore != value) {
// add value to submission
add (job_input_id, input.id, value);
// add payload to submission
if (input.payload) {
for (var p_id in input.payload) {
add (p_id, input.id, input.payload[p_id]);
}
}
}
}
}
}
}
}
// start conversion
convert('', dict);
// return result
return result_dict;
},
/** Match job definition identifier to input element identifier
*/
match: function (job_input_id) {
return this.map_dict && this.map_dict[job_input_id];
},
/** Match conditional values to selected cases
*/
matchCase: function(input, value) {
// format value for boolean inputs
if (input.test_param.type == 'boolean') {
if (value == 'true') {
value = input.test_param.truevalue || 'true';
} else {
value = input.test_param.falsevalue || 'false';
}
}
// find selected case
for (var i in input.cases) {
if (input.cases[i].value == value) {
return i;
}
}
// selected case not found
return -1;
},
/** Matches identifier from api model to input elements
*/
matchModel: function(model, callback) {
// final result dictionary
var result = {};
// link this
var self = this;
// search throughout response
function search (id, head) {
for (var i in head) {
var node = head[i];
var index = node.name;
if (id != '') {
index = id + '|' + index;
}
switch (node.type) {
case 'repeat':
for (var j in node.cache) {
search (index + '_' + j, node.cache[j]);
}
break;
case 'conditional':
var value = node.test_param && node.test_param.value;
var selectedCase = self.matchCase(node, value);
if (selectedCase != -1) {
search (index, node.cases[selectedCase].inputs);
}
break;
default:
var input_id = self.map_dict[index];
if (input_id) {
callback(input_id, node);
}
}
}
}
// match all ids and return messages
search('', model.inputs);
// return matched results
return result;
},
/** Matches identifier from api response to input elements
*/
matchResponse: function(response) {
// final result dictionary
var result = {};
// link this
var self = this;
// search throughout response
function search (id, head) {
if (typeof head === 'string') {
var input_id = self.map_dict[id];
if (input_id) {
result[input_id] = head;
}
} else {
for (var i in head) {
var new_id = i;
if (id !== '') {
var separator = '|';
if (head instanceof Array) {
separator = '_';
}
new_id = id + separator + new_id;
}
search (new_id, head[i]);
}
}
}
// match all ids and return messages
search('', response);
// return matched results
return result;
},
/** Iterate through the form dom and map it to the dictionary.
*/
_iterate: function(parent, dict) {
// get child nodes
var self = this;
var children = $(parent).children();
children.each(function() {
// get child element
var child = this;
// get id
var id = $(child).attr('id');
// create new branch
if ($(child).hasClass('section-row')) {
// create sub dictionary
dict[id] = {};
// add input element if it exists
var input = self.app.input_list[id];
if (input) {
dict[id] = {
input : input
}
}
// fill sub dictionary
self._iterate(child, dict[id]);
} else {
self._iterate(child, dict);
}
});
}
});
});
+144
View File
@@ -0,0 +1,144 @@
/**
This class creates a form input element wrapper
*/
define([], function() {
return Backbone.View.extend({
initialize: function(app, options) {
// link app
this.app = app;
// set text labels and icons for optional button
this.text_enable = app.options.text_enable || 'Enable';
this.text_disable = app.options.text_disable || 'Disable';
this.cls_enable = app.options.cls_enable || 'fa fa-plus-square';
this.cls_disable = app.options.cls_disable || 'fa fa-minus-square';
// link field
this.field = options.field;
this.default_value = options.default_value;
// set element
this.setElement(this._template(options));
// link elements
this.$field = this.$el.find('.ui-table-form-field');
this.$optional = this.$el.find('.ui-table-form-optional');
this.$optional_icon = this.$el.find('.ui-table-form-optional').find('.icon');
this.$error_text = this.$el.find('.ui-table-form-error-text');
this.$error = this.$el.find('.ui-table-form-error');
// add field element
this.$field.prepend(this.field.$el);
// decide wether to expand or collapse optional fields
this.field.skip = false;
var v = this.field.value && this.field.value();
this.field.skip = Boolean(options.optional &&
(v === null || v === '' || v === this.default_value ||
String(v) === String(this.default_value) ||
Number(v) === Number(this.default_value) ||
JSON.stringify(v) === JSON.stringify(this.default_value)));
// refresh view
this._refresh();
// add optional hide/show
var self = this;
this.$optional.on('click', function() {
// flip flag
self.field.skip = !self.field.skip;
// refresh view
self._refresh();
// refresh state
self.app.trigger('refresh');
});
},
/** Set error text
*/
error: function(text) {
this.$error_text.html(text);
this.$error.show();
this.$el.addClass('ui-error');
},
/** Reset this view
*/
reset: function() {
this.$error.hide();
this.$el.removeClass('ui-error');
},
/** Refresh element
*/
_refresh: function() {
// reset optional button
this.$optional_icon.removeClass().addClass('icon');
// identify state
if (!this.field.skip) {
// enable input field
this.$field.fadeIn('fast');
this._tooltip(this.text_disable, this.cls_disable);
} else {
// disable input field
this.$field.hide();
this._tooltip(this.text_enable, this.cls_enable);
// reset field value
this.field.value && this.field.value(this.default_value);
}
},
/** Set tooltip text
*/
_tooltip: function(title, cls) {
if (this.$optional.length) {
this.$optional_icon.addClass(cls)
.tooltip({ placement: 'bottom' })
.attr('data-original-title', title)
.tooltip('fixTitle').tooltip('hide');
}
},
/** Main Template
*/
_template: function(options) {
// create table element
var tmp = '<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">';
// is optional
if (options.optional) {
tmp += '<div class="ui-table-form-optional">' +
'<i class="icon"/>' + options.label +
'</div>';
} else {
tmp += options.label;
}
// finalize title
tmp += '</div>' +
'<div class="ui-table-form-field">';
// add help
tmp += '<div class="ui-table-form-info">';
if (options.help) {
tmp += options.help;
}
tmp += '</div>';
// finalize
tmp += '</div>' +
'</div>';
// return input element
return tmp;
}
});
});
+263
View File
@@ -0,0 +1,263 @@
/**
This class creates input elements. New input parameter types should be added to the types dictionary.
*/
define(['utils/utils',
'mvc/ui/ui-misc',
'mvc/form/form-select-content',
'mvc/ui/ui-color-picker'],
function(Utils, Ui, SelectContent, ColorPicker) {
// create form view
return Backbone.Model.extend({
/** Available parameter types */
types: {
'text' : '_fieldText',
'select' : '_fieldSelect',
'data_column' : '_fieldSelect',
'genomebuild' : '_fieldSelect',
'data' : '_fieldData',
'data_collection' : '_fieldData',
'integer' : '_fieldSlider',
'float' : '_fieldSlider',
'boolean' : '_fieldBoolean',
'drill_down' : '_fieldDrilldown',
'color' : '_fieldColor',
'hidden' : '_fieldHidden',
'hidden_data' : '_fieldHidden',
'baseurl' : '_fieldHidden'
},
// initialize
initialize: function(app, options) {
this.app = app;
},
/** Returns an input field for a given field type
*/
create: function(input_def) {
// add regular/default value if missing
if (input_def.value === undefined) {
input_def.value = null;
}
if (input_def.default_value === undefined) {
input_def.default_value = input_def.value;
}
// field wrapper
var field = null;
// get field class
var fieldClass = this.types[input_def.type];
if (fieldClass && typeof(this[fieldClass]) === 'function') {
field = this[fieldClass].call(this, input_def);
}
// identify field type
if (!field) {
// flag
this.app.incompatible = true;
// with or without options
if (input_def.options) {
// assign select field
field = this._fieldSelect(input_def);
} else {
// assign text field
field = this._fieldText(input_def);
}
// log
console.debug('tools-form::_addRow() : Auto matched field type (' + input_def.type + ').');
}
// set field value
if (input_def.value !== undefined) {
field.value(input_def.value);
}
// return field element
return field;
},
/** Data input field
*/
_fieldData: function(input_def) {
if (!this.app.options.is_dynamic) {
input_def.info = 'Data input \'' + input_def.name + '\' (' + Utils.textify(input_def.extensions.toString()) + ')';
input_def.value = null;
return this._fieldHidden(input_def);
}
var self = this;
return new SelectContent.View(this.app, {
id : 'field-' + input_def.id,
extensions : input_def.extensions,
optional : input_def.optional,
multiple : input_def.multiple,
type : input_def.type,
data : input_def.options,
onchange : function() {
self.app.trigger('change');
}
});
},
/** Select/Checkbox/Radio options field
*/
_fieldSelect: function (input_def) {
// show text field in if dynamic fields are disabled e.g. in workflow editor
if (!this.app.options.is_dynamic && input_def.is_dynamic) {
return this._fieldText(input_def);
}
// customize properties
if (input_def.type == 'data_column') {
input_def.error_text = 'Missing columns in referenced dataset.'
}
if (input_def.type == 'genomebuild') {
input_def.searchable = true;
}
// configure options fields
var options = [];
for (var i in input_def.options) {
var option = input_def.options[i];
options.push({
label: option[0],
value: option[1]
});
}
// identify display type
var SelectClass = Ui.Select;
switch (input_def.display) {
case 'checkboxes':
SelectClass = Ui.Checkbox;
break;
case 'radio':
SelectClass = Ui.Radio;
break;
}
// select field
var self = this;
return new SelectClass.View({
id : 'field-' + input_def.id,
data : options,
error_text : input_def.error_text || 'No options available',
multiple : input_def.multiple,
searchable : input_def.searchable,
onchange : function() {
self.app.trigger('change');
}
});
},
/** Drill down options field
*/
_fieldDrilldown: function (input_def) {
// show text field in if dynamic fields are disabled e.g. in workflow editor
if (!this.app.options.is_dynamic && input_def.is_dynamic) {
return this._fieldText(input_def);
}
// create drill down field
var self = this;
return new Ui.Drilldown.View({
id : 'field-' + input_def.id,
data : input_def.options,
display : input_def.display,
onchange : function() {
self.app.trigger('change');
}
});
},
/** Text input field
*/
_fieldText: function(input_def) {
// field replaces e.g. a select field
if (input_def.options) {
// show text area if selecting multiple entries is allowed
input_def.area = input_def.multiple;
// validate value
if (!Utils.validate(input_def.value)) {
input_def.value = '';
} else {
if (input_def.value instanceof Array) {
input_def.value = value.toString();
} else {
input_def.value = String(input_def.value).replace(/[\[\]'"\s]/g, '');
if (input_def.multiple) {
input_def.value = input_def.value.replace(/,/g, '\n');
}
}
}
}
// create input element
var self = this;
return new Ui.Input({
id : 'field-' + input_def.id,
area : input_def.area,
onchange : function() {
self.app.trigger('change');
}
});
},
/** Slider field
*/
_fieldSlider: function(input_def) {
var self = this;
return new Ui.Slider.View({
id : 'field-' + input_def.id,
precise : input_def.type == 'float',
min : input_def.min,
max : input_def.max,
onchange : function() {
self.app.trigger('change');
}
});
},
/** Hidden field
*/
_fieldHidden: function(input_def) {
return new Ui.Hidden({
id : 'field-' + input_def.id,
info : input_def.info
});
},
/** Boolean field
*/
_fieldBoolean: function(input_def) {
var self = this;
return new Ui.RadioButton.View({
id : 'field-' + input_def.id,
data : [ { label : 'Yes', value : 'true' },
{ label : 'No', value : 'false' }],
onchange : function() {
self.app.trigger('change');
}
});
},
/** Color picker field
*/
_fieldColor: function(input_def) {
var self = this;
return new ColorPicker({
id : 'field-' + input_def.id,
onchange : function() {
self.app.trigger('change');
}
});
}
});
return {
View: View
};
});
+167
View File
@@ -0,0 +1,167 @@
// dependencies
define(['utils/utils', 'mvc/ui/ui-table', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc'],
function(Utils, Table, Portlet, Ui) {
/** This class creates a ui component which enables the dynamic creation of portlets
*/
var View = Backbone.View.extend({
// default options
optionsDefault : {
title : 'Section',
max : null,
min : null
},
/** Initialize
*/
initialize : function(options) {
// configure options
this.options = Utils.merge(options, this.optionsDefault);
// create new element
this.setElement('<div/>');
// link this
var self = this;
// create button
this.button_new = new Ui.ButtonIcon({
icon : 'fa-plus',
title : 'Insert ' + options.title_new,
tooltip : 'Add new ' + options.title_new + ' block',
floating: 'clear',
onclick : function() {
if (options.onnew) {
options.onnew();
}
}
});
// create table
this.table = new Table.View({
cls : 'ui-table-plain',
content : ''
});
// append button
this.$el.append(this.table.$el);
// add button
this.$el.append($('<div/>').append(this.button_new.$el));
// clear list
this.list = {};
// number of available repeats
this.n = 0;
},
/** Number of repeat blocks
*/
size: function() {
return this.n;
},
/** Add new repeat block
*/
add: function(options) {
// repeat block already exists
if (!options.id || this.list[options.id]) {
console.debug('form-repeat::add - Duplicate repeat block id.');
return;
}
// increase repeat block counter
this.n++;
// delete button
var button_delete = new Ui.ButtonIcon({
icon : 'fa-trash-o',
tooltip : 'Delete this repeat block',
cls : 'ui-button-icon-plain',
onclick : function() {
if (options.ondel) {
options.ondel();
}
}
});
// create portlet
var portlet = new Portlet.View({
id : options.id,
title : 'placeholder',
cls : 'ui-portlet-repeat',
operations : {
button_delete : button_delete
}
});
// append content
portlet.append(options.$el);
// tag as section row
portlet.$el.addClass('section-row');
// append to dom
this.list[options.id] = portlet;
// append to dom
this.table.add(portlet.$el);
this.table.append('row_' + options.id, true);
// validate maximum
if (this.options.max > 0 && this.n >= this.options.max) {
this.button_new.disable();
}
// refresh view
this._refresh();
},
/** Delete repeat block
*/
del: function(id) {
// could not find element
if (!this.list[id]) {
console.debug('form-repeat::del - Invalid repeat block id.');
return;
}
// decrease repeat block counter
this.n--;
// delete table row
var table_row = this.table.get('row_' + id);
table_row.remove();
// remove from list
delete this.list[id];
// enable new button
this.button_new.enable();
// refresh delete button visibility
this._refresh();
},
/** Refresh view
*/
_refresh: function() {
var index = 0;
for (var id in this.list) {
var portlet = this.list[id];
portlet.title(++index + ': ' + this.options.title);
if (this.n > this.options.min) {
portlet.showOperation('button_delete');
} else {
portlet.hideOperation('button_delete');
}
}
}
});
return {
View : View
}
});
+343
View File
@@ -0,0 +1,343 @@
/**
This class creates a form section and populates it with input elements. It also handles repeat blocks and conditionals by recursively creating new sub sections.
*/
define(['utils/utils',
'mvc/ui/ui-table',
'mvc/ui/ui-misc',
'mvc/ui/ui-portlet',
'mvc/form/form-repeat',
'mvc/form/form-input',
'mvc/form/form-parameters'],
function(Utils, Table, Ui, Portlet, Repeat, InputElement, Parameters) {
// create form view
var View = Backbone.View.extend({
// initialize
initialize: function(app, options) {
// link app
this.app = app;
// link inputs
this.inputs = options.inputs;
// fix table style
options.cls = 'ui-table-plain';
// add table class for tr tag
// this assist in transforming the form into a json structure
options.cls_tr = 'section-row';
// create table
this.table = new Table.View(options);
// create parameter handler
this.parameters = new Parameters(app, options);
// configure portlet and form table
this.setElement(this.table.$el);
// render section
this.render();
},
/** Render section view
*/
render: function() {
// reset table
this.table.delAll();
// load settings elements into table
for (var i in this.inputs) {
this.add(this.inputs[i]);
}
},
/** Add a new input element
*/
add: function(input) {
// link this
var self = this;
// clone definition
var input_def = jQuery.extend(true, {}, input);
// create unique id
input_def.id = input.id = Utils.uuid();
// add to sequential list of inputs
this.app.input_list[input_def.id] = input_def;
// identify field type
var type = input_def.type;
switch(type) {
// conditional field
case 'conditional':
this._addConditional(input_def);
break;
// repeat block
case 'repeat':
this._addRepeat(input_def);
break;
// customized section
case 'section':
this._addSection(input_def);
break;
// default single element row
default:
this._addRow(input_def);
}
},
/** Add a conditional block
*/
_addConditional: function(input_def) {
// link this
var self = this;
// copy identifier
input_def.test_param.id = input_def.id;
// build test parameter
var field = this._addRow(input_def.test_param);
// set onchange event for test parameter
field.options.onchange = function(value) {
// identify the selected case
var selectedCase = self.app.data.matchCase(input_def, value);
// check value in order to hide/show options
for (var i in input_def.cases) {
// get case
var case_def = input_def.cases[i];
// identify subsection name
var section_id = input_def.id + '-section-' + i;
// identify row
var section_row = self.table.get(section_id);
// check if non-hidden elements exist
var nonhidden = false;
for (var j in case_def.inputs) {
if (!case_def.inputs[j].hidden) {
nonhidden = true;
break;
}
}
// show/hide sub form
if (i == selectedCase && nonhidden) {
section_row.fadeIn('fast');
} else {
section_row.hide();
}
}
// refresh form inputs
self.app.trigger('change');
};
// add conditional sub sections
for (var i in input_def.cases) {
// create id tag
var sub_section_id = input_def.id + '-section-' + i;
// create sub section
var sub_section = new View(this.app, {
inputs : input_def.cases[i].inputs
});
// displays as grouped subsection
sub_section.$el.addClass('ui-table-section');
// create table row
this.table.add(sub_section.$el);
// append to table
this.table.append(sub_section_id);
}
// trigger refresh on conditional input field after all input elements have been created
field.trigger('change');
},
/** Add a repeat block
*/
_addRepeat: function(input_def) {
// link this
var self = this;
// block index
var block_index = 0;
// create repeat block element
var repeat = new Repeat.View({
title : input_def.title,
title_new : input_def.title,
min : input_def.min,
max : input_def.max,
onnew : function() {
// create
create(input_def.inputs);
// trigger refresh
self.app.trigger('change');
}
});
// helper function to create new repeat blocks
function create (inputs) {
// create id tag
var sub_section_id = input_def.id + '-section-' + (block_index++);
// create sub section
var sub_section = new View(self.app, {
inputs : inputs
});
// add tab
repeat.add({
id : sub_section_id,
$el : sub_section.$el,
ondel : function() {
// delete repeat block
repeat.del(sub_section_id);
// trigger refresh
self.app.trigger('change');
}
});
}
//
// add parsed/minimum number of repeat blocks
//
var n_min = input_def.min;
var n_cache = _.size(input_def.cache);
for (var i = 0; i < Math.max(n_cache, n_min); i++) {
var inputs = null;
if (i < n_cache) {
inputs = input_def.cache[i];
} else {
inputs = input_def.inputs;
}
// create repeat block
create(inputs);
}
// create input field wrapper
var input_element = new InputElement(this.app, {
label : input_def.title,
help : input_def.help,
field : repeat
});
// create table row
this.table.add(input_element.$el);
// append row to table
this.table.append(input_def.id);
},
/** Add a customized section
*/
_addSection: function(input_def) {
// link this
var self = this;
// create sub section
var sub_section = new View(self.app, {
inputs : input_def.inputs
});
// delete button
var button_visible = new Ui.ButtonIcon({
icon : 'fa-eye-slash',
tooltip : 'Show/hide section',
cls : 'ui-button-icon-plain'
});
// create portlet for sub section
var portlet = new Portlet.View({
title : input_def.label,
cls : 'ui-portlet-section',
operations : {
button_visible: button_visible
}
});
portlet.append(sub_section.$el);
portlet.append($('<div/>').addClass('ui-table-form-info').html(input_def.help));
// add event handler visibility button
var visible = false;
portlet.$content.hide();
portlet.$header.css('cursor', 'pointer');
portlet.$header.on('click', function() {
if (visible) {
visible = false;
portlet.$content.hide();
button_visible.setIcon('fa-eye-slash');
} else {
visible = true;
portlet.$content.fadeIn('fast');
button_visible.setIcon('fa-eye');
}
});
// show sub section if requested
if (input_def.expand) {
portlet.$header.trigger('click');
}
// create table row
this.table.add(portlet.$el);
// append row to table
this.table.append(input_def.id);
},
/** Add a single input field element
*/
_addRow: function(input_def) {
// get id
var id = input_def.id;
// create input field
var field = this.parameters.create(input_def);
// add to field list
this.app.field_list[id] = field;
// create input field wrapper
var input_element = new InputElement(this.app, {
label : input_def.label,
default_value : input_def.default_value,
optional : input_def.optional,
help : input_def.help,
field : field
});
// add to element list
this.app.element_list[id] = input_element;
// create table row
this.table.add(input_element.$el);
// append to table
this.table.append(id);
// hide row if neccessary
if (input_def.hidden) {
this.table.get(id).hide();
}
// return created field
return field;
}
});
return {
View: View
};
});
@@ -0,0 +1,348 @@
// dependencies
define(['utils/utils', 'mvc/ui/ui-misc', 'mvc/ui/ui-tabs', 'mvc/tools/tools-template'],
function(Utils, Ui, Tabs, ToolTemplate) {
history = {};
var View = Backbone.View.extend({
// initialize
initialize : function(app, options) {
// link app and options
this.app = app;
this.options = options;
// link this
var self = this;
// add element
this.setElement('<div class="ui-select-content"/>');
// list of select fieldsFormSection
this.list = {};
// radio button options
var radio_buttons = [];
// identify selector type
if (options.type == 'data_collection') {
this.mode = 'collection';
} else {
if (options.multiple) {
this.mode = 'multiple';
} else {
this.mode = 'single';
}
}
// set initial state
this.current = this.mode;
this.list = {};
// error messages
var extensions = Utils.textify(options.extensions);
var hda_error = 'No dataset available.';
if (extensions) {
hda_error = 'No ' + extensions + ' dataset available.';
}
var hdca_error = 'No dataset list available.';
if (extensions) {
hdca_error = 'No ' + extensions + ' dataset collection available.';
}
// add single dataset selector
if (this.mode == 'single') {
radio_buttons.push({
icon : 'fa-file-o',
value : 'single',
tooltip : 'Single dataset'
});
this.select_single = new Ui.Select.View({
optional : options.optional,
error_text : hda_error,
onchange : function() {
self.trigger('change');
}
});
this.list['single'] = {
field: this.select_single,
type : 'hda'
};
}
// add multiple dataset selector
if (this.mode == 'single' || this.mode == 'multiple') {
radio_buttons.push({
icon : 'fa-files-o',
value : 'multiple',
tooltip : 'Multiple datasets'
});
this.select_multiple = new Ui.Select.View({
multiple : true,
searchable : false,
error_text : hda_error,
onchange : function() {
self.trigger('change');
}
});
this.list['multiple'] = {
field: this.select_multiple,
type : 'hda'
};
}
// add collection selector
if (this.mode == 'single' || this.mode == 'multiple' || this.mode == 'collection') {
radio_buttons.push({
icon : 'fa-folder-o',
value : 'collection',
tooltip : 'Dataset collection'
});
this.select_collection = new Ui.Select.View({
error_text : hdca_error,
optional : options.optional,
onchange : function() {
self.trigger('change');
}
});
this.list['collection'] = {
field: this.select_collection,
type : 'hdca'
};
}
// create button
this.button_type = new Ui.RadioButton.View({
value : this.current,
data : radio_buttons,
onchange: function(value) {
self.current = value;
self.refresh();
self.trigger('change');
}
});
// add batch mode information
this.$batch = $(this.template_batch());
// number of radio buttons
var n_buttons = _.size(this.list);
// add button to dom
var button_width = 0;
if (n_buttons > 1) {
this.$el.append(this.button_type.$el);
button_width = Math.max(0, _.size(this.list) * 35) + 'px';
}
// append field elements
for (var i in this.list) {
this.$el.append(this.list[i].field.$el.css({
'margin-left': button_width
}));
}
// append batch message
this.$el.append(this.$batch.css({
'margin-left': button_width
}));
// update options
this.update(options.data);
// set initial value
if (this.options.value !== undefined) {
this.value(this.options.value);
}
// refresh view
this.refresh();
// add change event. fires on trigger
this.on('change', function() {
if (options.onchange) {
options.onchange(self.value());
}
});
},
/** Indicate that select fields are being updated */
wait: function() {
for (var i in this.list) {
this.list[i].field.wait();
}
},
/** Indicate that the options update has been completed */
unwait: function() {
for (var i in this.list) {
this.list[i].field.unwait();
}
},
/** Update content selector */
update: function(options) {
// update a particular select field
var self = this;
function _update(field, options) {
if (field) {
// identify available options
var select_options = [];
for (var i in options) {
var item = options[i];
select_options.push({
label: item.hid + ': ' + item.name,
value: item.id
});
// backup to local history
history[item.id + '_' + item.src] = item;
}
// update field
field.update(select_options);
}
}
// update available options
_update(this.select_single, options.hda);
_update(this.select_multiple, options.hda);
_update(this.select_collection, options.hdca);
},
/** Return the currently selected dataset values */
value : function (new_value) {
// update current value
if (new_value !== undefined) {
if (new_value && new_value.values) {
try {
// create list with values
var list = [];
for (var i in new_value.values) {
list.push(new_value.values[i].id);
}
// identify suitable select field
if (new_value && new_value.values.length > 0 && new_value.values[0].src == 'hcda') {
this.current = 'collection';
this.select_collection.value(list[0]);
} else {
if (this.mode == 'multiple') {
this.current = 'multiple';
this.select_multiple.value(list);
} else {
this.current = 'single';
this.select_single.value(list[0]);
}
}
} catch (err) {
console.debug('tools-select-content::value() - Skipped.');
}
} else {
for (var i in this.list) {
this.list[i].field.value(null);
}
}
}
// refresh view
this.refresh();
// validate value
var id_list = this._select().value();
if (id_list === null) {
return null;
}
// transform into an array
if (!(id_list instanceof Array)) {
id_list = [id_list];
}
// check if value exists
if (id_list.length === 0) {
return null;
}
// prepare result dict
var result = {
batch : this._batch(),
values : []
}
// append to dataset ids
for (var i in id_list) {
var details = _.findWhere(history, {
id : id_list[i],
src : this.list[this.current].type
});
if (details) {
result.values.push(details);
} else {
return null;
}
}
// sort by history ids
result.values.sort(function(a, b){
return a.hid - b.hid;
});
// return
return result;
},
/** Refreshes data selection view */
refresh: function() {
this.button_type.value(this.current);
for (var i in this.list) {
var $el = this.list[i].field.$el;
if (this.current == i) {
$el.show();
} else {
$el.hide();
}
}
if (this._batch()) {
this.$batch.show();
} else {
this.$batch.hide();
}
},
/** Assists in selecting the current field */
_select: function() {
return this.list[this.current].field;
},
/** Assists in identifying the batch mode */
_batch: function() {
if (this.current == 'collection') {
var hdca = _.findWhere(history, {
id : this._select().value(),
src : 'hdca'
});
if (hdca && hdca.map_over_type) {
return true;
}
}
if (this.current != 'single') {
if (this.mode == 'single') {
return true;
}
}
return false;
},
/** Batch message template */
template_batch: function() {
return '<div class="ui-table-form-info">' +
'<i class="fa fa-sitemap" style="font-size: 1.2em; padding: 2px 5px;"/>' +
'This is a batch mode input field. A separate job will be triggered for each dataset.' +
'</div>';
}
});
return {
View: View
}
});
+199
View File
@@ -0,0 +1,199 @@
/**
This is the main class of the form plugin. It is referenced as 'app' in all lower level modules.
*/
define(['utils/utils', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
'mvc/form/form-section', 'mvc/form/form-data'],
function(Utils, Portlet, Ui, FormSection, FormData) {
// create form view
return Backbone.View.extend({
// initialize
initialize: function(options) {
// options
this.optionsDefault = {
// uses dynamic fields instead of text fields
is_dynamic : true,
// shows form in narrow view mode
narrow : false,
// shows errors on start
initial_errors : false,
// portlet style
cls : 'ui-portlet-limited'
};
// configure options
this.options = Utils.merge(options, this.optionsDefault);
// log options
console.debug(this.options);
// link galaxy modal or create one
var galaxy = parent.Galaxy;
if (galaxy && galaxy.modal) {
this.modal = galaxy.modal;
} else {
this.modal = new Ui.Modal.View();
}
// set element
this.setElement('<div/>');
// build this form
this._build();
},
/** Set form into wait mode */
wait: function(active) {
for (var i in this.input_list) {
var field = this.field_list[i];
var input = this.input_list[i];
if (input.is_dynamic && field.wait && field.unwait) {
if (active) {
field.wait();
} else {
field.unwait();
}
}
}
},
/** Shows the final message (usually upon successful job submission)
*/
reciept: function($el) {
this.$el.empty();
this.$el.append($el);
},
/** 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) {
$('html, body').animate({
scrollTop: input_element.$el.offset().top - 20
}, 500);
}
}
},
/** Highlights errors
*/
errors: function(options) {
// hide previous error statements
this.trigger('reset');
// highlight all errors
if (options && options.errors) {
var error_messages = this.data.matchResponse(options.errors);
for (var input_id in this.element_list) {
var input = this.element_list[input_id];
if (error_messages[input_id]) {
this.highlight(input_id, error_messages[input_id], true);
}
}
}
},
/** Main tool form build function. This function is called once a new model is available.
*/
_build: function() {
// link this
var self = this;
// reset events
this.off('change');
this.off('reset');
// reset field list, which contains the input field elements
this.field_list = {};
// reset sequential input definition list, which contains the input definitions as provided from the api
this.input_list = {};
// reset input element list, which contains the dom elements of each input element (includes also the input field)
this.element_list = {};
// creates a json data structure from the input form
this.data = new FormData(this);
// create ui elements
this._renderForm();
// refresh data
this.data.create();
// show errors on startup
if (this.options.initial_errors) {
this.errors(this.options);
}
// add listener which triggers on checksum change
var current_check = this.data.checksum();
this.on('change', function() {
var new_check = self.data.checksum();
if (new_check != current_check) {
current_check = new_check;
self.options.onchange && self.options.onchange();
}
});
// 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() {
// create message view
this.message = new Ui.Message();
// create tool form section
this.section = new FormSection.View(this, {
inputs : this.options.inputs
});
// create portlet
this.portlet = new Portlet.View({
icon : 'fa-wrench',
title : this.options.title,
cls : this.options.cls,
operations : this.options.operations,
buttons : this.options.buttons
});
// append message
this.portlet.append(this.message.$el.addClass('ui-margin-top'));
// append tool section
this.portlet.append(this.section.$el);
// start form
this.$el.empty();
this.$el.append(this.portlet.$el);
// show message if available in model
if (this.options.message) {
this.message.update({
persistent : true,
status : 'warning',
message : this.options.message
});
}
// log
console.debug('tools-form-base::initialize() - Completed.');
}
});
});
+58 -197
View File
@@ -1,52 +1,22 @@
/**
This is the main class of the tool form plugin. It is referenced as 'app' in all lower level modules.
This is the base class of the tool form plugin. It is referenced as 'app' in all lower level modules.
*/
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-section', 'mvc/tools/tools-tree'],
function(Utils, Deferred, Portlet, Ui, CitationModel, CitationView,
Tools, ToolTemplate, ToolSection, ToolTree) {
define(['utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view',
'mvc/tools/tools-template', 'mvc/citation/citation-model', 'mvc/citation/citation-view'],
function(Utils, Deferred, Ui, Form, ToolTemplate, CitationModel, CitationView) {
// create form view
return Backbone.View.extend({
// initialize
initialize: function(options) {
// options
this.optionsDefault = {
// uses dynamic fields instead of text fields
is_dynamic : true,
// shows form in narrow view mode
narrow : false,
// shows errors on start
initial_errors : false,
// portlet style
cls_portlet : 'ui-portlet-limited'
};
// configure options
this.options = Utils.merge(options, this.optionsDefault);
// log options
console.debug(this.options);
// link galaxy modal or create one
var galaxy = parent.Galaxy;
if (galaxy && galaxy.modal) {
this.modal = galaxy.modal;
} else {
this.modal = new Ui.Modal.View();
}
// check if the user is an admin
var galaxy = parent.Galaxy;
if (galaxy && galaxy.currUser) {
this.is_admin = galaxy.currUser.get('is_admin');
} else {
this.is_admin = false;
}
// link container
this.container = this.options.container || 'body';
// create deferred processing queue handler
// this handler reduces the number of requests to the api by filtering redundant requests
this.deferred = new Deferred();
@@ -54,126 +24,52 @@ define(['utils/utils', 'utils/deferred', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
// set element
this.setElement('<div/>');
// add to main element
// append to body
this.container = options.container || 'body';
$(this.container).append(this.$el);
// build this form
this.build(this.options);
// create form
this._buildForm(options);
},
/** Main tool form build function. This function is called once a new model is available.
*/
build: function(options) {
/** Build form */
_buildForm: function(options) {
// link this
var self = this;
// reset events
this.off('refresh');
this.off('reset');
// configure options
this.options = Utils.merge(options, this.optionsDefault);
// reset field list, which contains the input field elements
this.field_list = {};
// reset sequential input definition list, which contains the input definitions as provided from the api
this.input_list = {};
// reset input element list, which contains the dom elements of each input element (includes also the input field)
this.element_list = {};
// creates a tree/json data structure from the input form
this.tree = new ToolTree(this);
// keeps track of history items
this.history = {};
// update model data
self.options.inputs = options && options.inputs;
// create ui elements
this._renderForm(options);
// rebuild the underlying data structure
var current_state = this.tree.finalize();
// show errors on startup
if (options.initial_errors) {
this._errors(options);
}
// add refresh listener
this.on('refresh', function() {
// by using/resetting the deferred ajax queue the number of redundant calls is reduced
self.deferred.reset();
self.deferred.execute(function(){
var new_state = self.tree.finalize();
if (!_.isEqual(new_state, current_state)) {
current_state = new_state;
self._updateModel($.extend(true, {}, current_state));
}
});
});
// add reset listener
this.on('reset', function() {
for (var i in this.element_list) {
this.element_list[i].reset();
// merge form options
var form_options = Utils.merge({
icon : 'fa-wrench',
title : '<b>' + options.name + '</b> ' + options.description + ' (Galaxy Tool Version ' + options.version + ')',
operations : this._operations(),
onchange : function(current_state) {
// by resetting the deferred ajax queue the number of redundant calls is reduced
self.deferred.reset();
self.deferred.execute(function(){
self._updateModel($.extend(true, {}, self.form.data.create()));
});
}
});
}, options);
// create form
this.form = new Form(form_options);
// create footer
this._footer();
// create element
this.$el.empty();
this.$el.append(this.form.$el);
},
/** Shows the final message (usually upon successful job submission)
*/
reciept: function($el) {
$(this.container).empty();
$(this.container).append($el);
},
/** 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) {
$('html, body').animate({
scrollTop: input_element.$el.offset().top - 20
}, 500);
}
}
},
/** Highlights errors
*/
_errors: function(options) {
// hide previous error statements
this.trigger('reset');
// highlight all errors
if (options && options.errors) {
var error_messages = this.tree.matchResponse(options.errors);
for (var input_id in this.element_list) {
var input = this.element_list[input_id];
if (error_messages[input_id]) {
this.highlight(input_id, error_messages[input_id], true);
}
}
}
},
/** Renders the UI elements required for the form
*/
_renderForm: function(options) {
// create tool operation menu
_operations: function() {
// link this
var self = this;
// create message view
this.message = new Ui.Message();
var options = self.options;
// button for version selection
var versions_button = new Ui.ButtonMenu({
@@ -191,8 +87,8 @@ define(['utils/utils', 'utils/deferred', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
icon : 'fa-cube',
onclick : function() {
// here we update the tool version (some tools encode the version also in the id)
self.options.id = self.options.id.replace(self.options.version, this.version);
self.options.version = this.version;
options.id = options.id.replace(options.version, this.version);
options.version = this.version;
// rebuild the model and form
self.deferred.reset();
@@ -223,7 +119,7 @@ define(['utils/utils', 'utils/deferred', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
window.open(options.biostar_url + '/p/new/post/');
}
});
// create search button
menu_button.addMenu({
icon : 'fa-search',
@@ -246,7 +142,7 @@ define(['utils/utils', 'utils/deferred', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
});
// add admin operations
if (this.is_admin) {
if (self.is_admin) {
// create download button
menu_button.addMenu({
icon : 'fa-download',
@@ -267,14 +163,14 @@ define(['utils/utils', 'utils/deferred', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
onclick : function() {
if (!this.visible) {
this.visible = true;
self.message.update({
self.form.message.update({
persistent : true,
message : ToolTemplate.requirements(options),
status : 'info'
});
} else {
this.visible = false;
self.message.update({
self.form.message.update({
message : ''
});
}
@@ -282,59 +178,36 @@ define(['utils/utils', 'utils/deferred', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
});
}
// add toolshed url
if (this.options.sharable_url) {
if (options.sharable_url) {
menu_button.addMenu({
icon : 'fa-external-link',
title : 'See in Tool Shed',
tooltip : 'Access the repository',
onclick : function() {
window.open(self.options.sharable_url);
window.open(options.sharable_url);
}
});
}
// create tool form section
this.section = new ToolSection.View(self, {
inputs : options.inputs
});
// switch to classic tool form mako if the form definition is incompatible
if (this.incompatible) {
this.$el.hide();
$('#tool-form-classic').show();
return;
// return operations
return {
menu : menu_button,
versions : versions_button
}
},
// create portlet
this.portlet = new Portlet.View({
icon : 'fa-wrench',
title : '<b>' + options.name + '</b> ' + options.description + ' (Galaxy Tool Version ' + options.version + ')',
cls : this.options.cls_portlet,
operations: {
menu : menu_button,
versions : versions_button
},
buttons : this.buttons
});
// append message
this.portlet.append(this.message.$el.addClass('ui-margin-top'));
// append tool section
this.portlet.append(this.section.$el);
// start form
this.$el.empty();
this.$el.append(this.portlet.$el);
// create footer
_footer: function() {
// link options
var options = this.options;
// append help
if (options.help != '') {
this.$el.append(ToolTemplate.help(options.help));
this.form.$el.append(ToolTemplate.help(options));
}
// append citations
// create and append tool citations
if (options.citations) {
var $citations = $('<div/>');
var citations = new CitationModel.ToolCitationCollection();
@@ -342,20 +215,8 @@ define(['utils/utils', 'utils/deferred', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
var citation_list_view = new CitationView.CitationListView({ el: $citations, collection: citations } );
citation_list_view.render();
citations.fetch();
this.$el.append($citations);
this.form.$el.append($citations);
}
// show message if available in model
if (options.message) {
this.message.update({
persistent : true,
status : 'warning',
message : options.message
});
}
// log
console.debug('tools-form-base::initialize() - Completed.');
}
});
});
@@ -278,7 +278,7 @@ define(['utils/utils', 'mvc/tools/tools-form-base'],
_updateModel: function(current_state) {
// link self
var self = this;
// create the request dictionary
current_state = {
tool_id : this.options.id,
@@ -306,7 +306,7 @@ define(['utils/utils', 'mvc/tools/tools-form-base'],
self.node.update_field_data(data);
// highlight errors
self._errors(data && data.tool_model);
self.form.errors(data && data.tool_model);
// process completed
self.deferred.done(process_id);
+16 -30
View File
@@ -9,8 +9,7 @@ define(['utils/utils', 'mvc/ui/ui-misc', 'mvc/tools/tools-form-base', 'mvc/tools
// initialize
initialize: function(options) {
var self = this;
this.job_handler = new ToolJobs(this);
this.buttons = {
options.buttons = {
execute : new Ui.Button({
icon : 'fa-check',
tooltip : 'Execute: ' + options.name,
@@ -18,11 +17,10 @@ define(['utils/utils', 'mvc/ui/ui-misc', 'mvc/tools/tools-form-base', 'mvc/tools
cls : 'btn btn-primary',
floating : 'clear',
onclick : function() {
self.job_handler.submit();
ToolJobs.submit(self.form, options);
}
})
}
options.initial_errors = options.job_id;
};
ToolFormBase.prototype.initialize.call(this, options);
},
@@ -58,10 +56,10 @@ define(['utils/utils', 'mvc/ui/ui-misc', 'mvc/tools/tools-form-base', 'mvc/tools
url : model_url,
success : function(response) {
// build new tool form
self.build(response);
self._buildForm(response);
// notification
self.message.update({
self.form.message.update({
status : 'success',
message : 'Now you are using \'' + self.options.name + '\' version ' + self.options.version + '.',
persistent : false
@@ -84,12 +82,12 @@ define(['utils/utils', 'mvc/ui/ui-misc', 'mvc/tools/tools-form-base', 'mvc/tools
// show error
var error_message = response.error || 'Uncaught error.';
self.modal.show({
self.form.modal.show({
title : 'Tool cannot be executed',
body : error_message,
buttons : {
'Close' : function() {
self.modal.hide();
self.form.modal.hide();
}
}
});
@@ -100,8 +98,11 @@ define(['utils/utils', 'mvc/ui/ui-misc', 'mvc/tools/tools-form-base', 'mvc/tools
/** Request a new model for an already created tool form and updates the form inputs
*/
_updateModel: function(current_state) {
// create the request dictionary
// link this
var self = this;
// create the request dictionary
var form = this.form;
// create the request dictionary
var current_state = {
@@ -110,23 +111,8 @@ define(['utils/utils', 'mvc/ui/ui-misc', 'mvc/tools/tools-form-base', 'mvc/tools
inputs : current_state
}
// activates/disables spinner for dynamic fields to indicate that they are currently being updated
function wait(active) {
for (var i in self.input_list) {
var field = self.field_list[i];
var input = self.input_list[i];
if (input.is_dynamic && field.wait && field.unwait) {
if (active) {
field.wait();
} else {
field.unwait();
}
}
}
}
// set wait mode
wait(true);
form.wait(true);
// register process
var process_id = this.deferred.register();
@@ -145,15 +131,15 @@ define(['utils/utils', 'mvc/ui/ui-misc', 'mvc/tools/tools-form-base', 'mvc/tools
data : current_state,
success : function(new_model) {
// update form
self.tree.matchModel(new_model, function(input_id, node) {
var input = self.input_list[input_id];
form.data.matchModel(new_model, function(input_id, node) {
var input = form.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];
var field = form.field_list[input_id];
if (field.update) {
var new_options = [];
if ((['data', 'data_collection', 'drill_down']).indexOf(input.type) != -1) {
@@ -178,7 +164,7 @@ define(['utils/utils', 'mvc/ui/ui-misc', 'mvc/tools/tools-form-base', 'mvc/tools
});
// unset wait mode
wait(false);
form.wait(false);
// log success
console.debug('tools-form::_refreshForm() - Received new model (see below).');
+43 -50
View File
@@ -1,74 +1,67 @@
/**
This class handles job submissions and the error handling.
This class handles job submissions and validations.
*/
define(['utils/utils', 'mvc/tools/tools-template'], function(Utils, ToolTemplate) {
return Backbone.Model.extend({
// initialize
initialize: function(app) {
this.app = app;
},
/** Creates and submits a job request to the api
*/
submit: function() {
return {
submit: function(form, options) {
// link this
var self = this;
// create job definition for submission to tools api
var job_def = {
tool_id : this.app.options.id,
tool_version : this.app.options.version,
inputs : this.app.tree.finalize()
tool_id : options.id,
tool_version : options.version,
inputs : form.data.create()
}
// reset
this.app.trigger('reset');
form.trigger('reset');
// validate job definition
if (!this._validation(job_def)) {
if (!this._validation(form, job_def)) {
console.debug('tools-jobs::submit - Submission canceled. Validation failed.');
return;
}
// debug
console.debug(job_def);
// show progress modal
var user_is_waiting = true;
this.app.modal.show({title: 'Please wait...', body: 'progress', buttons: {
form.modal.show({title: 'Please wait...', body: 'progress', buttons: {
'Close' : function () {
self.app.modal.hide();
form.modal.hide();
user_is_waiting = false;
}
}});
// post job
Utils.request({
type : 'POST',
url : galaxy_config.root + 'api/tools',
data : job_def,
success : function(response) {
self.app.modal.hide();
self.app.reciept(ToolTemplate.success(response));
form.modal.hide();
form.reciept(ToolTemplate.success(response));
self._refreshHdas();
},
error : function(response, response_full) {
self.app.modal.hide();
form.modal.hide();
if (response && response.message && response.message.data) {
var error_messages = self.app.tree.matchResponse(response.message.data);
var error_messages = form.data.matchResponse(response.message.data);
for (var input_id in error_messages) {
self.app.highlight(input_id, error_messages[input_id]);
form.highlight(input_id, error_messages[input_id]);
break;
}
} else {
// show error message with details
console.debug(response);
user_is_waiting && self.app.modal.show({
user_is_waiting && form.modal.show({
title : 'Job submission failed',
body : ToolTemplate.error(job_def),
buttons : {
'Close' : function() {
self.app.modal.hide();
form.modal.hide();
}
}
});
@@ -76,78 +69,78 @@ return Backbone.Model.extend({
}
});
},
/** Validate job definition
*/
_validation: function(job_def) {
_validation: function(form, job_def) {
// get input parameters
var job_inputs = job_def.inputs;
// counter for values declared in batch mode
var batch_n = -1;
var batch_src = null;
// validation
for (var job_input_id in job_inputs) {
// get current value
var input_value = job_inputs[job_input_id];
// collect input field properties
var input_id = this.app.tree.match(job_input_id);
var input_field = this.app.field_list[input_id];
var input_def = this.app.input_list[input_id];
var input_id = form.data.match(job_input_id);
var input_field = form.field_list[input_id];
var input_def = form.input_list[input_id];
// check if objects where properly identified
if (!input_id || !input_def || !input_field) {
console.debug('tools-jobs::_validation - Retrieving input objects failed.');
continue;
}
// validate non-optional fields
if (!input_def.optional && input_value == null) {
this.app.highlight(input_id);
form.highlight(input_id);
return false;
}
// check if input field is in batch mode
if (input_value && input_value.batch) {
// get values
var n = input_value.values.length;
// get source
var src = null;
if (n > 0) {
src = input_value.values[0] && input_value.values[0].src;
}
// check source type
if (src) {
if (batch_src === null) {
batch_src = src;
} else {
if (batch_src !== src) {
this.app.highlight(input_id, 'Please select either dataset or dataset list fields for all batch mode fields.');
form.highlight(input_id, 'Please select either dataset or dataset list fields for all batch mode fields.');
return false;
}
}
}
// check number of inputs
if (batch_n === -1) {
batch_n = n;
} else {
if (batch_n !== n) {
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>.');
form.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;
}
}
}
}
// return validation result
return true;
},
/** Refreshes the history panel
*/
_refreshHdas: function() {
@@ -155,6 +148,6 @@ return Backbone.Model.extend({
parent.Galaxy.currHistoryPanel.refreshContents();
}
}
});
};
});
+3 -10
View File
@@ -3,14 +3,14 @@ define([], function() {
// tool form templates
return {
help: function(content) {
help: function(options) {
return '<div class="toolHelp" style="overflow: auto;">' +
'<div class="toolHelpBody">' +
content +
options.help +
'</div>' +
'</div>';
},
success: function(response) {
// check
if (!response.jobs || !response.jobs.length) {
@@ -52,13 +52,6 @@ return {
'</div>';
},
batchMode: function() {
return '<div class="ui-table-form-info">' +
'<i class="fa fa-sitemap" style="font-size: 1.2em; padding: 2px 5px;"/>' +
'This is a batch mode input field. A separate job will be triggered for each dataset.' +
'</div>';
},
requirements: function(options) {
var requirements_message = 'This tool requires ';
for (var i in options.requirements) {
@@ -0,0 +1 @@
define(["utils/utils"],function(a){return Backbone.Model.extend({initialize:function(b){this.app=b},checksum:function(){var c="";for(var b in this.app.field_list){var d=this.app.field_list[b];c+=JSON.stringify(d.value&&d.value())}return c},create:function(){var b=this;var f={};this._iterate(this.app.section.$el,f);var e={};this.map_dict={};function d(i,h,g){b.map_dict[i]=h;e[i]=g}function c(o,r){for(var m in r){var j=r[m];if(j.input){var t=j.input;var n=o;if(o!=""){n+="|"}n+=t.name;switch(t.type){case"repeat":var h="section-";var w=[];var q=null;for(var v in j){var p=v.indexOf(h);if(p!=-1){p+=h.length;w.push(parseInt(v.substr(p)));if(!q){q=v.substr(0,p)}}}w.sort(function(x,i){return x-i});var m=0;for(var k in w){c(n+"_"+m++,j[q+w[k]])}break;case"conditional":var u=b.app.field_list[t.id].value();d(n+"|"+t.test_param.name,t.id,u);var g=b.matchCase(t,u);if(g!=-1){c(n,r[t.id+"-section-"+g])}break;case"section":c("",j);break;default:var s=b.app.field_list[t.id];if(s&&s.value){var u=s.value();if(t.ignore===undefined||t.ignore!=u){d(n,t.id,u);if(t.payload){for(var l in t.payload){d(l,t.id,t.payload[l])}}}}}}}}c("",f);return e},match:function(b){return this.map_dict&&this.map_dict[b]},matchCase:function(b,d){if(b.test_param.type=="boolean"){if(d=="true"){d=b.test_param.truevalue||"true"}else{d=b.test_param.falsevalue||"false"}}for(var c in b.cases){if(b.cases[c].value==d){return c}}return -1},matchModel:function(d,f){var b={};var c=this;function e(g,p){for(var m in p){var k=p[m];var n=k.name;if(g!=""){n=g+"|"+n}switch(k.type){case"repeat":for(var l in k.cache){e(n+"_"+l,k.cache[l])}break;case"conditional":var q=k.test_param&&k.test_param.value;var h=c.matchCase(k,q);if(h!=-1){e(n,k.cases[h].inputs)}break;default:var o=c.map_dict[n];if(o){f(o,k)}}}}e("",d.inputs);return b},matchResponse:function(d){var b={};var c=this;function e(l,j){if(typeof j==="string"){var g=c.map_dict[l];if(g){b[g]=j}}else{for(var h in j){var f=h;if(l!==""){var k="|";if(j instanceof Array){k="_"}f=l+k+f}e(f,j[h])}}}e("",d);return b},_iterate:function(d,e){var b=this;var c=$(d).children();c.each(function(){var h=this;var g=$(h).attr("id");if($(h).hasClass("section-row")){e[g]={};var f=b.app.input_list[g];if(f){e[g]={input:f}}b._iterate(h,e[g])}else{b._iterate(h,e)}})}})});
@@ -0,0 +1 @@
define([],function(){return Backbone.View.extend({initialize:function(d,c){this.app=d;this.text_enable=d.options.text_enable||"Enable";this.text_disable=d.options.text_disable||"Disable";this.cls_enable=d.options.cls_enable||"fa fa-plus-square";this.cls_disable=d.options.cls_disable||"fa fa-minus-square";this.field=c.field;this.default_value=c.default_value;this.setElement(this._template(c));this.$field=this.$el.find(".ui-table-form-field");this.$optional=this.$el.find(".ui-table-form-optional");this.$optional_icon=this.$el.find(".ui-table-form-optional").find(".icon");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;var b=this.field.value&&this.field.value();this.field.skip=Boolean(c.optional&&(b===null||b===""||b===this.default_value||String(b)===String(this.default_value)||Number(b)===Number(this.default_value)||JSON.stringify(b)===JSON.stringify(this.default_value)));this._refresh();var a=this;this.$optional.on("click",function(){a.field.skip=!a.field.skip;a._refresh();a.app.trigger("refresh")})},error:function(a){this.$error_text.html(a);this.$error.show();this.$el.addClass("ui-error")},reset:function(){this.$error.hide();this.$el.removeClass("ui-error")},_refresh:function(){this.$optional_icon.removeClass().addClass("icon");if(!this.field.skip){this.$field.fadeIn("fast");this._tooltip(this.text_disable,this.cls_disable)}else{this.$field.hide();this._tooltip(this.text_enable,this.cls_enable);this.field.value&&this.field.value(this.default_value)}},_tooltip:function(b,a){if(this.$optional.length){this.$optional_icon.addClass(a).tooltip({placement:"bottom"}).attr("data-original-title",b).tooltip("fixTitle").tooltip("hide")}},_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">';if(a.optional){b+='<div class="ui-table-form-optional"><i class="icon"/>'+a.label+"</div>"}else{b+=a.label}b+='</div><div class="ui-table-form-field">';b+='<div class="ui-table-form-info">';if(a.help){b+=a.help}b+="</div>";b+="</div></div>";return b}})});
@@ -0,0 +1 @@
define(["utils/utils","mvc/ui/ui-misc","mvc/form/form-select-content","mvc/ui/ui-color-picker"],function(c,d,a,b){return Backbone.Model.extend({types:{text:"_fieldText",select:"_fieldSelect",data_column:"_fieldSelect",genomebuild:"_fieldSelect",data:"_fieldData",data_collection:"_fieldData",integer:"_fieldSlider","float":"_fieldSlider","boolean":"_fieldBoolean",drill_down:"_fieldDrilldown",color:"_fieldColor",hidden:"_fieldHidden",hidden_data:"_fieldHidden",baseurl:"_fieldHidden"},initialize:function(f,e){this.app=f},create:function(e){if(e.value===undefined){e.value=null}if(e.default_value===undefined){e.default_value=e.value}var g=null;var f=this.types[e.type];if(f&&typeof(this[f])==="function"){g=this[f].call(this,e)}if(!g){this.app.incompatible=true;if(e.options){g=this._fieldSelect(e)}else{g=this._fieldText(e)}console.debug("tools-form::_addRow() : Auto matched field type ("+e.type+").")}if(e.value!==undefined){g.value(e.value)}return g},_fieldData:function(e){if(!this.app.options.is_dynamic){e.info="Data input '"+e.name+"' ("+c.textify(e.extensions.toString())+")";e.value=null;return this._fieldHidden(e)}var f=this;return new a.View(this.app,{id:"field-"+e.id,extensions:e.extensions,optional:e.optional,multiple:e.multiple,type:e.type,data:e.options,onchange:function(){f.app.trigger("change")}})},_fieldSelect:function(e){if(!this.app.options.is_dynamic&&e.is_dynamic){return this._fieldText(e)}if(e.type=="data_column"){e.error_text="Missing columns in referenced dataset."}if(e.type=="genomebuild"){e.searchable=true}var g=[];for(var h in e.options){var j=e.options[h];g.push({label:j[0],value:j[1]})}var k=d.Select;switch(e.display){case"checkboxes":k=d.Checkbox;break;case"radio":k=d.Radio;break}var f=this;return new k.View({id:"field-"+e.id,data:g,error_text:e.error_text||"No options available",multiple:e.multiple,searchable:e.searchable,onchange:function(){f.app.trigger("change")}})},_fieldDrilldown:function(e){if(!this.app.options.is_dynamic&&e.is_dynamic){return this._fieldText(e)}var f=this;return new d.Drilldown.View({id:"field-"+e.id,data:e.options,display:e.display,onchange:function(){f.app.trigger("change")}})},_fieldText:function(e){if(e.options){e.area=e.multiple;if(!c.validate(e.value)){e.value=""}else{if(e.value instanceof Array){e.value=value.toString()}else{e.value=String(e.value).replace(/[\[\]'"\s]/g,"");if(e.multiple){e.value=e.value.replace(/,/g,"\n")}}}}var f=this;return new d.Input({id:"field-"+e.id,area:e.area,onchange:function(){f.app.trigger("change")}})},_fieldSlider:function(e){var f=this;return new d.Slider.View({id:"field-"+e.id,precise:e.type=="float",min:e.min,max:e.max,onchange:function(){f.app.trigger("change")}})},_fieldHidden:function(e){return new d.Hidden({id:"field-"+e.id,info:e.info})},_fieldBoolean:function(e){var f=this;return new d.RadioButton.View({id:"field-"+e.id,data:[{label:"Yes",value:"true"},{label:"No",value:"false"}],onchange:function(){f.app.trigger("change")}})},_fieldColor:function(e){var f=this;return new b({id:"field-"+e.id,onchange:function(){f.app.trigger("change")}})}});return{View:View}});
@@ -0,0 +1 @@
define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-portlet","mvc/ui/ui-misc"],function(c,a,b,e){var d=Backbone.View.extend({optionsDefault:{title:"Section",max:null,min:null},initialize:function(g){this.options=c.merge(g,this.optionsDefault);this.setElement("<div/>");var f=this;this.button_new=new e.ButtonIcon({icon:"fa-plus",title:"Insert "+g.title_new,tooltip:"Add new "+g.title_new+" block",floating:"clear",onclick:function(){if(g.onnew){g.onnew()}}});this.table=new a.View({cls:"ui-table-plain",content:""});this.$el.append(this.table.$el);this.$el.append($("<div/>").append(this.button_new.$el));this.list={};this.n=0},size:function(){return this.n},add:function(g){if(!g.id||this.list[g.id]){console.debug("form-repeat::add - Duplicate repeat block id.");return}this.n++;var f=new e.ButtonIcon({icon:"fa-trash-o",tooltip:"Delete this repeat block",cls:"ui-button-icon-plain",onclick:function(){if(g.ondel){g.ondel()}}});var h=new b.View({id:g.id,title:"placeholder",cls:"ui-portlet-repeat",operations:{button_delete:f}});h.append(g.$el);h.$el.addClass("section-row");this.list[g.id]=h;this.table.add(h.$el);this.table.append("row_"+g.id,true);if(this.options.max>0&&this.n>=this.options.max){this.button_new.disable()}this._refresh()},del:function(g){if(!this.list[g]){console.debug("form-repeat::del - Invalid repeat block id.");return}this.n--;var f=this.table.get("row_"+g);f.remove();delete this.list[g];this.button_new.enable();this._refresh()},_refresh:function(){var f=0;for(var h in this.list){var g=this.list[h];g.title(++f+": "+this.options.title);if(this.n>this.options.min){g.showOperation("button_delete")}else{g.hideOperation("button_delete")}}}});return{View:d}});
@@ -0,0 +1 @@
define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/ui/ui-portlet","mvc/form/form-repeat","mvc/form/form-input","mvc/form/form-parameters"],function(e,a,h,d,c,f,b){var g=Backbone.View.extend({initialize:function(j,i){this.app=j;this.inputs=i.inputs;i.cls="ui-table-plain";i.cls_tr="section-row";this.table=new a.View(i);this.parameters=new b(j,i);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();for(var j in this.inputs){this.add(this.inputs[j])}},add:function(k){var j=this;var i=jQuery.extend(true,{},k);i.id=k.id=e.uuid();this.app.input_list[i.id]=i;var l=i.type;switch(l){case"conditional":this._addConditional(i);break;case"repeat":this._addRepeat(i);break;case"section":this._addSection(i);break;default:this._addRow(i)}},_addConditional:function(j){var k=this;j.test_param.id=j.id;var n=this._addRow(j.test_param);n.options.onchange=function(w){var v=k.app.data.matchCase(j,w);for(var u in j.cases){var q=j.cases[u];var t=j.id+"-section-"+u;var p=k.table.get(t);var s=false;for(var r in q.inputs){if(!q.inputs[r].hidden){s=true;break}}if(u==v&&s){p.fadeIn("fast")}else{p.hide()}}k.app.trigger("change")};for(var m in j.cases){var l=j.id+"-section-"+m;var o=new g(this.app,{inputs:j.cases[m].inputs});o.$el.addClass("ui-table-section");this.table.add(o.$el);this.table.append(l)}n.trigger("change")},_addRepeat:function(p){var s=this;var q=0;var l=new c.View({title:p.title,title_new:p.title,min:p.min,max:p.max,onnew:function(){n(p.inputs);s.app.trigger("change")}});function n(i){var t=p.id+"-section-"+(q++);var u=new g(s.app,{inputs:i});l.add({id:t,$el:u.$el,ondel:function(){l.del(t);s.app.trigger("change")}})}var j=p.min;var r=_.size(p.cache);for(var m=0;m<Math.max(r,j);m++){var o=null;if(m<r){o=p.cache[m]}else{o=p.inputs}n(o)}var k=new f(this.app,{label:p.title,help:p.help,field:l});this.table.add(k.$el);this.table.append(p.id)},_addSection:function(i){var j=this;var n=new g(j.app,{inputs:i.inputs});var m=new h.ButtonIcon({icon:"fa-eye-slash",tooltip:"Show/hide section",cls:"ui-button-icon-plain"});var l=new d.View({title:i.label,cls:"ui-portlet-section",operations:{button_visible:m}});l.append(n.$el);l.append($("<div/>").addClass("ui-table-form-info").html(i.help));var k=false;l.$content.hide();l.$header.css("cursor","pointer");l.$header.on("click",function(){if(k){k=false;l.$content.hide();m.setIcon("fa-eye-slash")}else{k=true;l.$content.fadeIn("fast");m.setIcon("fa-eye")}});if(i.expand){l.$header.trigger("click")}this.table.add(l.$el);this.table.append(i.id)},_addRow:function(i){var l=i.id;var j=this.parameters.create(i);this.app.field_list[l]=j;var k=new f(this.app,{label:i.label,default_value:i.default_value,optional:i.optional,help:i.help,field:j});this.app.element_list[l]=k;this.table.add(k.$el);this.table.append(l);if(i.hidden){this.table.get(l).hide()}return j}});return{View:g}});
@@ -0,0 +1 @@
define(["utils/utils","mvc/ui/ui-misc","mvc/ui/ui-tabs","mvc/tools/tools-template"],function(c,e,b,a){history={};var d=Backbone.View.extend({initialize:function(g,p){this.app=g;this.options=p;var o=this;this.setElement('<div class="ui-select-content"/>');this.list={};var m=[];if(p.type=="data_collection"){this.mode="collection"}else{if(p.multiple){this.mode="multiple"}else{this.mode="single"}}this.current=this.mode;this.list={};var k=c.textify(p.extensions);var j="No dataset available.";if(k){j="No "+k+" dataset available."}var l="No dataset list available.";if(k){l="No "+k+" dataset collection available."}if(this.mode=="single"){m.push({icon:"fa-file-o",value:"single",tooltip:"Single dataset"});this.select_single=new e.Select.View({optional:p.optional,error_text:j,onchange:function(){o.trigger("change")}});this.list.single={field:this.select_single,type:"hda"}}if(this.mode=="single"||this.mode=="multiple"){m.push({icon:"fa-files-o",value:"multiple",tooltip:"Multiple datasets"});this.select_multiple=new e.Select.View({multiple:true,searchable:false,error_text:j,onchange:function(){o.trigger("change")}});this.list.multiple={field:this.select_multiple,type:"hda"}}if(this.mode=="single"||this.mode=="multiple"||this.mode=="collection"){m.push({icon:"fa-folder-o",value:"collection",tooltip:"Dataset collection"});this.select_collection=new e.Select.View({error_text:l,optional:p.optional,onchange:function(){o.trigger("change")}});this.list.collection={field:this.select_collection,type:"hdca"}}this.button_type=new e.RadioButton.View({value:this.current,data:m,onchange:function(i){o.current=i;o.refresh();o.trigger("change")}});this.$batch=$(this.template_batch());var f=_.size(this.list);var n=0;if(f>1){this.$el.append(this.button_type.$el);n=Math.max(0,_.size(this.list)*35)+"px"}for(var h in this.list){this.$el.append(this.list[h].field.$el.css({"margin-left":n}))}this.$el.append(this.$batch.css({"margin-left":n}));this.update(p.data);if(this.options.value!==undefined){this.value(this.options.value)}this.refresh();this.on("change",function(){if(p.onchange){p.onchange(o.value())}})},wait:function(){for(var f in this.list){this.list[f].field.wait()}},unwait:function(){for(var f in this.list){this.list[f].field.unwait()}},update:function(h){var f=this;function g(m,j){if(m){var n=[];for(var k in j){var l=j[k];n.push({label:l.hid+": "+l.name,value:l.id});history[l.id+"_"+l.src]=l}m.update(n)}}g(this.select_single,h.hda);g(this.select_multiple,h.hda);g(this.select_collection,h.hdca)},value:function(j){if(j!==undefined){if(j&&j.values){try{var m=[];for(var h in j.values){m.push(j.values[h].id)}if(j&&j.values.length>0&&j.values[0].src=="hcda"){this.current="collection";this.select_collection.value(m[0])}else{if(this.mode=="multiple"){this.current="multiple";this.select_multiple.value(m)}else{this.current="single";this.select_single.value(m[0])}}}catch(l){console.debug("tools-select-content::value() - Skipped.")}}else{for(var h in this.list){this.list[h].field.value(null)}}}this.refresh();var k=this._select().value();if(k===null){return null}if(!(k instanceof Array)){k=[k]}if(k.length===0){return null}var f={batch:this._batch(),values:[]};for(var h in k){var g=_.findWhere(history,{id:k[h],src:this.list[this.current].type});if(g){f.values.push(g)}else{return null}}f.values.sort(function(n,i){return n.hid-i.hid});return f},refresh:function(){this.button_type.value(this.current);for(var g in this.list){var f=this.list[g].field.$el;if(this.current==g){f.show()}else{f.hide()}}if(this._batch()){this.$batch.show()}else{this.$batch.hide()}},_select:function(){return this.list[this.current].field},_batch:function(){if(this.current=="collection"){var f=_.findWhere(history,{id:this._select().value(),src:"hdca"});if(f&&f.map_over_type){return true}}if(this.current!="single"){if(this.mode=="single"){return true}}return false},template_batch:function(){return'<div class="ui-table-form-info"><i class="fa fa-sitemap" style="font-size: 1.2em; padding: 2px 5px;"/>This is a batch mode input field. A separate job will be triggered for each dataset.</div>'}});return{View:d}});
@@ -0,0 +1 @@
define(["utils/utils","mvc/ui/ui-portlet","mvc/ui/ui-misc","mvc/form/form-section","mvc/form/form-data"],function(c,b,e,a,d){return Backbone.View.extend({initialize:function(f){this.optionsDefault={is_dynamic:true,narrow:false,initial_errors:false,cls:"ui-portlet-limited"};this.options=c.merge(f,this.optionsDefault);console.debug(this.options);var g=parent.Galaxy;if(g&&g.modal){this.modal=g.modal}else{this.modal=new e.Modal.View()}this.setElement("<div/>");this._build()},wait:function(j){for(var g in this.input_list){var h=this.field_list[g];var f=this.input_list[g];if(f.is_dynamic&&h.wait&&h.unwait){if(j){h.wait()}else{h.unwait()}}}},reciept:function(f){this.$el.empty();this.$el.append(f)},highlight:function(g,h,f){var i=this.element_list[g];if(i){i.error(h||"Please verify this parameter.");if(!f){$("html, body").animate({scrollTop:i.$el.offset().top-20},500)}}},errors:function(h){this.trigger("reset");if(h&&h.errors){var i=this.data.matchResponse(h.errors);for(var g in this.element_list){var f=this.element_list[g];if(i[g]){this.highlight(g,i[g],true)}}}},_build:function(){var f=this;this.off("change");this.off("reset");this.field_list={};this.input_list={};this.element_list={};this.data=new d(this);this._renderForm();this.data.create();if(this.options.initial_errors){this.errors(this.options)}var g=this.data.checksum();this.on("change",function(){var h=f.data.checksum();if(h!=g){g=h;f.options.onchange&&f.options.onchange()}});this.on("reset",function(){for(var h in this.element_list){this.element_list[h].reset()}})},_renderForm:function(){this.message=new e.Message();this.section=new a.View(this,{inputs:this.options.inputs});this.portlet=new b.View({icon:"fa-wrench",title:this.options.title,cls:this.options.cls,operations:this.options.operations,buttons:this.options.buttons});this.portlet.append(this.message.$el.addClass("ui-margin-top"));this.portlet.append(this.section.$el);this.$el.empty();this.$el.append(this.portlet.$el);if(this.options.message){this.message.update({persistent:true,status:"warning",message:this.options.message})}console.debug("tools-form-base::initialize() - Completed.")}})});
@@ -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-section","mvc/tools/tools-tree"],function(f,g,e,j,h,a,d,c,i,b){return Backbone.View.extend({initialize:function(k){this.optionsDefault={is_dynamic:true,narrow:false,initial_errors:false,cls_portlet:"ui-portlet-limited"};this.options=f.merge(k,this.optionsDefault);console.debug(this.options);var l=parent.Galaxy;if(l&&l.modal){this.modal=l.modal}else{this.modal=new j.Modal.View()}if(l&&l.currUser){this.is_admin=l.currUser.get("is_admin")}else{this.is_admin=false}this.container=this.options.container||"body";this.deferred=new g();this.setElement("<div/>");$(this.container).append(this.$el);this.build(this.options)},build:function(m){var k=this;this.off("refresh");this.off("reset");this.field_list={};this.input_list={};this.element_list={};this.tree=new b(this);this.history={};k.options.inputs=m&&m.inputs;this._renderForm(m);var l=this.tree.finalize();if(m.initial_errors){this._errors(m)}this.on("refresh",function(){k.deferred.reset();k.deferred.execute(function(){var n=k.tree.finalize();if(!_.isEqual(n,l)){l=n;k._updateModel($.extend(true,{},l))}})});this.on("reset",function(){for(var n in this.element_list){this.element_list[n].reset()}})},reciept:function(k){$(this.container).empty();$(this.container).append(k)},highlight:function(l,m,k){var n=this.element_list[l];if(n){n.error(m||"Please verify this parameter.");if(!k){$("html, body").animate({scrollTop:n.$el.offset().top-20},500)}}},_errors:function(m){this.trigger("reset");if(m&&m.errors){var n=this.tree.matchResponse(m.errors);for(var l in this.element_list){var k=this.element_list[l];if(n[l]){this.highlight(l,n[l],true)}}}},_renderForm:function(s){var r=this;this.message=new j.Message();var l=new j.ButtonMenu({icon:"fa-cubes",title:(!s.narrow&&"Versions")||null,tooltip:"Select another tool version"});if(s.versions&&s.versions.length>1){for(var n in s.versions){var p=s.versions[n];if(p!=s.version){l.addMenu({title:"Switch to "+p,version:p,icon:"fa-cube",onclick:function(){r.options.id=r.options.id.replace(r.options.version,this.version);r.options.version=this.version;r.deferred.reset();r.deferred.execute(function(){r._buildModel()})}})}}}else{l.$el.hide()}var o=new j.ButtonMenu({icon:"fa-caret-down",title:(!s.narrow&&"Options")||null,tooltip:"View available options"});if(s.biostar_url){o.addMenu({icon:"fa-question-circle",title:"Question?",tooltip:"Ask a question about this tool (Biostar)",onclick:function(){window.open(s.biostar_url+"/p/new/post/")}});o.addMenu({icon:"fa-search",title:"Search",tooltip:"Search help for this tool (Biostar)",onclick:function(){window.open(s.biostar_url+"/local/search/page/?q="+s.name)}})}o.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="+s.id)}});if(this.is_admin){o.addMenu({icon:"fa-download",title:"Download",tooltip:"Download this tool",onclick:function(){window.location.href=galaxy_config.root+"api/tools/"+s.id+"/download"}})}if(s.requirements&&s.requirements.length>0){o.addMenu({icon:"fa-info-circle",title:"Requirements",tooltip:"Display tool requirements",onclick:function(){if(!this.visible){this.visible=true;r.message.update({persistent:true,message:c.requirements(s),status:"info"})}else{this.visible=false;r.message.update({message:""})}}})}if(this.options.sharable_url){o.addMenu({icon:"fa-external-link",title:"See in Tool Shed",tooltip:"Access the repository",onclick:function(){window.open(r.options.sharable_url)}})}this.section=new i.View(r,{inputs:s.inputs});if(this.incompatible){this.$el.hide();$("#tool-form-classic").show();return}this.portlet=new e.View({icon:"fa-wrench",title:"<b>"+s.name+"</b> "+s.description+" (Galaxy Tool Version "+s.version+")",cls:this.options.cls_portlet,operations:{menu:o,versions:l},buttons:this.buttons});this.portlet.append(this.message.$el.addClass("ui-margin-top"));this.portlet.append(this.section.$el);this.$el.empty();this.$el.append(this.portlet.$el);if(s.help!=""){this.$el.append(c.help(s.help))}if(s.citations){var q=$("<div/>");var k=new h.ToolCitationCollection();k.tool_id=s.id;var m=new a.CitationListView({el:q,collection:k});m.render();k.fetch();this.$el.append(q)}if(s.message){this.message.update({persistent:true,status:"warning",message:s.message})}console.debug("tools-form-base::initialize() - Completed.")}})});
define(["utils/utils","utils/deferred","mvc/ui/ui-misc","mvc/form/form-view","mvc/tools/tools-template","mvc/citation/citation-model","mvc/citation/citation-view"],function(f,d,g,c,a,e,b){return Backbone.View.extend({initialize:function(h){var i=parent.Galaxy;if(i&&i.currUser){this.is_admin=i.currUser.get("is_admin")}else{this.is_admin=false}this.deferred=new d();this.setElement("<div/>");this.container=h.container||"body";$(this.container).append(this.$el);this._buildForm(h)},_buildForm:function(i){var h=this;this.options=f.merge(i,this.optionsDefault);var j=f.merge({icon:"fa-wrench",title:"<b>"+i.name+"</b> "+i.description+" (Galaxy Tool Version "+i.version+")",operations:this._operations(),onchange:function(k){h.deferred.reset();h.deferred.execute(function(){h._updateModel($.extend(true,{},h.form.data.create()))})}},i);this.form=new c(j);this._footer();this.$el.empty();this.$el.append(this.form.$el)},_operations:function(){var j=this;var k=j.options;var n=new g.ButtonMenu({icon:"fa-cubes",title:(!k.narrow&&"Versions")||null,tooltip:"Select another tool version"});if(k.versions&&k.versions.length>1){for(var m in k.versions){var h=k.versions[m];if(h!=k.version){n.addMenu({title:"Switch to "+h,version:h,icon:"fa-cube",onclick:function(){k.id=k.id.replace(k.version,this.version);k.version=this.version;j.deferred.reset();j.deferred.execute(function(){j._buildModel()})}})}}}else{n.$el.hide()}var l=new g.ButtonMenu({icon:"fa-caret-down",title:(!k.narrow&&"Options")||null,tooltip:"View available options"});if(k.biostar_url){l.addMenu({icon:"fa-question-circle",title:"Question?",tooltip:"Ask a question about this tool (Biostar)",onclick:function(){window.open(k.biostar_url+"/p/new/post/")}});l.addMenu({icon:"fa-search",title:"Search",tooltip:"Search help for this tool (Biostar)",onclick:function(){window.open(k.biostar_url+"/local/search/page/?q="+k.name)}})}l.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="+k.id)}});if(j.is_admin){l.addMenu({icon:"fa-download",title:"Download",tooltip:"Download this tool",onclick:function(){window.location.href=galaxy_config.root+"api/tools/"+k.id+"/download"}})}if(k.requirements&&k.requirements.length>0){l.addMenu({icon:"fa-info-circle",title:"Requirements",tooltip:"Display tool requirements",onclick:function(){if(!this.visible){this.visible=true;j.form.message.update({persistent:true,message:a.requirements(k),status:"info"})}else{this.visible=false;j.form.message.update({message:""})}}})}if(k.sharable_url){l.addMenu({icon:"fa-external-link",title:"See in Tool Shed",tooltip:"Access the repository",onclick:function(){window.open(k.sharable_url)}})}return{menu:l,versions:n}},_footer:function(){var i=this.options;if(i.help!=""){this.form.$el.append(a.help(i))}if(i.citations){var k=$("<div/>");var h=new e.ToolCitationCollection();h.tool_id=i.id;var j=new b.CitationListView({el:k,collection:h});j.render();h.fetch();this.form.$el.append(k)}}})});
@@ -1 +1 @@
define(["utils/utils","mvc/tools/tools-form-base"],function(b,a){var c=a.extend({initialize:function(e){this.node=workflow.active_node;if(!this.node){console.debug("FAILED - tools-form-workflow:initialize() - Node not found in workflow.");return}this.post_job_actions=this.node.post_job_actions||{};this.options=e;this.options.text_enable="Set in Advance";this.options.text_disable="Set at Runtime";this.options.is_dynamic=false;this.options.narrow=true;this.options.initial_errors=true;this.options.cls_portlet="ui-portlet-narrow";b.deepeach(e.inputs,function(f){if(f.type){f.optional=(["data","data_hidden","hidden","repeat","conditional"]).indexOf(f.type)==-1}});b.deepeach(e.inputs,function(f){if(f.type){if(f.type=="conditional"){f.test_param.optional=false}}});var d=this;b.get({url:galaxy_config.root+"api/datatypes",cache:true,success:function(f){d.datatypes=f;d._makeSections(e.inputs);a.prototype.initialize.call(d,e)}})},_makeSections:function(d){d[b.uuid()]={label:"Annotation / Notes",name:"annotation",type:"text",area:true,help:"Add an annotation or note for this step. It will be shown with the workflow.",value:this.node.annotation};var f=this.node.output_terminals&&Object.keys(this.node.output_terminals)[0];if(f){d[b.uuid()]={name:"pja__"+f+"__EmailAction",label:"Email notification",type:"boolean",value:String(Boolean(this.post_job_actions["EmailAction"+f])),ignore:"false",help:"An email notification will be send when the job has completed.",payload:{host:window.location.host}};d[b.uuid()]={name:"pja__"+f+"__DeleteIntermediatesAction",label:"Output cleanup",type:"boolean",value:String(Boolean(this.post_job_actions["DeleteIntermediatesAction"+f])),ignore:"false",help:"Delete intermediate outputs if they are not used as input for another job."};for(var e in this.node.output_terminals){d[b.uuid()]=this._makeSection(e)}}},_makeSection:function(h){var g=[];for(key in this.datatypes){g.push({0:this.datatypes[key],1:this.datatypes[key]})}g.sort(function(j,i){return j.label>i.label?1:j.label<i.label?-1:0});g.unshift({0:"Sequences",1:"Sequences"});g.unshift({0:"Roadmaps",1:"Roadmaps"});g.unshift({0:"Leave unchanged",1:"__empty__"});var f={label:"Add Actions: '"+h+"'",type:"section",inputs:[{action:"RenameDatasetAction",argument:"newname",label:"Rename dataset",type:"text",value:"",ignore:"",help:'This action will rename the result dataset. Click <a href="https://wiki.galaxyproject.org/Learn/AdvancedWorkflow/Variables">here</a> for more information.'},{action:"ChangeDatatypeAction",argument:"newtype",label:"Change datatype",type:"select",ignore:"__empty__",value:"__empty__",options:g,help:"This action will change the datatype of the output to the indicated value."},{action:"TagDatasetAction",argument:"tags",label:"Tags",type:"text",value:"",ignore:"",help:"This action will set tags for the dataset."},{label:"Assign columns",type:"section",inputs:[{action:"ColumnSetAction",argument:"chromCol",label:"Chrom column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"startCol",label:"Start column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"endCol",label:"End column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"strandCol",label:"Strand column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"nameCol",label:"Name column",type:"integer",value:"",ignore:""}],help:"This action will set column assignments in the output dataset. Blank fields are ignored."}]};var d=this;function e(n,o){o=o||[];o.push(n);for(var m in n.inputs){var k=n.inputs[m];if(k.action){k.name="pja__"+h+"__"+k.action;if(k.argument){k.name+="__"+k.argument}if(k.payload){for(var s in k.payload){var q=k.payload[s];k.payload[k.name+"__"+s]=q;delete q}}var r=d.post_job_actions[k.action+h];if(r){for(var l in o){o[l].expand=true}if(k.argument){k.value=r.action_arguments&&r.action_arguments[k.argument]||k.value}else{k.value="true"}}}if(k.inputs){e(k,o.slice(0))}}}e(f);return f},_buildModel:function(){Galaxy.modal.show({title:"Coming soon...",body:"This feature has not been implemented yet.",buttons:{Close:function(){Galaxy.modal.hide()}}})},_updateModel:function(e){var d=this;e={tool_id:this.options.id,tool_version:this.options.version,inputs:e};console.debug("tools-form-workflow::_refreshForm() - Refreshing states.");console.debug(e);var g=this.deferred.register();var f=galaxy_config.root+"api/workflows/build_module";b.request({type:"POST",url:f,data:e,success:function(h){d.node.update_field_data(h);d._errors(h&&h.tool_model);d.deferred.done(g);console.debug("tools-form::_refreshForm() - States refreshed.");console.debug(h)},error:function(h){d.deferred.done(g);console.debug("tools-form::_refreshForm() - Refresh request failed.");console.debug(h)}})}});return{View:c}});
define(["utils/utils","mvc/tools/tools-form-base"],function(b,a){var c=a.extend({initialize:function(e){this.node=workflow.active_node;if(!this.node){console.debug("FAILED - tools-form-workflow:initialize() - Node not found in workflow.");return}this.post_job_actions=this.node.post_job_actions||{};this.options=e;this.options.text_enable="Set in Advance";this.options.text_disable="Set at Runtime";this.options.is_dynamic=false;this.options.narrow=true;this.options.initial_errors=true;this.options.cls_portlet="ui-portlet-narrow";b.deepeach(e.inputs,function(f){if(f.type){f.optional=(["data","data_hidden","hidden","repeat","conditional"]).indexOf(f.type)==-1}});b.deepeach(e.inputs,function(f){if(f.type){if(f.type=="conditional"){f.test_param.optional=false}}});var d=this;b.get({url:galaxy_config.root+"api/datatypes",cache:true,success:function(f){d.datatypes=f;d._makeSections(e.inputs);a.prototype.initialize.call(d,e)}})},_makeSections:function(d){d[b.uuid()]={label:"Annotation / Notes",name:"annotation",type:"text",area:true,help:"Add an annotation or note for this step. It will be shown with the workflow.",value:this.node.annotation};var f=this.node.output_terminals&&Object.keys(this.node.output_terminals)[0];if(f){d[b.uuid()]={name:"pja__"+f+"__EmailAction",label:"Email notification",type:"boolean",value:String(Boolean(this.post_job_actions["EmailAction"+f])),ignore:"false",help:"An email notification will be send when the job has completed.",payload:{host:window.location.host}};d[b.uuid()]={name:"pja__"+f+"__DeleteIntermediatesAction",label:"Output cleanup",type:"boolean",value:String(Boolean(this.post_job_actions["DeleteIntermediatesAction"+f])),ignore:"false",help:"Delete intermediate outputs if they are not used as input for another job."};for(var e in this.node.output_terminals){d[b.uuid()]=this._makeSection(e)}}},_makeSection:function(h){var g=[];for(key in this.datatypes){g.push({0:this.datatypes[key],1:this.datatypes[key]})}g.sort(function(j,i){return j.label>i.label?1:j.label<i.label?-1:0});g.unshift({0:"Sequences",1:"Sequences"});g.unshift({0:"Roadmaps",1:"Roadmaps"});g.unshift({0:"Leave unchanged",1:"__empty__"});var f={label:"Add Actions: '"+h+"'",type:"section",inputs:[{action:"RenameDatasetAction",argument:"newname",label:"Rename dataset",type:"text",value:"",ignore:"",help:'This action will rename the result dataset. Click <a href="https://wiki.galaxyproject.org/Learn/AdvancedWorkflow/Variables">here</a> for more information.'},{action:"ChangeDatatypeAction",argument:"newtype",label:"Change datatype",type:"select",ignore:"__empty__",value:"__empty__",options:g,help:"This action will change the datatype of the output to the indicated value."},{action:"TagDatasetAction",argument:"tags",label:"Tags",type:"text",value:"",ignore:"",help:"This action will set tags for the dataset."},{label:"Assign columns",type:"section",inputs:[{action:"ColumnSetAction",argument:"chromCol",label:"Chrom column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"startCol",label:"Start column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"endCol",label:"End column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"strandCol",label:"Strand column",type:"integer",value:"",ignore:""},{action:"ColumnSetAction",argument:"nameCol",label:"Name column",type:"integer",value:"",ignore:""}],help:"This action will set column assignments in the output dataset. Blank fields are ignored."}]};var d=this;function e(n,o){o=o||[];o.push(n);for(var m in n.inputs){var k=n.inputs[m];if(k.action){k.name="pja__"+h+"__"+k.action;if(k.argument){k.name+="__"+k.argument}if(k.payload){for(var s in k.payload){var q=k.payload[s];k.payload[k.name+"__"+s]=q;delete q}}var r=d.post_job_actions[k.action+h];if(r){for(var l in o){o[l].expand=true}if(k.argument){k.value=r.action_arguments&&r.action_arguments[k.argument]||k.value}else{k.value="true"}}}if(k.inputs){e(k,o.slice(0))}}}e(f);return f},_buildModel:function(){Galaxy.modal.show({title:"Coming soon...",body:"This feature has not been implemented yet.",buttons:{Close:function(){Galaxy.modal.hide()}}})},_updateModel:function(e){var d=this;e={tool_id:this.options.id,tool_version:this.options.version,inputs:e};console.debug("tools-form-workflow::_refreshForm() - Refreshing states.");console.debug(e);var g=this.deferred.register();var f=galaxy_config.root+"api/workflows/build_module";b.request({type:"POST",url:f,data:e,success:function(h){d.node.update_field_data(h);d.form.errors(h&&h.tool_model);d.deferred.done(g);console.debug("tools-form::_refreshForm() - States refreshed.");console.debug(h)},error:function(h){d.deferred.done(g);console.debug("tools-form::_refreshForm() - Refresh request failed.");console.debug(h)}})}});return{View:c}});
@@ -1 +1 @@
define(["utils/utils","mvc/ui/ui-misc","mvc/tools/tools-form-base","mvc/tools/tools-jobs"],function(c,e,b,a){var d=b.extend({initialize:function(g){var f=this;this.job_handler=new a(this);this.buttons={execute:new e.Button({icon:"fa-check",tooltip:"Execute: "+g.name,title:"Execute",cls:"btn btn-primary",floating:"clear",onclick:function(){f.job_handler.submit()}})};g.initial_errors=g.job_id;b.prototype.initialize.call(this,g)},_buildModel:function(){var f=this;var g=galaxy_config.root+"api/tools/"+this.options.id+"/build?";if(this.options.job_id){g+="job_id="+this.options.job_id}else{if(this.options.dataset_id){g+="dataset_id="+this.options.dataset_id}else{g+="tool_version="+this.options.version+"&";var i=top.location.href;var j=i.indexOf("?");if(i.indexOf("tool_id=")!=-1&&j!==-1){g+=i.slice(j+1)}}}var h=this.deferred.register();c.request({type:"GET",url:g,success:function(k){f.build(k);f.message.update({status:"success",message:"Now you are using '"+f.options.name+"' version "+f.options.version+".",persistent:false});f.deferred.done(h);console.debug("tools-form::initialize() - Initial tool model ready.");console.debug(k)},error:function(k){f.deferred.done(h);console.debug("tools-form::initialize() - Initial tool model request failed.");console.debug(k);var l=k.error||"Uncaught error.";f.modal.show({title:"Tool cannot be executed",body:l,buttons:{Close:function(){f.modal.hide()}}})}})},_updateModel:function(g){var f=this;var g={tool_id:this.options.id,tool_version:this.options.version,inputs:g};function j(n){for(var l in f.input_list){var m=f.field_list[l];var k=f.input_list[l];if(k.is_dynamic&&m.wait&&m.unwait){if(n){m.wait()}else{m.unwait()}}}}j(true);var i=this.deferred.register();console.debug("tools-form::_refreshForm() - Sending current state (see below).");console.debug(g);var h=galaxy_config.root+"api/tools/"+this.options.id+"/build";c.request({type:"POST",url:h,data:g,success:function(k){f.tree.matchModel(k,function(m,q){var l=f.input_list[m];if(l&&l.options){if(!_.isEqual(l.options,q.options)){l.options=q.options;var r=f.field_list[m];if(r.update){var p=[];if((["data","data_collection","drill_down"]).indexOf(l.type)!=-1){p=l.options}else{for(var o in q.options){var n=q.options[o];if(n.length>2){p.push({label:n[0],value:n[1]})}}}r.update(p);r.trigger("change");console.debug("Updating options for "+m)}}}});j(false);console.debug("tools-form::_refreshForm() - Received new model (see below).");console.debug(k);f.deferred.done(i)},error:function(k){f.deferred.done(i);console.debug("tools-form::_refreshForm() - Refresh request failed.");console.debug(k)}})}});return{View:d}});
define(["utils/utils","mvc/ui/ui-misc","mvc/tools/tools-form-base","mvc/tools/tools-jobs"],function(c,e,b,a){var d=b.extend({initialize:function(g){var f=this;g.buttons={execute:new e.Button({icon:"fa-check",tooltip:"Execute: "+g.name,title:"Execute",cls:"btn btn-primary",floating:"clear",onclick:function(){a.submit(f.form,g)}})};b.prototype.initialize.call(this,g)},_buildModel:function(){var f=this;var g=galaxy_config.root+"api/tools/"+this.options.id+"/build?";if(this.options.job_id){g+="job_id="+this.options.job_id}else{if(this.options.dataset_id){g+="dataset_id="+this.options.dataset_id}else{g+="tool_version="+this.options.version+"&";var i=top.location.href;var j=i.indexOf("?");if(i.indexOf("tool_id=")!=-1&&j!==-1){g+=i.slice(j+1)}}}var h=this.deferred.register();c.request({type:"GET",url:g,success:function(k){f._buildForm(k);f.form.message.update({status:"success",message:"Now you are using '"+f.options.name+"' version "+f.options.version+".",persistent:false});f.deferred.done(h);console.debug("tools-form::initialize() - Initial tool model ready.");console.debug(k)},error:function(k){f.deferred.done(h);console.debug("tools-form::initialize() - Initial tool model request failed.");console.debug(k);var l=k.error||"Uncaught error.";f.form.modal.show({title:"Tool cannot be executed",body:l,buttons:{Close:function(){f.form.modal.hide()}}})}})},_updateModel:function(g){var f=this;var i=this.form;var g={tool_id:this.options.id,tool_version:this.options.version,inputs:g};i.wait(true);var j=this.deferred.register();console.debug("tools-form::_refreshForm() - Sending current state (see below).");console.debug(g);var h=galaxy_config.root+"api/tools/"+this.options.id+"/build";c.request({type:"POST",url:h,data:g,success:function(k){i.data.matchModel(k,function(m,q){var l=i.input_list[m];if(l&&l.options){if(!_.isEqual(l.options,q.options)){l.options=q.options;var r=i.field_list[m];if(r.update){var p=[];if((["data","data_collection","drill_down"]).indexOf(l.type)!=-1){p=l.options}else{for(var o in q.options){var n=q.options[o];if(n.length>2){p.push({label:n[0],value:n[1]})}}}r.update(p);r.trigger("change");console.debug("Updating options for "+m)}}}});i.wait(false);console.debug("tools-form::_refreshForm() - Received new model (see below).");console.debug(k);f.deferred.done(j)},error:function(k){f.deferred.done(j);console.debug("tools-form::_refreshForm() - Refresh request failed.");console.debug(k)}})}});return{View:d}});
@@ -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 e={tool_id:this.app.options.id,tool_version:this.app.options.version,inputs:this.app.tree.finalize()};this.app.trigger("reset");if(!this._validation(e)){console.debug("tools-jobs::submit - Submission canceled. Validation failed.");return}console.debug(e);var d=true;this.app.modal.show({title:"Please wait...",body:"progress",buttons:{Close:function(){c.app.modal.hide();d=false}}});b.request({type:"POST",url:galaxy_config.root+"api/tools",data:e,success:function(f){c.app.modal.hide();c.app.reciept(a.success(f));c._refreshHdas()},error:function(f,h){c.app.modal.hide();if(f&&f.message&&f.message.data){var i=c.app.tree.matchResponse(f.message.data);for(var g in i){c.app.highlight(g,i[g]);break}}else{console.debug(f);d&&c.app.modal.show({title:"Job submission failed",body:a.error(e),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&&f==null){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()}}})});
define(["utils/utils","mvc/tools/tools-template"],function(b,a){return{submit:function(g,e){var c=this;var f={tool_id:e.id,tool_version:e.version,inputs:g.data.create()};g.trigger("reset");if(!this._validation(g,f)){console.debug("tools-jobs::submit - Submission canceled. Validation failed.");return}console.debug(f);var d=true;g.modal.show({title:"Please wait...",body:"progress",buttons:{Close:function(){g.modal.hide();d=false}}});b.request({type:"POST",url:galaxy_config.root+"api/tools",data:f,success:function(h){g.modal.hide();g.reciept(a.success(h));c._refreshHdas()},error:function(h,j){g.modal.hide();if(h&&h.message&&h.message.data){var k=g.data.matchResponse(h.message.data);for(var i in k){g.highlight(i,k[i]);break}}else{console.debug(h);d&&g.modal.show({title:"Job submission failed",body:a.error(f),buttons:{Close:function(){g.modal.hide()}}})}}})},_validation:function(e,i){var f=i.inputs;var o=-1;var j=null;for(var l in f){var g=f[l];var m=e.data.match(l);var d=e.field_list[m];var k=e.input_list[m];if(!m||!k||!d){console.debug("tools-jobs::_validation - Retrieving input objects failed.");continue}if(!k.optional&&g==null){e.highlight(m);return false}if(g&&g.batch){var h=g.values.length;var c=null;if(h>0){c=g.values[0]&&g.values[0].src}if(c){if(j===null){j=c}else{if(j!==c){e.highlight(m,"Please select either dataset or dataset list fields for all batch mode fields.");return false}}}if(o===-1){o=h}else{if(o!==h){e.highlight(m,"Please make sure that you select the same number of inputs for all batch mode fields. This field contains <b>"+h+"</b> selection(s) while a previous field contains <b>"+o+"</b>.");return false}}}}return true},_refreshHdas:function(){if(parent.Galaxy&&parent.Galaxy.currHistoryPanel){parent.Galaxy.currHistoryPanel.refreshContents()}}}});
@@ -1 +1 @@
define([],function(){return{help:function(a){return'<div class="toolHelp" style="overflow: auto;"><div class="toolHelpBody">'+a+"</div></div>"},success:function(c){if(!c.jobs||!c.jobs.length){return this.error(c)}var a=c.jobs.length;var d="";if(a==1){d="1 job has"}else{d=a+" jobs have"}var b='<div class="donemessagelarge"><p>'+d+" been successfully added to the queue - resulting in the following datasets:</p>";for(var e in c.outputs){b+='<p style="padding: 10px 20px;"><b>'+c.outputs[e].hid+": "+c.outputs[e].name+"</b></p>"}b+="<p>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.</p></div>";return b},error:function(a){return'<div><p>The server could not complete the request. Please contact the Galaxy Team if this error persists.</p><textarea class="ui-textarea" disabled style="color: black; height: 300px !important;">'+JSON.stringify(a,undefined,4)+"</textarea></div>"},batchMode:function(){return'<div class="ui-table-form-info"><i class="fa fa-sitemap" style="font-size: 1.2em; padding: 2px 5px;"/>This is a batch mode input field. A separate job will be triggered for each dataset.</div>'},requirements:function(a){var d="This tool requires ";for(var b in a.requirements){var c=a.requirements[b];d+=c.name;if(c.version){d+=" (Version "+c.version+")"}if(b<a.requirements.length-2){d+=", "}if(b==a.requirements.length-2){d+=" and "}}return d+'. Click <a target="_blank" href="https://wiki.galaxyproject.org/Tools/Requirements">here</a> for more information.'}}});
define([],function(){return{help:function(a){return'<div class="toolHelp" style="overflow: auto;"><div class="toolHelpBody">'+a.help+"</div></div>"},success:function(c){if(!c.jobs||!c.jobs.length){return this.error(c)}var a=c.jobs.length;var d="";if(a==1){d="1 job has"}else{d=a+" jobs have"}var b='<div class="donemessagelarge"><p>'+d+" been successfully added to the queue - resulting in the following datasets:</p>";for(var e in c.outputs){b+='<p style="padding: 10px 20px;"><b>'+c.outputs[e].hid+": "+c.outputs[e].name+"</b></p>"}b+="<p>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.</p></div>";return b},error:function(a){return'<div><p>The server could not complete the request. Please contact the Galaxy Team if this error persists.</p><textarea class="ui-textarea" disabled style="color: black; height: 300px !important;">'+JSON.stringify(a,undefined,4)+"</textarea></div>"},requirements:function(a){var d="This tool requires ";for(var b in a.requirements){var c=a.requirements[b];d+=c.name;if(c.version){d+=" (Version "+c.version+")"}if(b<a.requirements.length-2){d+=", "}if(b==a.requirements.length-2){d+=" and "}}return d+'. Click <a target="_blank" href="https://wiki.galaxyproject.org/Tools/Requirements">here</a> for more information.'}}});