galaxy-commits
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
April 2012
- 1 participants
- 170 discussions
7 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/f11e8aa26fcc/
changeset: f11e8aa26fcc
user: jgoecks
date: 2012-04-12 20:14:00
summary: More client-side support for tools: (a) include different attributes in dict depending on params; (b) framework for dictifying inputs; (c) support for getting tool description by id via API.
affected #: 2 files
diff -r 84d49e39069d965a45097ade1b71a57cdc0a0386 -r f11e8aa26fcc88b9fa92e752000b092cfefce88c lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -598,7 +598,7 @@
""" Return a dict that includes section's attributes. """
section_elts = []
for key, val in self.elems.items():
- section_elts.append( val.to_dict( trans ) )
+ section_elts.append( val.to_dict( trans, for_link=True ) )
return { 'type': 'section', 'id': self.id, 'name': self.name, 'version': self.version, 'elems': section_elts }
class ToolSectionLabel( object ):
@@ -611,7 +611,7 @@
self.id = elem.get( "id" )
self.version = elem.get( "version" ) or ''
- def to_dict( self, trans ):
+ def to_dict( self, trans, **kwargs ):
""" Return a dict that includes label's attributes. """
return { 'type': 'label', 'id': self.id, 'name': self.text, 'version': self.version }
@@ -691,6 +691,14 @@
def __iter__( self ):
return iter( ( self.format, self.metadata_source, self.parent ) )
+
+ def to_dict( self ):
+ return {
+ 'name': self.name,
+ 'format': self.format,
+ 'label': self.label,
+ 'hidden': self.hidden
+ }
class ToolRequirement( object ):
"""
@@ -2392,20 +2400,48 @@
return True
return False
- def to_dict( self, trans ):
- """ Return dict of tool attributes. """
+ def to_dict( self, trans, for_link=False, for_display=False ):
+ """ Returns dict of tool. """
- # Create tool link.
- if not self.tool_type.startswith( 'data_source' ):
- link = url_for( controller='tool_runner', tool_id=self.id )
- else:
- link = url_for( self.action, **self.get_static_param_values( trans ) )
+ # Basic information
+ tool_dict = { 'id': self.id, 'name': self.name,
+ 'version': self.version, 'description': self.description }
+
+ if for_link:
+ # Create tool link.
+ if not self.tool_type.startswith( 'data_source' ):
+ link = url_for( controller='tool_runner', tool_id=self.id )
+ else:
+ link = url_for( self.action, **self.get_static_param_values( trans ) )
- return { 'type': 'tool', 'id': self.id, 'name': self.name, 'link': link,
- 'version': self.version, 'description': self.description,
- 'min_width': self.uihints.get( 'minwidth', -1 ),
- 'target': self.target,
- 'hidden': self._is_hidden_for_user( trans.user ) }
+ # Basic information
+ tool_dict.update( { 'type': 'tool', 'link': link,
+ 'min_width': self.uihints.get( 'minwidth', -1 ),
+ 'target': self.target } )
+
+ if for_display:
+ # Dictify inputs.
+ inputs = []
+ for name, input in self.inputs.items():
+ param_dict = { 'name' : name, 'label' : input.label }
+ if isinstance( input, DataToolParameter ):
+ param_dict.update( { 'type' : 'data', 'html' : urllib.quote( input.get_html( trans ) ) } )
+ elif isinstance( input, SelectToolParameter ):
+ param_dict.update( { 'type' : 'select', 'html' : urllib.quote( input.get_html( trans ) ) } )
+ elif isinstance( input, Conditional ):
+ # TODO.
+ pass
+ else:
+ param_dict.update( { 'type' : '??', 'init_value' : input.value, \
+ 'html' : urllib.quote( input.get_html( trans ) ) } )
+ inputs.append( param_dict )
+
+ tool_dict[ 'inputs' ] = inputs
+
+ # Dictify outputs.
+ pass
+
+ return tool_dict
class DataSourceTool( Tool ):
"""
diff -r 84d49e39069d965a45097ade1b71a57cdc0a0386 -r f11e8aa26fcc88b9fa92e752000b092cfefce88c lib/galaxy/web/api/tools.py
--- a/lib/galaxy/web/api/tools.py
+++ b/lib/galaxy/web/api/tools.py
@@ -6,7 +6,7 @@
RESTful controller for interactions with tools.
"""
- @web.json
+ @web.expose_api
def index( self, trans, **kwds ):
"""
GET /api/tools: returns a list of tools defined by parameters
@@ -22,11 +22,11 @@
# Create return value.
return self.app.toolbox.to_dict( trans, in_panel=in_panel, trackster=trackster )
- @web.expose_api
+ @web.json
def show( self, trans, id, **kwd ):
"""
GET /api/tools/{tool_id}
Returns tool information, including parameters and inputs.
"""
- return self.app.toolbox.tools_by_id[ id ].to_dict( trans, all=True )
+ return self.app.toolbox.tools_by_id[ id ].to_dict( trans, for_display=True )
\ No newline at end of file
https://bitbucket.org/galaxy/galaxy-central/changeset/272506e479f5/
changeset: 272506e479f5
user: jgoecks
date: 2012-04-12 20:18:44
summary: Basic support for dynamically displaying tool forms.
affected #: 7 files
diff -r f11e8aa26fcc88b9fa92e752000b092cfefce88c -r 272506e479f54d41b345c373786c23cab57cc153 static/june_2007_style/base.less
--- a/static/june_2007_style/base.less
+++ b/static/june_2007_style/base.less
@@ -1632,7 +1632,7 @@
margin-top: 5px;
}
-.unified-panel-body > .toolMenu {
+.unified-panel-body .toolMenu {
padding: 10px;
}
@@ -1717,5 +1717,13 @@
padding:2px 10px;
}
+// ==== Integrated tool form styles
+
+.toolMenuAndView .toolForm
+{
+ float: left;
+ background-color: white;
+ margin: 10px;
+}
@import "base_sprites";
diff -r f11e8aa26fcc88b9fa92e752000b092cfefce88c -r 272506e479f54d41b345c373786c23cab57cc153 static/june_2007_style/blue/base.css
--- a/static/june_2007_style/blue/base.css
+++ b/static/june_2007_style/blue/base.css
@@ -713,7 +713,7 @@
pre.peek{background:white;color:black;width:100%;font-size:10px;overflow:auto;}pre.peek th{color:white;background:#023858;}
pre.peek table,pre.peek th,pre.peek tr,pre.peek td{font-family:Menlo,Monaco,"Courier New",monospace;font-size:10px;}
.toolMenuContainer{color:#303030;background:#dfe5f9;margin-top:5px;}
-.unified-panel-body>.toolMenu{padding:10px;}
+.unified-panel-body .toolMenu{padding:10px;}
div.toolSectionPad{margin:0;padding:0;height:5px;font-size:0px;}
div.toolSectionWrapper{margin-bottom:5px;}
div.toolSectionDetailsInner{margin-left:5px;margin-right:5px;}
@@ -725,6 +725,7 @@
#tool-search{padding-top:5px;padding-bottom:10px;position:relative;}
#loading_indicator{position:fixed;right:10px;top:10px;height:32px;width:32px;background:url(largespinner.gif);}
#content_table td{text-align:right;white-space:nowrap;padding:2px 10px;}
+.toolMenuAndView .toolForm{float:left;background-color:white;margin:10px;}
.icon-button.display{background:url(history-buttons.png) no-repeat 0px 0px;}
.icon-button.display:hover{background:url(history-buttons.png) no-repeat 0px -26px;}
.icon-button.display_disabled{background:url(history-buttons.png) no-repeat 0px -52px;}
diff -r f11e8aa26fcc88b9fa92e752000b092cfefce88c -r 272506e479f54d41b345c373786c23cab57cc153 static/scripts/backbone/tools.js
--- a/static/scripts/backbone/tools.js
+++ b/static/scripts/backbone/tools.js
@@ -8,7 +8,7 @@
* Simple base model for any visible element. Includes useful attributes and ability
* to set and track visibility.
*/
-var BaseModel = Backbone.Model.extend({
+var BaseModel = Backbone.RelationalModel.extend({
defaults: {
name: null,
hidden: false
@@ -35,9 +35,22 @@
defaults: {
description: null,
target: null,
- params: []
+ inputs: []
},
+ relations: [
+ {
+ type: Backbone.HasMany,
+ key: 'inputs',
+ relatedModel: 'ToolInput',
+ reverseRelation: {
+ key: 'tool'
+ }
+ }
+ ],
+
+ urlRoot: galaxy_paths.attributes.root_path + 'api/tools',
+
apply_search_results: function(results) {
( _.indexOf(results, this.attributes.id) !== -1 ? this.show() : this.hide() );
return this.is_visible();
@@ -45,6 +58,17 @@
});
/**
+ * A tool input.
+ */
+var ToolInput = Backbone.RelationalModel.extend({
+
+ initialize: function() {
+ this.attributes.html = unescape(this.attributes.html);
+ }
+
+});
+
+/**
* Wrap collection of tools for fast access/manipulation.
*/
var ToolCollection = Backbone.Collection.extend({
@@ -379,6 +403,10 @@
}
});
+/**
+ * Tool panel view. Events triggered include:
+ * tool_link_click(click event, tool_model)
+ */
var ToolPanelView = Backbone.View.extend({
tagName: 'div',
className: 'toolMenu',
@@ -386,13 +414,8 @@
/**
* Waits for collection to load and then renders.
*/
- initialize: function(options) {
+ initialize: function() {
this.collection.tool_search.on("change:results", this.handle_search_results, this);
-
- this.tool_link_click_fn = null;
- if (options && 'tool_link_click_fn' in options) {
- this.tool_link_click_fn = options.tool_link_click_fn;
- }
},
render: function() {
@@ -422,16 +445,15 @@
}
});
- // Setup tool link click handling.
- if (self.tool_link_click_fn) {
- self.$el.find("a.tool-link").click(function() {
- // Tool id is always the first class.
- var tool_id = $(this).attr('class').split(/\s+/)[0];
+ // Setup tool link click eventing.
+ self.$el.find("a.tool-link").click(function(e) {
+ // Tool id is always the first class.
+ var
+ tool_id = $(this).attr('class').split(/\s+/)[0],
+ tool = self.collection.tools.get(tool_id);
- self.tool_link_click_fn(self.collection.tools.get(tool_id));
- return false;
- });
- }
+ self.trigger("tool_link_click", e, tool);
+ });
return this;
},
@@ -446,3 +468,62 @@
}
}
});
+
+/**
+ * View for working with a tool: setting parameters and inputs and executing the tool.
+ */
+var ToolFormView = Backbone.View.extend({
+ className: 'toolForm',
+ template: Handlebars.templates.tool_form,
+
+ render: function() {
+ this.$el.children().remove();
+ this.$el.append( this.template(this.model.toJSON()) );
+ }
+});
+
+
+/**
+ * Integrated tool menu + tool execution.
+ */
+var IntegratedToolMenuAndView = Backbone.View.extend({
+ className: 'toolMenuAndView',
+
+ initialize: function() {
+ this.tool_panel_view = new ToolPanelView({collection: this.collection});
+ this.tool_form_view = new ToolFormView();
+ },
+
+ render: function() {
+ // Render and append tool panel.
+ this.tool_panel_view.render();
+ this.tool_panel_view.$el.css("float", "left");
+ this.$el.append(this.tool_panel_view.$el);
+
+ // Append tool form view.
+ this.tool_form_view.$el.hide();
+ this.$el.append(this.tool_form_view.$el);
+
+ // On tool link click, show tool.
+ var self = this;
+ this.tool_panel_view.on("tool_link_click", function(e, tool) {
+ // Prevents click from activating link:
+ e.preventDefault();
+ // Show tool that was clicked on:
+ self.show_tool(tool);
+ });
+ },
+
+ /**
+ * Fetch and display tool.
+ */
+ show_tool: function(tool) {
+ var self = this;
+ tool.fetch().done( function() {
+ self.tool_form_view.model = tool;
+ self.tool_form_view.render();
+ self.tool_form_view.$el.show();
+ $('#left').width("650px");
+ });
+ }
+});
\ No newline at end of file
diff -r f11e8aa26fcc88b9fa92e752000b092cfefce88c -r 272506e479f54d41b345c373786c23cab57cc153 static/scripts/handlebars/compiled/tool_form.js
--- /dev/null
+++ b/static/scripts/handlebars/compiled/tool_form.js
@@ -0,0 +1,61 @@
+(function() {
+ var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
+templates['tool_form'] = template(function (Handlebars,depth0,helpers,partials,data) {
+ helpers = helpers || Handlebars.helpers;
+ var buffer = "", stack1, stack2, foundHelper, tmp1, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression;
+
+function program1(depth0,data) {
+
+ var buffer = "", stack1;
+ buffer += "\n <div class=\"form-row\">\n <label for=\"";
+ foundHelper = helpers.name;
+ stack1 = foundHelper || depth0.name;
+ if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
+ else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); }
+ buffer += escapeExpression(stack1) + "\">";
+ foundHelper = helpers.label;
+ stack1 = foundHelper || depth0.label;
+ if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
+ else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "label", { hash: {} }); }
+ buffer += escapeExpression(stack1) + ":</label>\n <div class=\"form-row-input\">\n ";
+ foundHelper = helpers.html;
+ stack1 = foundHelper || depth0.html;
+ if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
+ else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "html", { hash: {} }); }
+ if(stack1 || stack1 === 0) { buffer += stack1; }
+ buffer += "\n </div>\n <div class=\"toolParamHelp\" style=\"clear: both;\">\n ";
+ foundHelper = helpers.help;
+ stack1 = foundHelper || depth0.help;
+ if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
+ else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "help", { hash: {} }); }
+ buffer += escapeExpression(stack1) + "\n </div>\n <div style=\"clear: both;\"></div>\n </div>\n ";
+ return buffer;}
+
+ buffer += "<div class=\"toolFormTitle\">";
+ foundHelper = helpers.name;
+ stack1 = foundHelper || depth0.name;
+ if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
+ else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); }
+ buffer += escapeExpression(stack1) + " (version ";
+ foundHelper = helpers.version;
+ stack1 = foundHelper || depth0.version;
+ if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
+ else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "version", { hash: {} }); }
+ buffer += escapeExpression(stack1) + ")</div>\n <div class=\"toolFormBody\">\n ";
+ foundHelper = helpers.inputs;
+ stack1 = foundHelper || depth0.inputs;
+ stack2 = helpers.each;
+ tmp1 = self.program(1, program1, data);
+ tmp1.hash = {};
+ tmp1.fn = tmp1;
+ tmp1.inverse = self.noop;
+ stack1 = stack2.call(depth0, stack1, tmp1);
+ if(stack1 || stack1 === 0) { buffer += stack1; }
+ buffer += "\n </div>\n <div class=\"form-row form-actions\">\n <input type=\"submit\" class=\"btn btn-primary\" name=\"runtool_btn\" value=\"Execute\">\n</div>\n<div class=\"toolHelp\">\n <div class=\"toolHelpBody\">";
+ foundHelper = helpers.help;
+ stack1 = foundHelper || depth0.help;
+ if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
+ else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "help", { hash: {} }); }
+ buffer += escapeExpression(stack1) + "</div>\n</div>";
+ return buffer;});
+})();
\ No newline at end of file
diff -r f11e8aa26fcc88b9fa92e752000b092cfefce88c -r 272506e479f54d41b345c373786c23cab57cc153 static/scripts/handlebars/tool_form.handlebars
--- /dev/null
+++ b/static/scripts/handlebars/tool_form.handlebars
@@ -0,0 +1,21 @@
+<div class="toolFormTitle">{{name}} (version {{version}})</div>
+ <div class="toolFormBody">
+ {{#each inputs}}
+ <div class="form-row">
+ <label for="{{name}}">{{label}}:</label>
+ <div class="form-row-input">
+ {{{html}}}
+ </div>
+ <div class="toolParamHelp" style="clear: both;">
+ {{help}}
+ </div>
+ <div style="clear: both;"></div>
+ </div>
+ {{/each}}
+ </div>
+ <div class="form-row form-actions">
+ <input type="submit" class="btn btn-primary" name="runtool_btn" value="Execute">
+</div>
+<div class="toolHelp">
+ <div class="toolHelpBody">{{help}}</div>
+</div>
\ No newline at end of file
diff -r f11e8aa26fcc88b9fa92e752000b092cfefce88c -r 272506e479f54d41b345c373786c23cab57cc153 static/scripts/packed/backbone/tools.js
--- a/static/scripts/packed/backbone/tools.js
+++ b/static/scripts/packed/backbone/tools.js
@@ -1,1 +1,1 @@
-var BaseModel=Backbone.Model.extend({defaults:{name:null,hidden:false},show:function(){this.set("hidden",false)},hide:function(){this.set("hidden",true)},is_visible:function(){return !this.attributes.hidden}});var Tool=BaseModel.extend({defaults:{description:null,target:null,params:[]},apply_search_results:function(a){(_.indexOf(a,this.attributes.id)!==-1?this.show():this.hide());return this.is_visible()}});var ToolPanelLabel=BaseModel.extend({});var ToolPanelSection=BaseModel.extend({defaults:{elems:[],open:false},clear_search_results:function(){_.each(this.attributes.elems,function(a){a.show()});this.show();this.set("open",false)},apply_search_results:function(b){var c=true,a;_.each(this.attributes.elems,function(d){if(d instanceof ToolPanelLabel){a=d;a.hide()}else{if(d instanceof Tool){if(d.apply_search_results(b)){c=false;if(a){a.show()}}}}});if(c){this.hide()}else{this.show();this.set("open",true)}}});var ToolSearch=BaseModel.extend({defaults:{spinner_url:"",search_url:"",visible:true,query:"",results:null},initialize:function(){this.on("change:query",this.do_search)},do_search:function(){var c=this.attributes.query;if(c.length<3){this.set("results",null);return}var b=c+"*";if(this.timer){clearTimeout(this.timer)}$("#search-spinner").show();var a=this;this.timer=setTimeout(function(){$.get(a.attributes.search_url,{query:b},function(d){a.set("results",d);$("#search-spinner").hide()},"json")},200)}});var ToolPanel=Backbone.Collection.extend({url:"/tools",parse:function(a){var b=function(e){var d=e.type;if(d==="tool"){return new Tool(e)}else{if(d==="section"){var c=_.map(e.elems,b);e.elems=c;return new ToolPanelSection(e)}else{if(d==="label"){return new ToolPanelLabel(e)}}}};return _.map(a,b)},initialize:function(a){this.tool_search=a.tool_search;this.tool_search.on("change:results",this.apply_search_results,this)},clear_search_results:function(){this.each(function(a){if(a instanceof ToolPanelSection){a.clear_search_results()}else{a.show()}})},apply_search_results:function(){var b=this.tool_search.attributes.results;if(b===null){this.clear_search_results();return}var a=null;this.each(function(c){if(c instanceof ToolPanelLabel){a=c;a.hide()}else{if(c instanceof Tool){if(c.apply_search_results(b)){if(a){a.show()}}}else{a=null;c.apply_search_results(b)}}})}});var BaseView=Backbone.View.extend({initialize:function(){this.model.on("change:hidden",this.update_visible,this);this.update_visible()},update_visible:function(){(this.model.attributes.hidden?this.$el.hide():this.$el.show())}});var ToolLinkView=BaseView.extend({tagName:"div",template:Handlebars.templates.tool_link,render:function(){this.$el.append(this.template(this.model.toJSON()));return this}});var ToolPanelLabelView=BaseView.extend({tagName:"div",className:"toolPanelLabel",template:Handlebars.templates.panel_label,render:function(){this.$el.append(this.template(this.model.toJSON()));return this},});var ToolPanelSectionView=BaseView.extend({tagName:"div",className:"toolSectionWrapper",template:Handlebars.templates.panel_section,initialize:function(){BaseView.prototype.initialize.call(this);this.model.on("change:open",this.update_open,this)},render:function(){this.$el.append(this.template(this.model.toJSON()));var a=this.$el.find(".toolSectionBody");_.each(this.model.attributes.elems,function(b){if(b instanceof Tool){var c=new ToolLinkView({model:b,className:"toolTitle"});c.render();a.append(c.$el)}else{if(b instanceof ToolPanelLabel){var d=new ToolPanelLabelView({model:b});d.render();a.append(d.$el)}else{}}});return this},events:{"click .toolSectionTitle > a":"toggle"},toggle:function(){this.model.set("open",!this.model.attributes.open)},update_open:function(){(this.model.attributes.open?this.$el.children(".toolSectionBody").slideDown("fast"):this.$el.children(".toolSectionBody").slideUp("fast"))}});var ToolSearchView=Backbone.View.extend({tagName:"div",id:"tool-search",className:"bar",template:Handlebars.templates.tool_search,events:{click:"focus_and_select","keyup :input":"query_changed"},render:function(){this.$el.append(this.template(this.model.toJSON()));if(!this.model.is_visible()){this.$el.hide()}return this},focus_and_select:function(){this.$el.find(":input").focus().select()},query_changed:function(){this.model.set("query",this.$el.find(":input").val())}});var ToolPanelView=Backbone.View.extend({tagName:"div",className:"toolMenu",initialize:function(a){this.collection.tool_search.on("change:results",this.handle_search_results,this)},render:function(){var b=this.$el;var a=new ToolSearchView({model:this.collection.tool_search});a.render();b.append(a.$el);this.collection.each(function(d){if(d instanceof ToolPanelSection){var c=new ToolPanelSectionView({model:d});c.render();b.append(c.$el)}else{if(d instanceof Tool){var e=new ToolLinkView({model:d,className:"toolTitleNoSection"});e.render();b.append(e.$el)}else{if(d instanceof ToolPanelLabel){var f=new ToolPanelLabelView({model:d});f.render();b.append(f.$el)}}}});return this},handle_search_results:function(){var a=this.collection.tool_search.attributes.results;if(a&&a.length===0){$("#search-no-results").show()}else{$("#search-no-results").hide()}}});
\ No newline at end of file
+var BaseModel=Backbone.RelationalModel.extend({defaults:{name:null,hidden:false},show:function(){this.set("hidden",false)},hide:function(){this.set("hidden",true)},is_visible:function(){return !this.attributes.hidden}});var Tool=BaseModel.extend({defaults:{description:null,target:null,inputs:[]},relations:[{type:Backbone.HasMany,key:"inputs",relatedModel:"ToolInput",reverseRelation:{key:"tool"}}],url:function(){return galaxy_paths.attributes.root_path+"tools/show?id="+this.id},apply_search_results:function(a){(_.indexOf(a,this.attributes.id)!==-1?this.show():this.hide());return this.is_visible()}});var ToolInput=Backbone.RelationalModel.extend({});var ToolCollection=Backbone.Collection.extend({model:Tool});var ToolPanelLabel=BaseModel.extend({});var ToolPanelSection=BaseModel.extend({defaults:{elems:[],open:false},clear_search_results:function(){_.each(this.attributes.elems,function(a){a.show()});this.show();this.set("open",false)},apply_search_results:function(b){var c=true,a;_.each(this.attributes.elems,function(d){if(d instanceof ToolPanelLabel){a=d;a.hide()}else{if(d instanceof Tool){if(d.apply_search_results(b)){c=false;if(a){a.show()}}}}});if(c){this.hide()}else{this.show();this.set("open",true)}}});var ToolSearch=BaseModel.extend({defaults:{spinner_url:"",search_url:"",visible:true,query:"",results:null},initialize:function(){this.on("change:query",this.do_search)},do_search:function(){var c=this.attributes.query;if(c.length<3){this.set("results",null);return}var b=c+"*";if(this.timer){clearTimeout(this.timer)}$("#search-spinner").show();var a=this;this.timer=setTimeout(function(){$.get(a.attributes.search_url,{query:b},function(d){a.set("results",d);$("#search-spinner").hide()},"json")},200)}});var ToolPanel=Backbone.Collection.extend({url:"/tools",tools:new ToolCollection(),parse:function(a){var b=function(e){var d=e.type;if(d==="tool"){return new Tool(e)}else{if(d==="section"){var c=_.map(e.elems,b);e.elems=c;return new ToolPanelSection(e)}else{if(d==="label"){return new ToolPanelLabel(e)}}}};return _.map(a,b)},initialize:function(a){this.tool_search=a.tool_search;this.tool_search.on("change:results",this.apply_search_results,this);this.on("reset",this.populate_tools,this)},populate_tools:function(){var a=this;a.tools=new ToolCollection();this.each(function(b){if(b instanceof ToolPanelSection){_.each(b.attributes.elems,function(c){if(c instanceof Tool){a.tools.push(c)}})}else{if(b instanceof Tool){a.tools.push(b)}}})},clear_search_results:function(){this.each(function(a){if(a instanceof ToolPanelSection){a.clear_search_results()}else{a.show()}})},apply_search_results:function(){var b=this.tool_search.attributes.results;if(b===null){this.clear_search_results();return}var a=null;this.each(function(c){if(c instanceof ToolPanelLabel){a=c;a.hide()}else{if(c instanceof Tool){if(c.apply_search_results(b)){if(a){a.show()}}}else{a=null;c.apply_search_results(b)}}})}});var BaseView=Backbone.View.extend({initialize:function(){this.model.on("change:hidden",this.update_visible,this);this.update_visible()},update_visible:function(){(this.model.attributes.hidden?this.$el.hide():this.$el.show())}});var ToolLinkView=BaseView.extend({tagName:"div",template:Handlebars.templates.tool_link,render:function(){this.$el.append(this.template(this.model.toJSON()));return this}});var ToolPanelLabelView=BaseView.extend({tagName:"div",className:"toolPanelLabel",template:Handlebars.templates.panel_label,render:function(){this.$el.append(this.template(this.model.toJSON()));return this},});var ToolPanelSectionView=BaseView.extend({tagName:"div",className:"toolSectionWrapper",template:Handlebars.templates.panel_section,initialize:function(){BaseView.prototype.initialize.call(this);this.model.on("change:open",this.update_open,this)},render:function(){this.$el.append(this.template(this.model.toJSON()));var a=this.$el.find(".toolSectionBody");_.each(this.model.attributes.elems,function(b){if(b instanceof Tool){var c=new ToolLinkView({model:b,className:"toolTitle"});c.render();a.append(c.$el)}else{if(b instanceof ToolPanelLabel){var d=new ToolPanelLabelView({model:b});d.render();a.append(d.$el)}else{}}});return this},events:{"click .toolSectionTitle > a":"toggle"},toggle:function(){this.model.set("open",!this.model.attributes.open)},update_open:function(){(this.model.attributes.open?this.$el.children(".toolSectionBody").slideDown("fast"):this.$el.children(".toolSectionBody").slideUp("fast"))}});var ToolSearchView=Backbone.View.extend({tagName:"div",id:"tool-search",className:"bar",template:Handlebars.templates.tool_search,events:{click:"focus_and_select","keyup :input":"query_changed"},render:function(){this.$el.append(this.template(this.model.toJSON()));if(!this.model.is_visible()){this.$el.hide()}return this},focus_and_select:function(){this.$el.find(":input").focus().select()},query_changed:function(){this.model.set("query",this.$el.find(":input").val())}});var ToolPanelView=Backbone.View.extend({tagName:"div",className:"toolMenu",initialize:function(){this.collection.tool_search.on("change:results",this.handle_search_results,this)},render:function(){var a=this;var b=new ToolSearchView({model:this.collection.tool_search});b.render();a.$el.append(b.$el);this.collection.each(function(d){if(d instanceof ToolPanelSection){var c=new ToolPanelSectionView({model:d});c.render();a.$el.append(c.$el)}else{if(d instanceof Tool){var e=new ToolLinkView({model:d,className:"toolTitleNoSection"});e.render();a.$el.append(e.$el)}else{if(d instanceof ToolPanelLabel){var f=new ToolPanelLabelView({model:d});f.render();a.$el.append(f.$el)}}}});a.$el.find("a.tool-link").click(function(f){var d=$(this).attr("class").split(/\s+/)[0],c=a.collection.tools.get(d);a.trigger("tool_link_click",f,c)});return this},handle_search_results:function(){var a=this.collection.tool_search.attributes.results;if(a&&a.length===0){$("#search-no-results").show()}else{$("#search-no-results").hide()}}});var ToolView=Backbone.View.extend({className:"toolForm",render:function(){var a=this}});var IntegratedToolMenuAndView=Backbone.View.extend({className:"toolMenuAndView",initialize:function(){this.tool_panel_view=new ToolPanelView({collection:this.collection})},render:function(){this.tool_panel_view.render();this.tool_panel_view.$el.css("float","left");this.$el.append(this.tool_panel_view.$el);var a=this;this.tool_panel_view.on("tool_link_click",function(c,b){c.preventDefault();a.show_tool(b)})},show_tool:function(a){a.fetch().done(function(){console.log(a);var b=new ToolView({model:a});b.render();b.$el.css("float","left");this.$el.append(b.$el);$("#left").width("500px")})}});
\ No newline at end of file
diff -r f11e8aa26fcc88b9fa92e752000b092cfefce88c -r 272506e479f54d41b345c373786c23cab57cc153 static/scripts/packed/handlebars/compiled/tool_form.js
--- /dev/null
+++ b/static/scripts/packed/handlebars/compiled/tool_form.js
@@ -0,0 +1,1 @@
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.tool_form=b(function(f,p,e,n,m){e=e||f.helpers;var k="",c,r,j,i,q=this,g="function",o=e.helperMissing,h=void 0,l=this.escapeExpression;function d(v,u){var s="",t;s+='\n <div class="form-row">\n <label for="';j=e.name;t=j||v.name;if(typeof t===g){t=t.call(v,{hash:{}})}else{if(t===h){t=o.call(v,"name",{hash:{}})}}s+=l(t)+'">';j=e.label;t=j||v.label;if(typeof t===g){t=t.call(v,{hash:{}})}else{if(t===h){t=o.call(v,"label",{hash:{}})}}s+=l(t)+':</label>\n <div class="form-row-input">\n ';j=e.html;t=j||v.html;if(typeof t===g){t=t.call(v,{hash:{}})}else{if(t===h){t=o.call(v,"html",{hash:{}})}}if(t||t===0){s+=t}s+='\n </div>\n <div class="toolParamHelp" style="clear: both;">\n ';j=e.help;t=j||v.help;if(typeof t===g){t=t.call(v,{hash:{}})}else{if(t===h){t=o.call(v,"help",{hash:{}})}}s+=l(t)+'\n </div>\n <div style="clear: both;"></div>\n </div>\n ';return s}k+='<div class="toolFormTitle">';j=e.name;c=j||p.name;if(typeof c===g){c=c.call(p,{hash:{}})}else{if(c===h){c=o.call(p,"name",{hash:{}})}}k+=l(c)+" (version ";j=e.version;c=j||p.version;if(typeof c===g){c=c.call(p,{hash:{}})}else{if(c===h){c=o.call(p,"version",{hash:{}})}}k+=l(c)+')</div>\n <div class="toolFormBody">\n ';j=e.inputs;c=j||p.inputs;r=e.each;i=q.program(1,d,m);i.hash={};i.fn=i;i.inverse=q.noop;c=r.call(p,c,i);if(c||c===0){k+=c}k+='\n </div>\n <div class="form-row form-actions">\n <input type="submit" class="btn btn-primary" name="runtool_btn" value="Execute">\n</div>\n<div class="toolHelp">\n <div class="toolHelpBody">';j=e.help;c=j||p.help;if(typeof c===g){c=c.call(p,{hash:{}})}else{if(c===h){c=o.call(p,"help",{hash:{}})}}k+=l(c)+"</div>\n</div>";return k})})();
\ No newline at end of file
https://bitbucket.org/galaxy/galaxy-central/changeset/98c2b1689ab3/
changeset: 98c2b1689ab3
user: jgoecks
date: 2012-04-12 20:21:35
summary: Change handlebars directory name to templates.
affected #: 32 files
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/handlebars/compile_templates.py
--- a/static/scripts/handlebars/compile_templates.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python
-
-# Script requires handlebars compiler be installed; use node package manager
-# to install handlebars.
-
-import sys
-
-from glob import glob
-from subprocess import call
-from shutil import copyfile
-from os import path
-
-cmd = "handlebars %s -f compiled/%s.js"
-
-# If specific scripts specified on command line, just pack them, otherwise pack
-# all.
-
-if len( sys.argv ) > 1:
- to_pack = sys.argv[1:]
-else:
- to_pack = glob( "*.handlebars" )
-
-for fname in to_pack:
- fname_base = path.splitext( path.split( fname )[1] )[0]
- print "%s --> compiled/%s.js" % ( fname, fname_base )
- out = call( cmd % ( fname, fname_base ), shell=True )
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/handlebars/compiled/panel_label.js
--- a/static/scripts/handlebars/compiled/panel_label.js
+++ /dev/null
@@ -1,15 +0,0 @@
-(function() {
- var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
-templates['panel_label'] = template(function (Handlebars,depth0,helpers,partials,data) {
- helpers = helpers || Handlebars.helpers;
- var buffer = "", stack1, foundHelper, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression;
-
-
- buffer += "<span>";
- foundHelper = helpers.name;
- stack1 = foundHelper || depth0.name;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); }
- buffer += escapeExpression(stack1) + "</span>";
- return buffer;});
-})();
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/handlebars/compiled/panel_section.js
--- a/static/scripts/handlebars/compiled/panel_section.js
+++ /dev/null
@@ -1,25 +0,0 @@
-(function() {
- var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
-templates['panel_section'] = template(function (Handlebars,depth0,helpers,partials,data) {
- helpers = helpers || Handlebars.helpers;
- var buffer = "", stack1, foundHelper, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression;
-
-
- buffer += "<div class=\"toolSectionTitle\" id=\"title_";
- foundHelper = helpers.id;
- stack1 = foundHelper || depth0.id;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "id", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\">\n <a href=\"#\"><span>";
- foundHelper = helpers.name;
- stack1 = foundHelper || depth0.name;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); }
- buffer += escapeExpression(stack1) + "</span></a>\n</div>\n<div id=\"";
- foundHelper = helpers.id;
- stack1 = foundHelper || depth0.id;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "id", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\" class=\"toolSectionBody\" style=\"display: none; \">\n <div class=\"toolSectionBg\"></div>\n<div>";
- return buffer;});
-})();
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/handlebars/compiled/tool_form.js
--- a/static/scripts/handlebars/compiled/tool_form.js
+++ /dev/null
@@ -1,61 +0,0 @@
-(function() {
- var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
-templates['tool_form'] = template(function (Handlebars,depth0,helpers,partials,data) {
- helpers = helpers || Handlebars.helpers;
- var buffer = "", stack1, stack2, foundHelper, tmp1, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression;
-
-function program1(depth0,data) {
-
- var buffer = "", stack1;
- buffer += "\n <div class=\"form-row\">\n <label for=\"";
- foundHelper = helpers.name;
- stack1 = foundHelper || depth0.name;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\">";
- foundHelper = helpers.label;
- stack1 = foundHelper || depth0.label;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "label", { hash: {} }); }
- buffer += escapeExpression(stack1) + ":</label>\n <div class=\"form-row-input\">\n ";
- foundHelper = helpers.html;
- stack1 = foundHelper || depth0.html;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "html", { hash: {} }); }
- if(stack1 || stack1 === 0) { buffer += stack1; }
- buffer += "\n </div>\n <div class=\"toolParamHelp\" style=\"clear: both;\">\n ";
- foundHelper = helpers.help;
- stack1 = foundHelper || depth0.help;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "help", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\n </div>\n <div style=\"clear: both;\"></div>\n </div>\n ";
- return buffer;}
-
- buffer += "<div class=\"toolFormTitle\">";
- foundHelper = helpers.name;
- stack1 = foundHelper || depth0.name;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); }
- buffer += escapeExpression(stack1) + " (version ";
- foundHelper = helpers.version;
- stack1 = foundHelper || depth0.version;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "version", { hash: {} }); }
- buffer += escapeExpression(stack1) + ")</div>\n <div class=\"toolFormBody\">\n ";
- foundHelper = helpers.inputs;
- stack1 = foundHelper || depth0.inputs;
- stack2 = helpers.each;
- tmp1 = self.program(1, program1, data);
- tmp1.hash = {};
- tmp1.fn = tmp1;
- tmp1.inverse = self.noop;
- stack1 = stack2.call(depth0, stack1, tmp1);
- if(stack1 || stack1 === 0) { buffer += stack1; }
- buffer += "\n </div>\n <div class=\"form-row form-actions\">\n <input type=\"submit\" class=\"btn btn-primary\" name=\"runtool_btn\" value=\"Execute\">\n</div>\n<div class=\"toolHelp\">\n <div class=\"toolHelpBody\">";
- foundHelper = helpers.help;
- stack1 = foundHelper || depth0.help;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "help", { hash: {} }); }
- buffer += escapeExpression(stack1) + "</div>\n</div>";
- return buffer;});
-})();
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/handlebars/compiled/tool_link.js
--- a/static/scripts/handlebars/compiled/tool_link.js
+++ /dev/null
@@ -1,40 +0,0 @@
-(function() {
- var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
-templates['tool_link'] = template(function (Handlebars,depth0,helpers,partials,data) {
- helpers = helpers || Handlebars.helpers;
- var buffer = "", stack1, foundHelper, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression;
-
-
- buffer += "<a class=\"";
- foundHelper = helpers.id;
- stack1 = foundHelper || depth0.id;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "id", { hash: {} }); }
- buffer += escapeExpression(stack1) + " tool-link\" href=\"";
- foundHelper = helpers.link;
- stack1 = foundHelper || depth0.link;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "link", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\" target=\"";
- foundHelper = helpers.target;
- stack1 = foundHelper || depth0.target;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "target", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\" minsizehint=\"";
- foundHelper = helpers.min_width;
- stack1 = foundHelper || depth0.min_width;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "min_width", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\">";
- foundHelper = helpers.name;
- stack1 = foundHelper || depth0.name;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); }
- buffer += escapeExpression(stack1) + "</a> ";
- foundHelper = helpers.description;
- stack1 = foundHelper || depth0.description;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "description", { hash: {} }); }
- buffer += escapeExpression(stack1);
- return buffer;});
-})();
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/handlebars/compiled/tool_search.js
--- a/static/scripts/handlebars/compiled/tool_search.js
+++ /dev/null
@@ -1,15 +0,0 @@
-(function() {
- var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
-templates['tool_search'] = template(function (Handlebars,depth0,helpers,partials,data) {
- helpers = helpers || Handlebars.helpers;
- var buffer = "", stack1, foundHelper, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression;
-
-
- buffer += "<input type=\"text\" name=\"query\" value=\"search tools\" id=\"tool-search-query\" autocomplete=\"off\" class=\"search-query parent-width\" />\n<img src=\"";
- foundHelper = helpers.spinner_url;
- stack1 = foundHelper || depth0.spinner_url;
- if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
- else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "spinner_url", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\" id=\"search-spinner\" class=\"search-spinner\"/>\n";
- return buffer;});
-})();
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/handlebars/panel_label.handlebars
--- a/static/scripts/handlebars/panel_label.handlebars
+++ /dev/null
@@ -1,1 +0,0 @@
-<span>{{name}}</span>
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/handlebars/panel_section.handlebars
--- a/static/scripts/handlebars/panel_section.handlebars
+++ /dev/null
@@ -1,6 +0,0 @@
-<div class="toolSectionTitle" id="title_{{id}}">
- <a href="#"><span>{{name}}</span></a>
-</div>
-<div id="{{id}}" class="toolSectionBody" style="display: none; ">
- <div class="toolSectionBg"></div>
-<div>
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/handlebars/tool_form.handlebars
--- a/static/scripts/handlebars/tool_form.handlebars
+++ /dev/null
@@ -1,21 +0,0 @@
-<div class="toolFormTitle">{{name}} (version {{version}})</div>
- <div class="toolFormBody">
- {{#each inputs}}
- <div class="form-row">
- <label for="{{name}}">{{label}}:</label>
- <div class="form-row-input">
- {{{html}}}
- </div>
- <div class="toolParamHelp" style="clear: both;">
- {{help}}
- </div>
- <div style="clear: both;"></div>
- </div>
- {{/each}}
- </div>
- <div class="form-row form-actions">
- <input type="submit" class="btn btn-primary" name="runtool_btn" value="Execute">
-</div>
-<div class="toolHelp">
- <div class="toolHelpBody">{{help}}</div>
-</div>
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/handlebars/tool_link.handlebars
--- a/static/scripts/handlebars/tool_link.handlebars
+++ /dev/null
@@ -1,1 +0,0 @@
-<a class="{{id}} tool-link" href="{{link}}" target="{{target}}" minsizehint="{{min_width}}">{{name}}</a> {{description}}
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/handlebars/tool_search.handlebars
--- a/static/scripts/handlebars/tool_search.handlebars
+++ /dev/null
@@ -1,2 +0,0 @@
-<input type="text" name="query" value="search tools" id="tool-search-query" autocomplete="off" class="search-query parent-width" />
-<img src="{{spinner_url}}" id="search-spinner" class="search-spinner"/>
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/packed/handlebars/compiled/panel_label.js
--- a/static/scripts/packed/handlebars/compiled/panel_label.js
+++ /dev/null
@@ -1,1 +0,0 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.panel_label=b(function(e,n,d,l,k){d=d||e.helpers;var i="",c,h,o=this,f="function",m=d.helperMissing,g=void 0,j=this.escapeExpression;i+="<span>";h=d.name;c=h||n.name;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"name",{hash:{}})}}i+=j(c)+"</span>";return i})})();
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/packed/handlebars/compiled/panel_section.js
--- a/static/scripts/packed/handlebars/compiled/panel_section.js
+++ /dev/null
@@ -1,1 +0,0 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.panel_section=b(function(e,n,d,l,k){d=d||e.helpers;var i="",c,h,o=this,f="function",m=d.helperMissing,g=void 0,j=this.escapeExpression;i+='<div class="toolSectionTitle" id="title_';h=d.id;c=h||n.id;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"id",{hash:{}})}}i+=j(c)+'">\n <a href="#"><span>';h=d.name;c=h||n.name;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"name",{hash:{}})}}i+=j(c)+'</span></a>\n</div>\n<div id="';h=d.id;c=h||n.id;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"id",{hash:{}})}}i+=j(c)+'" class="toolSectionBody" style="display: none; ">\n <div class="toolSectionBg"></div>\n<div>';return i})})();
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/packed/handlebars/compiled/tool_form.js
--- a/static/scripts/packed/handlebars/compiled/tool_form.js
+++ /dev/null
@@ -1,1 +0,0 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.tool_form=b(function(f,p,e,n,m){e=e||f.helpers;var k="",c,r,j,i,q=this,g="function",o=e.helperMissing,h=void 0,l=this.escapeExpression;function d(v,u){var s="",t;s+='\n <div class="form-row">\n <label for="';j=e.name;t=j||v.name;if(typeof t===g){t=t.call(v,{hash:{}})}else{if(t===h){t=o.call(v,"name",{hash:{}})}}s+=l(t)+'">';j=e.label;t=j||v.label;if(typeof t===g){t=t.call(v,{hash:{}})}else{if(t===h){t=o.call(v,"label",{hash:{}})}}s+=l(t)+':</label>\n <div class="form-row-input">\n ';j=e.html;t=j||v.html;if(typeof t===g){t=t.call(v,{hash:{}})}else{if(t===h){t=o.call(v,"html",{hash:{}})}}if(t||t===0){s+=t}s+='\n </div>\n <div class="toolParamHelp" style="clear: both;">\n ';j=e.help;t=j||v.help;if(typeof t===g){t=t.call(v,{hash:{}})}else{if(t===h){t=o.call(v,"help",{hash:{}})}}s+=l(t)+'\n </div>\n <div style="clear: both;"></div>\n </div>\n ';return s}k+='<div class="toolFormTitle">';j=e.name;c=j||p.name;if(typeof c===g){c=c.call(p,{hash:{}})}else{if(c===h){c=o.call(p,"name",{hash:{}})}}k+=l(c)+" (version ";j=e.version;c=j||p.version;if(typeof c===g){c=c.call(p,{hash:{}})}else{if(c===h){c=o.call(p,"version",{hash:{}})}}k+=l(c)+')</div>\n <div class="toolFormBody">\n ';j=e.inputs;c=j||p.inputs;r=e.each;i=q.program(1,d,m);i.hash={};i.fn=i;i.inverse=q.noop;c=r.call(p,c,i);if(c||c===0){k+=c}k+='\n </div>\n <div class="form-row form-actions">\n <input type="submit" class="btn btn-primary" name="runtool_btn" value="Execute">\n</div>\n<div class="toolHelp">\n <div class="toolHelpBody">';j=e.help;c=j||p.help;if(typeof c===g){c=c.call(p,{hash:{}})}else{if(c===h){c=o.call(p,"help",{hash:{}})}}k+=l(c)+"</div>\n</div>";return k})})();
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/packed/handlebars/compiled/tool_link.js
--- a/static/scripts/packed/handlebars/compiled/tool_link.js
+++ /dev/null
@@ -1,1 +0,0 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.tool_link=b(function(e,n,d,l,k){d=d||e.helpers;var i="",c,h,o=this,f="function",m=d.helperMissing,g=void 0,j=this.escapeExpression;i+='<a class="';h=d.id;c=h||n.id;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"id",{hash:{}})}}i+=j(c)+' tool-link" href="';h=d.link;c=h||n.link;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"link",{hash:{}})}}i+=j(c)+'" target="';h=d.target;c=h||n.target;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"target",{hash:{}})}}i+=j(c)+'" minsizehint="';h=d.min_width;c=h||n.min_width;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"min_width",{hash:{}})}}i+=j(c)+'">';h=d.name;c=h||n.name;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"name",{hash:{}})}}i+=j(c)+"</a> ";h=d.description;c=h||n.description;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"description",{hash:{}})}}i+=j(c);return i})})();
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/packed/handlebars/compiled/tool_search.js
--- a/static/scripts/packed/handlebars/compiled/tool_search.js
+++ /dev/null
@@ -1,1 +0,0 @@
-(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.tool_search=b(function(e,n,d,l,k){d=d||e.helpers;var i="",c,h,o=this,f="function",m=d.helperMissing,g=void 0,j=this.escapeExpression;i+='<input type="text" name="query" value="search tools" id="tool-search-query" autocomplete="off" class="search-query parent-width" />\n<img src="';h=d.spinner_url;c=h||n.spinner_url;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"spinner_url",{hash:{}})}}i+=j(c)+'" id="search-spinner" class="search-spinner"/>\n';return i})})();
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/packed/templates/compiled/panel_label.js
--- /dev/null
+++ b/static/scripts/packed/templates/compiled/panel_label.js
@@ -0,0 +1,1 @@
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.panel_label=b(function(e,n,d,l,k){d=d||e.helpers;var i="",c,h,o=this,f="function",m=d.helperMissing,g=void 0,j=this.escapeExpression;i+="<span>";h=d.name;c=h||n.name;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"name",{hash:{}})}}i+=j(c)+"</span>";return i})})();
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/packed/templates/compiled/panel_section.js
--- /dev/null
+++ b/static/scripts/packed/templates/compiled/panel_section.js
@@ -0,0 +1,1 @@
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.panel_section=b(function(e,n,d,l,k){d=d||e.helpers;var i="",c,h,o=this,f="function",m=d.helperMissing,g=void 0,j=this.escapeExpression;i+='<div class="toolSectionTitle" id="title_';h=d.id;c=h||n.id;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"id",{hash:{}})}}i+=j(c)+'">\n <a href="#"><span>';h=d.name;c=h||n.name;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"name",{hash:{}})}}i+=j(c)+'</span></a>\n</div>\n<div id="';h=d.id;c=h||n.id;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"id",{hash:{}})}}i+=j(c)+'" class="toolSectionBody" style="display: none; ">\n <div class="toolSectionBg"></div>\n<div>';return i})})();
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/packed/templates/compiled/tool_form.js
--- /dev/null
+++ b/static/scripts/packed/templates/compiled/tool_form.js
@@ -0,0 +1,1 @@
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.tool_form=b(function(f,p,e,n,m){e=e||f.helpers;var k="",c,r,j,i,q=this,g="function",o=e.helperMissing,h=void 0,l=this.escapeExpression;function d(v,u){var s="",t;s+='\n <div class="form-row">\n <label for="';j=e.name;t=j||v.name;if(typeof t===g){t=t.call(v,{hash:{}})}else{if(t===h){t=o.call(v,"name",{hash:{}})}}s+=l(t)+'">';j=e.label;t=j||v.label;if(typeof t===g){t=t.call(v,{hash:{}})}else{if(t===h){t=o.call(v,"label",{hash:{}})}}s+=l(t)+':</label>\n <div class="form-row-input">\n ';j=e.html;t=j||v.html;if(typeof t===g){t=t.call(v,{hash:{}})}else{if(t===h){t=o.call(v,"html",{hash:{}})}}if(t||t===0){s+=t}s+='\n </div>\n <div class="toolParamHelp" style="clear: both;">\n ';j=e.help;t=j||v.help;if(typeof t===g){t=t.call(v,{hash:{}})}else{if(t===h){t=o.call(v,"help",{hash:{}})}}s+=l(t)+'\n </div>\n <div style="clear: both;"></div>\n </div>\n ';return s}k+='<div class="toolFormTitle">';j=e.name;c=j||p.name;if(typeof c===g){c=c.call(p,{hash:{}})}else{if(c===h){c=o.call(p,"name",{hash:{}})}}k+=l(c)+" (version ";j=e.version;c=j||p.version;if(typeof c===g){c=c.call(p,{hash:{}})}else{if(c===h){c=o.call(p,"version",{hash:{}})}}k+=l(c)+')</div>\n <div class="toolFormBody">\n ';j=e.inputs;c=j||p.inputs;r=e.each;i=q.program(1,d,m);i.hash={};i.fn=i;i.inverse=q.noop;c=r.call(p,c,i);if(c||c===0){k+=c}k+='\n </div>\n <div class="form-row form-actions">\n <input type="submit" class="btn btn-primary" name="runtool_btn" value="Execute">\n</div>\n<div class="toolHelp">\n <div class="toolHelpBody">';j=e.help;c=j||p.help;if(typeof c===g){c=c.call(p,{hash:{}})}else{if(c===h){c=o.call(p,"help",{hash:{}})}}k+=l(c)+"</div>\n</div>";return k})})();
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/packed/templates/compiled/tool_link.js
--- /dev/null
+++ b/static/scripts/packed/templates/compiled/tool_link.js
@@ -0,0 +1,1 @@
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.tool_link=b(function(e,n,d,l,k){d=d||e.helpers;var i="",c,h,o=this,f="function",m=d.helperMissing,g=void 0,j=this.escapeExpression;i+='<a class="';h=d.id;c=h||n.id;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"id",{hash:{}})}}i+=j(c)+' tool-link" href="';h=d.link;c=h||n.link;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"link",{hash:{}})}}i+=j(c)+'" target="';h=d.target;c=h||n.target;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"target",{hash:{}})}}i+=j(c)+'" minsizehint="';h=d.min_width;c=h||n.min_width;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"min_width",{hash:{}})}}i+=j(c)+'">';h=d.name;c=h||n.name;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"name",{hash:{}})}}i+=j(c)+"</a> ";h=d.description;c=h||n.description;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"description",{hash:{}})}}i+=j(c);return i})})();
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/packed/templates/compiled/tool_search.js
--- /dev/null
+++ b/static/scripts/packed/templates/compiled/tool_search.js
@@ -0,0 +1,1 @@
+(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.tool_search=b(function(e,n,d,l,k){d=d||e.helpers;var i="",c,h,o=this,f="function",m=d.helperMissing,g=void 0,j=this.escapeExpression;i+='<input type="text" name="query" value="search tools" id="tool-search-query" autocomplete="off" class="search-query parent-width" />\n<img src="';h=d.spinner_url;c=h||n.spinner_url;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"spinner_url",{hash:{}})}}i+=j(c)+'" id="search-spinner" class="search-spinner"/>\n';return i})})();
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/templates/compile_templates.py
--- /dev/null
+++ b/static/scripts/templates/compile_templates.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# Script requires handlebars compiler be installed; use node package manager
+# to install handlebars.
+
+import sys
+
+from glob import glob
+from subprocess import call
+from shutil import copyfile
+from os import path
+
+cmd = "handlebars %s -f compiled/%s.js"
+
+# If specific scripts specified on command line, just pack them, otherwise pack
+# all.
+
+if len( sys.argv ) > 1:
+ to_pack = sys.argv[1:]
+else:
+ to_pack = glob( "*.handlebars" )
+
+for fname in to_pack:
+ fname_base = path.splitext( path.split( fname )[1] )[0]
+ print "%s --> compiled/%s.js" % ( fname, fname_base )
+ out = call( cmd % ( fname, fname_base ), shell=True )
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/templates/compiled/panel_label.js
--- /dev/null
+++ b/static/scripts/templates/compiled/panel_label.js
@@ -0,0 +1,15 @@
+(function() {
+ var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
+templates['panel_label'] = template(function (Handlebars,depth0,helpers,partials,data) {
+ helpers = helpers || Handlebars.helpers;
+ var buffer = "", stack1, foundHelper, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression;
+
+
+ buffer += "<span>";
+ foundHelper = helpers.name;
+ stack1 = foundHelper || depth0.name;
+ if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
+ else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); }
+ buffer += escapeExpression(stack1) + "</span>";
+ return buffer;});
+})();
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/templates/compiled/panel_section.js
--- /dev/null
+++ b/static/scripts/templates/compiled/panel_section.js
@@ -0,0 +1,25 @@
+(function() {
+ var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
+templates['panel_section'] = template(function (Handlebars,depth0,helpers,partials,data) {
+ helpers = helpers || Handlebars.helpers;
+ var buffer = "", stack1, foundHelper, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression;
+
+
+ buffer += "<div class=\"toolSectionTitle\" id=\"title_";
+ foundHelper = helpers.id;
+ stack1 = foundHelper || depth0.id;
+ if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
+ else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "id", { hash: {} }); }
+ buffer += escapeExpression(stack1) + "\">\n <a href=\"#\"><span>";
+ foundHelper = helpers.name;
+ stack1 = foundHelper || depth0.name;
+ if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
+ else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); }
+ buffer += escapeExpression(stack1) + "</span></a>\n</div>\n<div id=\"";
+ foundHelper = helpers.id;
+ stack1 = foundHelper || depth0.id;
+ if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
+ else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "id", { hash: {} }); }
+ buffer += escapeExpression(stack1) + "\" class=\"toolSectionBody\" style=\"display: none; \">\n <div class=\"toolSectionBg\"></div>\n<div>";
+ return buffer;});
+})();
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/templates/compiled/tool_form.js
--- /dev/null
+++ b/static/scripts/templates/compiled/tool_form.js
@@ -0,0 +1,61 @@
+(function() {
+ var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
+templates['tool_form'] = template(function (Handlebars,depth0,helpers,partials,data) {
+ helpers = helpers || Handlebars.helpers;
+ var buffer = "", stack1, stack2, foundHelper, tmp1, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression;
+
+function program1(depth0,data) {
+
+ var buffer = "", stack1;
+ buffer += "\n <div class=\"form-row\">\n <label for=\"";
+ foundHelper = helpers.name;
+ stack1 = foundHelper || depth0.name;
+ if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
+ else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); }
+ buffer += escapeExpression(stack1) + "\">";
+ foundHelper = helpers.label;
+ stack1 = foundHelper || depth0.label;
+ if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
+ else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "label", { hash: {} }); }
+ buffer += escapeExpression(stack1) + ":</label>\n <div class=\"form-row-input\">\n ";
+ foundHelper = helpers.html;
+ stack1 = foundHelper || depth0.html;
+ if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
+ else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "html", { hash: {} }); }
+ if(stack1 || stack1 === 0) { buffer += stack1; }
+ buffer += "\n </div>\n <div class=\"toolParamHelp\" style=\"clear: both;\">\n ";
+ foundHelper = helpers.help;
+ stack1 = foundHelper || depth0.help;
+ if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
+ else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "help", { hash: {} }); }
+ buffer += escapeExpression(stack1) + "\n </div>\n <div style=\"clear: both;\"></div>\n </div>\n ";
+ return buffer;}
+
+ buffer += "<div class=\"toolFormTitle\">";
+ foundHelper = helpers.name;
+ stack1 = foundHelper || depth0.name;
+ if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
+ else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); }
+ buffer += escapeExpression(stack1) + " (version ";
+ foundHelper = helpers.version;
+ stack1 = foundHelper || depth0.version;
+ if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
+ else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "version", { hash: {} }); }
+ buffer += escapeExpression(stack1) + ")</div>\n <div class=\"toolFormBody\">\n ";
+ foundHelper = helpers.inputs;
+ stack1 = foundHelper || depth0.inputs;
+ stack2 = helpers.each;
+ tmp1 = self.program(1, program1, data);
+ tmp1.hash = {};
+ tmp1.fn = tmp1;
+ tmp1.inverse = self.noop;
+ stack1 = stack2.call(depth0, stack1, tmp1);
+ if(stack1 || stack1 === 0) { buffer += stack1; }
+ buffer += "\n </div>\n <div class=\"form-row form-actions\">\n <input type=\"submit\" class=\"btn btn-primary\" name=\"runtool_btn\" value=\"Execute\">\n</div>\n<div class=\"toolHelp\">\n <div class=\"toolHelpBody\">";
+ foundHelper = helpers.help;
+ stack1 = foundHelper || depth0.help;
+ if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
+ else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "help", { hash: {} }); }
+ buffer += escapeExpression(stack1) + "</div>\n</div>";
+ return buffer;});
+})();
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/templates/compiled/tool_link.js
--- /dev/null
+++ b/static/scripts/templates/compiled/tool_link.js
@@ -0,0 +1,40 @@
+(function() {
+ var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
+templates['tool_link'] = template(function (Handlebars,depth0,helpers,partials,data) {
+ helpers = helpers || Handlebars.helpers;
+ var buffer = "", stack1, foundHelper, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression;
+
+
+ buffer += "<a class=\"";
+ foundHelper = helpers.id;
+ stack1 = foundHelper || depth0.id;
+ if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
+ else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "id", { hash: {} }); }
+ buffer += escapeExpression(stack1) + " tool-link\" href=\"";
+ foundHelper = helpers.link;
+ stack1 = foundHelper || depth0.link;
+ if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
+ else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "link", { hash: {} }); }
+ buffer += escapeExpression(stack1) + "\" target=\"";
+ foundHelper = helpers.target;
+ stack1 = foundHelper || depth0.target;
+ if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
+ else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "target", { hash: {} }); }
+ buffer += escapeExpression(stack1) + "\" minsizehint=\"";
+ foundHelper = helpers.min_width;
+ stack1 = foundHelper || depth0.min_width;
+ if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
+ else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "min_width", { hash: {} }); }
+ buffer += escapeExpression(stack1) + "\">";
+ foundHelper = helpers.name;
+ stack1 = foundHelper || depth0.name;
+ if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
+ else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "name", { hash: {} }); }
+ buffer += escapeExpression(stack1) + "</a> ";
+ foundHelper = helpers.description;
+ stack1 = foundHelper || depth0.description;
+ if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
+ else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "description", { hash: {} }); }
+ buffer += escapeExpression(stack1);
+ return buffer;});
+})();
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/templates/compiled/tool_search.js
--- /dev/null
+++ b/static/scripts/templates/compiled/tool_search.js
@@ -0,0 +1,15 @@
+(function() {
+ var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
+templates['tool_search'] = template(function (Handlebars,depth0,helpers,partials,data) {
+ helpers = helpers || Handlebars.helpers;
+ var buffer = "", stack1, foundHelper, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression;
+
+
+ buffer += "<input type=\"text\" name=\"query\" value=\"search tools\" id=\"tool-search-query\" autocomplete=\"off\" class=\"search-query parent-width\" />\n<img src=\"";
+ foundHelper = helpers.spinner_url;
+ stack1 = foundHelper || depth0.spinner_url;
+ if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
+ else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "spinner_url", { hash: {} }); }
+ buffer += escapeExpression(stack1) + "\" id=\"search-spinner\" class=\"search-spinner\"/>\n";
+ return buffer;});
+})();
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/templates/panel_label.handlebars
--- /dev/null
+++ b/static/scripts/templates/panel_label.handlebars
@@ -0,0 +1,1 @@
+<span>{{name}}</span>
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/templates/panel_section.handlebars
--- /dev/null
+++ b/static/scripts/templates/panel_section.handlebars
@@ -0,0 +1,6 @@
+<div class="toolSectionTitle" id="title_{{id}}">
+ <a href="#"><span>{{name}}</span></a>
+</div>
+<div id="{{id}}" class="toolSectionBody" style="display: none; ">
+ <div class="toolSectionBg"></div>
+<div>
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/templates/tool_form.handlebars
--- /dev/null
+++ b/static/scripts/templates/tool_form.handlebars
@@ -0,0 +1,21 @@
+<div class="toolFormTitle">{{name}} (version {{version}})</div>
+ <div class="toolFormBody">
+ {{#each inputs}}
+ <div class="form-row">
+ <label for="{{name}}">{{label}}:</label>
+ <div class="form-row-input">
+ {{{html}}}
+ </div>
+ <div class="toolParamHelp" style="clear: both;">
+ {{help}}
+ </div>
+ <div style="clear: both;"></div>
+ </div>
+ {{/each}}
+ </div>
+ <div class="form-row form-actions">
+ <input type="submit" class="btn btn-primary" name="runtool_btn" value="Execute">
+</div>
+<div class="toolHelp">
+ <div class="toolHelpBody">{{help}}</div>
+</div>
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/templates/tool_link.handlebars
--- /dev/null
+++ b/static/scripts/templates/tool_link.handlebars
@@ -0,0 +1,1 @@
+<a class="{{id}} tool-link" href="{{link}}" target="{{target}}" minsizehint="{{min_width}}">{{name}}</a> {{description}}
\ No newline at end of file
diff -r 272506e479f54d41b345c373786c23cab57cc153 -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d static/scripts/templates/tool_search.handlebars
--- /dev/null
+++ b/static/scripts/templates/tool_search.handlebars
@@ -0,0 +1,2 @@
+<input type="text" name="query" value="search tools" id="tool-search-query" autocomplete="off" class="search-query parent-width" />
+<img src="{{spinner_url}}" id="search-spinner" class="search-spinner"/>
https://bitbucket.org/galaxy/galaxy-central/changeset/e7dc2ec85d1b/
changeset: e7dc2ec85d1b
user: jgoecks
date: 2012-04-12 20:29:36
summary: Change name of directory with backbone code to mvc.
affected #: 8 files
diff -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d -r e7dc2ec85d1ba124bd7f4558b3c5c89b56d55a0f static/scripts/backbone/tools.js
--- a/static/scripts/backbone/tools.js
+++ /dev/null
@@ -1,529 +0,0 @@
-/**
- * Model classes for Galaxy tools and tool panel. Models have no references to views,
- * instead using events to indicate state changes; this is advantageous because
- * multiple views can use the same object and models can be used without views.
- */
-
-/**
- * Simple base model for any visible element. Includes useful attributes and ability
- * to set and track visibility.
- */
-var BaseModel = Backbone.RelationalModel.extend({
- defaults: {
- name: null,
- hidden: false
- },
-
- show: function() {
- this.set("hidden", false);
- },
-
- hide: function() {
- this.set("hidden", true);
- },
-
- is_visible: function() {
- return !this.attributes.hidden;
- }
-});
-
-/**
- * A Galaxy tool.
- */
-var Tool = BaseModel.extend({
- // Default attributes.
- defaults: {
- description: null,
- target: null,
- inputs: []
- },
-
- relations: [
- {
- type: Backbone.HasMany,
- key: 'inputs',
- relatedModel: 'ToolInput',
- reverseRelation: {
- key: 'tool'
- }
- }
- ],
-
- urlRoot: galaxy_paths.attributes.root_path + 'api/tools',
-
- apply_search_results: function(results) {
- ( _.indexOf(results, this.attributes.id) !== -1 ? this.show() : this.hide() );
- return this.is_visible();
- }
-});
-
-/**
- * A tool input.
- */
-var ToolInput = Backbone.RelationalModel.extend({
-
- initialize: function() {
- this.attributes.html = unescape(this.attributes.html);
- }
-
-});
-
-/**
- * Wrap collection of tools for fast access/manipulation.
- */
-var ToolCollection = Backbone.Collection.extend({
- model: Tool
-});
-
-/**
- * Label or section header in tool panel.
- */
-var ToolPanelLabel = BaseModel.extend({});
-
-/**
- * Section of tool panel with elements (labels and tools).
- */
-var ToolPanelSection = BaseModel.extend({
- defaults: {
- elems: [],
- open: false
- },
-
- clear_search_results: function() {
- _.each(this.attributes.elems, function(elt) {
- elt.show();
- });
-
- this.show();
- this.set("open", false);
- },
-
- apply_search_results: function(results) {
- var all_hidden = true,
- cur_label;
- _.each(this.attributes.elems, function(elt) {
- if (elt instanceof ToolPanelLabel) {
- cur_label = elt;
- cur_label.hide();
- }
- else if (elt instanceof Tool) {
- if (elt.apply_search_results(results)) {
- all_hidden = false;
- if (cur_label) {
- cur_label.show();
- }
- }
- }
- });
-
- if (all_hidden) {
- this.hide();
- }
- else {
- this.show();
- this.set("open", true);
- }
- }
-});
-
-/**
- * Tool search that updates results when query is changed. Result value of null
- * indicates that query was not run; if not null, results are from search using
- * query.
- */
-var ToolSearch = BaseModel.extend({
- defaults: {
- spinner_url: "",
- search_url: "",
- visible: true,
- query: "",
- results: null
- },
-
- initialize: function() {
- this.on("change:query", this.do_search);
- },
-
- /**
- * Do the search and update the results.
- */
- do_search: function() {
- var query = this.attributes.query;
-
- // If query is too short, do not search.
- if (query.length < 3) {
- this.set("results", null);
- return;
- }
-
- // Do search via AJAX.
- var q = query + '*';
- // Stop previous ajax-request
- if (this.timer) {
- clearTimeout(this.timer);
- }
- // Start a new ajax-request in X ms
- $("#search-spinner").show();
- var self = this;
- this.timer = setTimeout(function () {
- $.get(self.attributes.search_url, { query: q }, function (data) {
- self.set("results", data);
- $("#search-spinner").hide();
- }, "json" );
- }, 200 );
- }
-});
-
-/**
- * A collection of ToolPanelSections, Tools, and ToolPanelLabels. Collection
- * applies search results as they become available.
- */
-var ToolPanel = Backbone.Collection.extend({
- url: "/tools",
- tools: new ToolCollection(),
-
- parse: function(response) {
- // Recursive function to parse tool panel elements.
- var parse_elt = function(elt_dict) {
- var type = elt_dict.type;
- if (type === 'tool') {
- return new Tool(elt_dict);
- }
- else if (type === 'section') {
- // Parse elements.
- var elems = _.map(elt_dict.elems, parse_elt);
- elt_dict.elems = elems;
- return new ToolPanelSection(elt_dict);
- }
- else if (type === 'label') {
- return new ToolPanelLabel(elt_dict);
- }
- };
-
- return _.map(response, parse_elt);
- },
-
- initialize: function(options) {
- this.tool_search = options.tool_search;
- this.tool_search.on("change:results", this.apply_search_results, this);
- this.on("reset", this.populate_tools, this);
- },
-
- /**
- * Populate tool collection from panel elements.
- */
- populate_tools: function() {
- var self = this;
- self.tools = new ToolCollection();
- this.each(function(panel_elt) {
- if (panel_elt instanceof ToolPanelSection) {
- _.each(panel_elt.attributes.elems, function (section_elt) {
- if (section_elt instanceof Tool) {
- self.tools.push(section_elt);
- }
- });
- }
- else if (panel_elt instanceof Tool) {
- self.tools.push(panel_elt);
- }
- });
- },
-
- clear_search_results: function() {
- this.each(function(panel_elt) {
- if (panel_elt instanceof ToolPanelSection) {
- panel_elt.clear_search_results();
- }
- else {
- // Label or tool, so just show.
- panel_elt.show();
- }
- });
- },
-
- apply_search_results: function() {
- var results = this.tool_search.attributes.results;
- if (results === null) {
- this.clear_search_results();
- return;
- }
-
- var cur_label = null;
- this.each(function(panel_elt) {
- if (panel_elt instanceof ToolPanelLabel) {
- cur_label = panel_elt;
- cur_label.hide();
- }
- else if (panel_elt instanceof Tool) {
- if (panel_elt.apply_search_results(results)) {
- if (cur_label) {
- cur_label.show();
- }
- }
- }
- else {
- // Starting new section, so clear current label.
- cur_label = null;
- panel_elt.apply_search_results(results);
- }
- });
- }
-});
-
-/**
- * View classes for Galaxy tools and tool panel.
- *
- * Views use precompiled Handlebars templates for rendering. Views update as needed
- * based on (a) model/collection events and (b) user interactions; in this sense,
- * they are controllers are well and the HTML is the real view in the MVC architecture.
- */
-
-/**
- * Base view that handles visibility based on model's hidden attribute.
- */
-var BaseView = Backbone.View.extend({
- initialize: function() {
- this.model.on("change:hidden", this.update_visible, this);
- this.update_visible();
- },
- update_visible: function() {
- ( this.model.attributes.hidden ? this.$el.hide() : this.$el.show() );
- }
-});
-
-/**
- * Link to a tool.
- */
-var ToolLinkView = BaseView.extend({
- tagName: 'div',
- template: Handlebars.templates.tool_link,
-
- render: function() {
- this.$el.append( this.template(this.model.toJSON()) );
- return this;
- }
-});
-
-/**
- * Panel label/section header.
- */
-var ToolPanelLabelView = BaseView.extend({
- tagName: 'div',
- className: 'toolPanelLabel',
- template: Handlebars.templates.panel_label,
-
- render: function() {
- this.$el.append( this.template(this.model.toJSON()) );
- return this;
- },
-});
-
-/**
- * Panel section.
- */
-var ToolPanelSectionView = BaseView.extend({
- tagName: 'div',
- className: 'toolSectionWrapper',
- template: Handlebars.templates.panel_section,
- initialize: function() {
- BaseView.prototype.initialize.call(this);
- this.model.on("change:open", this.update_open, this);
- },
- render: function() {
- // Build using template.
- this.$el.append( this.template(this.model.toJSON()) );
-
- // Add tools to section.
- var section_body = this.$el.find(".toolSectionBody");
- _.each(this.model.attributes.elems, function(elt) {
- if (elt instanceof Tool) {
- var tool_view = new ToolLinkView({model: elt, className: "toolTitle"});
- tool_view.render();
- section_body.append(tool_view.$el);
- }
- else if (elt instanceof ToolPanelLabel) {
- var label_view = new ToolPanelLabelView({model: elt});
- label_view.render();
- section_body.append(label_view.$el);
- }
- else {
- // TODO: handle nested section bodies?
- }
- });
- return this;
- },
-
- events: {
- 'click .toolSectionTitle > a': 'toggle'
- },
-
- /**
- * Toggle visibility of tool section.
- */
- toggle: function() {
- this.model.set("open", !this.model.attributes.open);
- },
-
- /**
- * Update whether section is open or close.
- */
- update_open: function() {
- (this.model.attributes.open ?
- this.$el.children(".toolSectionBody").slideDown("fast") :
- this.$el.children(".toolSectionBody").slideUp("fast")
- );
- }
-});
-
-var ToolSearchView = Backbone.View.extend({
- tagName: 'div',
- id: 'tool-search',
- className: 'bar',
- template: Handlebars.templates.tool_search,
-
- events: {
- 'click': 'focus_and_select',
- 'keyup :input': 'query_changed'
- },
-
- render: function() {
- this.$el.append( this.template(this.model.toJSON()) );
- if (!this.model.is_visible()) {
- this.$el.hide();
- }
- return this;
- },
-
- focus_and_select: function() {
- this.$el.find(":input").focus().select();
- },
-
- query_changed: function() {
- this.model.set("query", this.$el.find(":input").val());
- }
-});
-
-/**
- * Tool panel view. Events triggered include:
- * tool_link_click(click event, tool_model)
- */
-var ToolPanelView = Backbone.View.extend({
- tagName: 'div',
- className: 'toolMenu',
-
- /**
- * Waits for collection to load and then renders.
- */
- initialize: function() {
- this.collection.tool_search.on("change:results", this.handle_search_results, this);
- },
-
- render: function() {
- var self = this;
-
- // Render search.
- var search_view = new ToolSearchView( {model: this.collection.tool_search} );
- search_view.render();
- self.$el.append(search_view.$el);
-
- // Render panel.
- this.collection.each(function(panel_elt) {
- if (panel_elt instanceof ToolPanelSection) {
- var section_title_view = new ToolPanelSectionView({model: panel_elt});
- section_title_view.render();
- self.$el.append(section_title_view.$el);
- }
- else if (panel_elt instanceof Tool) {
- var tool_view = new ToolLinkView({model: panel_elt, className: "toolTitleNoSection"});
- tool_view.render();
- self.$el.append(tool_view.$el);
- }
- else if (panel_elt instanceof ToolPanelLabel) {
- var label_view = new ToolPanelLabelView({model: panel_elt});
- label_view.render();
- self.$el.append(label_view.$el);
- }
- });
-
- // Setup tool link click eventing.
- self.$el.find("a.tool-link").click(function(e) {
- // Tool id is always the first class.
- var
- tool_id = $(this).attr('class').split(/\s+/)[0],
- tool = self.collection.tools.get(tool_id);
-
- self.trigger("tool_link_click", e, tool);
- });
-
- return this;
- },
-
- handle_search_results: function() {
- var results = this.collection.tool_search.attributes.results;
- if (results && results.length === 0) {
- $("#search-no-results").show();
- }
- else {
- $("#search-no-results").hide();
- }
- }
-});
-
-/**
- * View for working with a tool: setting parameters and inputs and executing the tool.
- */
-var ToolFormView = Backbone.View.extend({
- className: 'toolForm',
- template: Handlebars.templates.tool_form,
-
- render: function() {
- this.$el.children().remove();
- this.$el.append( this.template(this.model.toJSON()) );
- }
-});
-
-
-/**
- * Integrated tool menu + tool execution.
- */
-var IntegratedToolMenuAndView = Backbone.View.extend({
- className: 'toolMenuAndView',
-
- initialize: function() {
- this.tool_panel_view = new ToolPanelView({collection: this.collection});
- this.tool_form_view = new ToolFormView();
- },
-
- render: function() {
- // Render and append tool panel.
- this.tool_panel_view.render();
- this.tool_panel_view.$el.css("float", "left");
- this.$el.append(this.tool_panel_view.$el);
-
- // Append tool form view.
- this.tool_form_view.$el.hide();
- this.$el.append(this.tool_form_view.$el);
-
- // On tool link click, show tool.
- var self = this;
- this.tool_panel_view.on("tool_link_click", function(e, tool) {
- // Prevents click from activating link:
- e.preventDefault();
- // Show tool that was clicked on:
- self.show_tool(tool);
- });
- },
-
- /**
- * Fetch and display tool.
- */
- show_tool: function(tool) {
- var self = this;
- tool.fetch().done( function() {
- self.tool_form_view.model = tool;
- self.tool_form_view.render();
- self.tool_form_view.$el.show();
- $('#left').width("650px");
- });
- }
-});
\ No newline at end of file
diff -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d -r e7dc2ec85d1ba124bd7f4558b3c5c89b56d55a0f static/scripts/backbone/ui.js
--- a/static/scripts/backbone/ui.js
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * Utility models and views for Galaxy objects.
- */
-
-/**
- * Necessary Galaxy paths.
- */
-var GalaxyPaths = Backbone.Model.extend({
- defaults: {
- root_path: "",
- image_path: ""
- }
-});
-
-/**
- * Clickable button represented as an icon.
- */
-var IconButton = Backbone.Model.extend({
- defaults: {
- title: "",
- icon_class: "",
- on_click: null
- }
-});
-
-var IconButtonCollection = Backbone.Collection.extend({
- model: IconButton
-});
-
-/**
- * Menu with multiple icon buttons. Views are not needed nor used for individual buttons.
- */
-var IconButtonMenuView = Backbone.View.extend({
- tagName: 'div',
-
- render: function() {
- var self = this;
- this.collection.each(function(button) {
- // Create and add icon button to menu.
- $("<a/>").attr('href', 'javascript:void(0)')
- .attr('title', button.attributes.title)
- .addClass('icon-button menu-button')
- .addClass(button.attributes.icon_class)
- .appendTo(self.$el)
- .click(button.attributes.on_click);
- });
- return this;
- }
-});
-
-/**
- *
- */
-var Grid = Backbone.Collection.extend({
-
-});
-
-/**
- *
- */
-var GridView = Backbone.View.extend({
-
-});
-
-
diff -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d -r e7dc2ec85d1ba124bd7f4558b3c5c89b56d55a0f static/scripts/mvc/tools.js
--- /dev/null
+++ b/static/scripts/mvc/tools.js
@@ -0,0 +1,529 @@
+/**
+ * Model classes for Galaxy tools and tool panel. Models have no references to views,
+ * instead using events to indicate state changes; this is advantageous because
+ * multiple views can use the same object and models can be used without views.
+ */
+
+/**
+ * Simple base model for any visible element. Includes useful attributes and ability
+ * to set and track visibility.
+ */
+var BaseModel = Backbone.RelationalModel.extend({
+ defaults: {
+ name: null,
+ hidden: false
+ },
+
+ show: function() {
+ this.set("hidden", false);
+ },
+
+ hide: function() {
+ this.set("hidden", true);
+ },
+
+ is_visible: function() {
+ return !this.attributes.hidden;
+ }
+});
+
+/**
+ * A Galaxy tool.
+ */
+var Tool = BaseModel.extend({
+ // Default attributes.
+ defaults: {
+ description: null,
+ target: null,
+ inputs: []
+ },
+
+ relations: [
+ {
+ type: Backbone.HasMany,
+ key: 'inputs',
+ relatedModel: 'ToolInput',
+ reverseRelation: {
+ key: 'tool'
+ }
+ }
+ ],
+
+ urlRoot: galaxy_paths.attributes.root_path + 'api/tools',
+
+ apply_search_results: function(results) {
+ ( _.indexOf(results, this.attributes.id) !== -1 ? this.show() : this.hide() );
+ return this.is_visible();
+ }
+});
+
+/**
+ * A tool input.
+ */
+var ToolInput = Backbone.RelationalModel.extend({
+
+ initialize: function() {
+ this.attributes.html = unescape(this.attributes.html);
+ }
+
+});
+
+/**
+ * Wrap collection of tools for fast access/manipulation.
+ */
+var ToolCollection = Backbone.Collection.extend({
+ model: Tool
+});
+
+/**
+ * Label or section header in tool panel.
+ */
+var ToolPanelLabel = BaseModel.extend({});
+
+/**
+ * Section of tool panel with elements (labels and tools).
+ */
+var ToolPanelSection = BaseModel.extend({
+ defaults: {
+ elems: [],
+ open: false
+ },
+
+ clear_search_results: function() {
+ _.each(this.attributes.elems, function(elt) {
+ elt.show();
+ });
+
+ this.show();
+ this.set("open", false);
+ },
+
+ apply_search_results: function(results) {
+ var all_hidden = true,
+ cur_label;
+ _.each(this.attributes.elems, function(elt) {
+ if (elt instanceof ToolPanelLabel) {
+ cur_label = elt;
+ cur_label.hide();
+ }
+ else if (elt instanceof Tool) {
+ if (elt.apply_search_results(results)) {
+ all_hidden = false;
+ if (cur_label) {
+ cur_label.show();
+ }
+ }
+ }
+ });
+
+ if (all_hidden) {
+ this.hide();
+ }
+ else {
+ this.show();
+ this.set("open", true);
+ }
+ }
+});
+
+/**
+ * Tool search that updates results when query is changed. Result value of null
+ * indicates that query was not run; if not null, results are from search using
+ * query.
+ */
+var ToolSearch = BaseModel.extend({
+ defaults: {
+ spinner_url: "",
+ search_url: "",
+ visible: true,
+ query: "",
+ results: null
+ },
+
+ initialize: function() {
+ this.on("change:query", this.do_search);
+ },
+
+ /**
+ * Do the search and update the results.
+ */
+ do_search: function() {
+ var query = this.attributes.query;
+
+ // If query is too short, do not search.
+ if (query.length < 3) {
+ this.set("results", null);
+ return;
+ }
+
+ // Do search via AJAX.
+ var q = query + '*';
+ // Stop previous ajax-request
+ if (this.timer) {
+ clearTimeout(this.timer);
+ }
+ // Start a new ajax-request in X ms
+ $("#search-spinner").show();
+ var self = this;
+ this.timer = setTimeout(function () {
+ $.get(self.attributes.search_url, { query: q }, function (data) {
+ self.set("results", data);
+ $("#search-spinner").hide();
+ }, "json" );
+ }, 200 );
+ }
+});
+
+/**
+ * A collection of ToolPanelSections, Tools, and ToolPanelLabels. Collection
+ * applies search results as they become available.
+ */
+var ToolPanel = Backbone.Collection.extend({
+ url: "/tools",
+ tools: new ToolCollection(),
+
+ parse: function(response) {
+ // Recursive function to parse tool panel elements.
+ var parse_elt = function(elt_dict) {
+ var type = elt_dict.type;
+ if (type === 'tool') {
+ return new Tool(elt_dict);
+ }
+ else if (type === 'section') {
+ // Parse elements.
+ var elems = _.map(elt_dict.elems, parse_elt);
+ elt_dict.elems = elems;
+ return new ToolPanelSection(elt_dict);
+ }
+ else if (type === 'label') {
+ return new ToolPanelLabel(elt_dict);
+ }
+ };
+
+ return _.map(response, parse_elt);
+ },
+
+ initialize: function(options) {
+ this.tool_search = options.tool_search;
+ this.tool_search.on("change:results", this.apply_search_results, this);
+ this.on("reset", this.populate_tools, this);
+ },
+
+ /**
+ * Populate tool collection from panel elements.
+ */
+ populate_tools: function() {
+ var self = this;
+ self.tools = new ToolCollection();
+ this.each(function(panel_elt) {
+ if (panel_elt instanceof ToolPanelSection) {
+ _.each(panel_elt.attributes.elems, function (section_elt) {
+ if (section_elt instanceof Tool) {
+ self.tools.push(section_elt);
+ }
+ });
+ }
+ else if (panel_elt instanceof Tool) {
+ self.tools.push(panel_elt);
+ }
+ });
+ },
+
+ clear_search_results: function() {
+ this.each(function(panel_elt) {
+ if (panel_elt instanceof ToolPanelSection) {
+ panel_elt.clear_search_results();
+ }
+ else {
+ // Label or tool, so just show.
+ panel_elt.show();
+ }
+ });
+ },
+
+ apply_search_results: function() {
+ var results = this.tool_search.attributes.results;
+ if (results === null) {
+ this.clear_search_results();
+ return;
+ }
+
+ var cur_label = null;
+ this.each(function(panel_elt) {
+ if (panel_elt instanceof ToolPanelLabel) {
+ cur_label = panel_elt;
+ cur_label.hide();
+ }
+ else if (panel_elt instanceof Tool) {
+ if (panel_elt.apply_search_results(results)) {
+ if (cur_label) {
+ cur_label.show();
+ }
+ }
+ }
+ else {
+ // Starting new section, so clear current label.
+ cur_label = null;
+ panel_elt.apply_search_results(results);
+ }
+ });
+ }
+});
+
+/**
+ * View classes for Galaxy tools and tool panel.
+ *
+ * Views use precompiled Handlebars templates for rendering. Views update as needed
+ * based on (a) model/collection events and (b) user interactions; in this sense,
+ * they are controllers are well and the HTML is the real view in the MVC architecture.
+ */
+
+/**
+ * Base view that handles visibility based on model's hidden attribute.
+ */
+var BaseView = Backbone.View.extend({
+ initialize: function() {
+ this.model.on("change:hidden", this.update_visible, this);
+ this.update_visible();
+ },
+ update_visible: function() {
+ ( this.model.attributes.hidden ? this.$el.hide() : this.$el.show() );
+ }
+});
+
+/**
+ * Link to a tool.
+ */
+var ToolLinkView = BaseView.extend({
+ tagName: 'div',
+ template: Handlebars.templates.tool_link,
+
+ render: function() {
+ this.$el.append( this.template(this.model.toJSON()) );
+ return this;
+ }
+});
+
+/**
+ * Panel label/section header.
+ */
+var ToolPanelLabelView = BaseView.extend({
+ tagName: 'div',
+ className: 'toolPanelLabel',
+ template: Handlebars.templates.panel_label,
+
+ render: function() {
+ this.$el.append( this.template(this.model.toJSON()) );
+ return this;
+ },
+});
+
+/**
+ * Panel section.
+ */
+var ToolPanelSectionView = BaseView.extend({
+ tagName: 'div',
+ className: 'toolSectionWrapper',
+ template: Handlebars.templates.panel_section,
+ initialize: function() {
+ BaseView.prototype.initialize.call(this);
+ this.model.on("change:open", this.update_open, this);
+ },
+ render: function() {
+ // Build using template.
+ this.$el.append( this.template(this.model.toJSON()) );
+
+ // Add tools to section.
+ var section_body = this.$el.find(".toolSectionBody");
+ _.each(this.model.attributes.elems, function(elt) {
+ if (elt instanceof Tool) {
+ var tool_view = new ToolLinkView({model: elt, className: "toolTitle"});
+ tool_view.render();
+ section_body.append(tool_view.$el);
+ }
+ else if (elt instanceof ToolPanelLabel) {
+ var label_view = new ToolPanelLabelView({model: elt});
+ label_view.render();
+ section_body.append(label_view.$el);
+ }
+ else {
+ // TODO: handle nested section bodies?
+ }
+ });
+ return this;
+ },
+
+ events: {
+ 'click .toolSectionTitle > a': 'toggle'
+ },
+
+ /**
+ * Toggle visibility of tool section.
+ */
+ toggle: function() {
+ this.model.set("open", !this.model.attributes.open);
+ },
+
+ /**
+ * Update whether section is open or close.
+ */
+ update_open: function() {
+ (this.model.attributes.open ?
+ this.$el.children(".toolSectionBody").slideDown("fast") :
+ this.$el.children(".toolSectionBody").slideUp("fast")
+ );
+ }
+});
+
+var ToolSearchView = Backbone.View.extend({
+ tagName: 'div',
+ id: 'tool-search',
+ className: 'bar',
+ template: Handlebars.templates.tool_search,
+
+ events: {
+ 'click': 'focus_and_select',
+ 'keyup :input': 'query_changed'
+ },
+
+ render: function() {
+ this.$el.append( this.template(this.model.toJSON()) );
+ if (!this.model.is_visible()) {
+ this.$el.hide();
+ }
+ return this;
+ },
+
+ focus_and_select: function() {
+ this.$el.find(":input").focus().select();
+ },
+
+ query_changed: function() {
+ this.model.set("query", this.$el.find(":input").val());
+ }
+});
+
+/**
+ * Tool panel view. Events triggered include:
+ * tool_link_click(click event, tool_model)
+ */
+var ToolPanelView = Backbone.View.extend({
+ tagName: 'div',
+ className: 'toolMenu',
+
+ /**
+ * Waits for collection to load and then renders.
+ */
+ initialize: function() {
+ this.collection.tool_search.on("change:results", this.handle_search_results, this);
+ },
+
+ render: function() {
+ var self = this;
+
+ // Render search.
+ var search_view = new ToolSearchView( {model: this.collection.tool_search} );
+ search_view.render();
+ self.$el.append(search_view.$el);
+
+ // Render panel.
+ this.collection.each(function(panel_elt) {
+ if (panel_elt instanceof ToolPanelSection) {
+ var section_title_view = new ToolPanelSectionView({model: panel_elt});
+ section_title_view.render();
+ self.$el.append(section_title_view.$el);
+ }
+ else if (panel_elt instanceof Tool) {
+ var tool_view = new ToolLinkView({model: panel_elt, className: "toolTitleNoSection"});
+ tool_view.render();
+ self.$el.append(tool_view.$el);
+ }
+ else if (panel_elt instanceof ToolPanelLabel) {
+ var label_view = new ToolPanelLabelView({model: panel_elt});
+ label_view.render();
+ self.$el.append(label_view.$el);
+ }
+ });
+
+ // Setup tool link click eventing.
+ self.$el.find("a.tool-link").click(function(e) {
+ // Tool id is always the first class.
+ var
+ tool_id = $(this).attr('class').split(/\s+/)[0],
+ tool = self.collection.tools.get(tool_id);
+
+ self.trigger("tool_link_click", e, tool);
+ });
+
+ return this;
+ },
+
+ handle_search_results: function() {
+ var results = this.collection.tool_search.attributes.results;
+ if (results && results.length === 0) {
+ $("#search-no-results").show();
+ }
+ else {
+ $("#search-no-results").hide();
+ }
+ }
+});
+
+/**
+ * View for working with a tool: setting parameters and inputs and executing the tool.
+ */
+var ToolFormView = Backbone.View.extend({
+ className: 'toolForm',
+ template: Handlebars.templates.tool_form,
+
+ render: function() {
+ this.$el.children().remove();
+ this.$el.append( this.template(this.model.toJSON()) );
+ }
+});
+
+
+/**
+ * Integrated tool menu + tool execution.
+ */
+var IntegratedToolMenuAndView = Backbone.View.extend({
+ className: 'toolMenuAndView',
+
+ initialize: function() {
+ this.tool_panel_view = new ToolPanelView({collection: this.collection});
+ this.tool_form_view = new ToolFormView();
+ },
+
+ render: function() {
+ // Render and append tool panel.
+ this.tool_panel_view.render();
+ this.tool_panel_view.$el.css("float", "left");
+ this.$el.append(this.tool_panel_view.$el);
+
+ // Append tool form view.
+ this.tool_form_view.$el.hide();
+ this.$el.append(this.tool_form_view.$el);
+
+ // On tool link click, show tool.
+ var self = this;
+ this.tool_panel_view.on("tool_link_click", function(e, tool) {
+ // Prevents click from activating link:
+ e.preventDefault();
+ // Show tool that was clicked on:
+ self.show_tool(tool);
+ });
+ },
+
+ /**
+ * Fetch and display tool.
+ */
+ show_tool: function(tool) {
+ var self = this;
+ tool.fetch().done( function() {
+ self.tool_form_view.model = tool;
+ self.tool_form_view.render();
+ self.tool_form_view.$el.show();
+ $('#left').width("650px");
+ });
+ }
+});
\ No newline at end of file
diff -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d -r e7dc2ec85d1ba124bd7f4558b3c5c89b56d55a0f static/scripts/mvc/ui.js
--- /dev/null
+++ b/static/scripts/mvc/ui.js
@@ -0,0 +1,65 @@
+/**
+ * Utility models and views for Galaxy objects.
+ */
+
+/**
+ * Necessary Galaxy paths.
+ */
+var GalaxyPaths = Backbone.Model.extend({
+ defaults: {
+ root_path: "",
+ image_path: ""
+ }
+});
+
+/**
+ * Clickable button represented as an icon.
+ */
+var IconButton = Backbone.Model.extend({
+ defaults: {
+ title: "",
+ icon_class: "",
+ on_click: null
+ }
+});
+
+var IconButtonCollection = Backbone.Collection.extend({
+ model: IconButton
+});
+
+/**
+ * Menu with multiple icon buttons. Views are not needed nor used for individual buttons.
+ */
+var IconButtonMenuView = Backbone.View.extend({
+ tagName: 'div',
+
+ render: function() {
+ var self = this;
+ this.collection.each(function(button) {
+ // Create and add icon button to menu.
+ $("<a/>").attr('href', 'javascript:void(0)')
+ .attr('title', button.attributes.title)
+ .addClass('icon-button menu-button')
+ .addClass(button.attributes.icon_class)
+ .appendTo(self.$el)
+ .click(button.attributes.on_click);
+ });
+ return this;
+ }
+});
+
+/**
+ *
+ */
+var Grid = Backbone.Collection.extend({
+
+});
+
+/**
+ *
+ */
+var GridView = Backbone.View.extend({
+
+});
+
+
diff -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d -r e7dc2ec85d1ba124bd7f4558b3c5c89b56d55a0f static/scripts/packed/backbone/tools.js
--- a/static/scripts/packed/backbone/tools.js
+++ /dev/null
@@ -1,1 +0,0 @@
-var BaseModel=Backbone.RelationalModel.extend({defaults:{name:null,hidden:false},show:function(){this.set("hidden",false)},hide:function(){this.set("hidden",true)},is_visible:function(){return !this.attributes.hidden}});var Tool=BaseModel.extend({defaults:{description:null,target:null,inputs:[]},relations:[{type:Backbone.HasMany,key:"inputs",relatedModel:"ToolInput",reverseRelation:{key:"tool"}}],url:function(){return galaxy_paths.attributes.root_path+"tools/show?id="+this.id},apply_search_results:function(a){(_.indexOf(a,this.attributes.id)!==-1?this.show():this.hide());return this.is_visible()}});var ToolInput=Backbone.RelationalModel.extend({});var ToolCollection=Backbone.Collection.extend({model:Tool});var ToolPanelLabel=BaseModel.extend({});var ToolPanelSection=BaseModel.extend({defaults:{elems:[],open:false},clear_search_results:function(){_.each(this.attributes.elems,function(a){a.show()});this.show();this.set("open",false)},apply_search_results:function(b){var c=true,a;_.each(this.attributes.elems,function(d){if(d instanceof ToolPanelLabel){a=d;a.hide()}else{if(d instanceof Tool){if(d.apply_search_results(b)){c=false;if(a){a.show()}}}}});if(c){this.hide()}else{this.show();this.set("open",true)}}});var ToolSearch=BaseModel.extend({defaults:{spinner_url:"",search_url:"",visible:true,query:"",results:null},initialize:function(){this.on("change:query",this.do_search)},do_search:function(){var c=this.attributes.query;if(c.length<3){this.set("results",null);return}var b=c+"*";if(this.timer){clearTimeout(this.timer)}$("#search-spinner").show();var a=this;this.timer=setTimeout(function(){$.get(a.attributes.search_url,{query:b},function(d){a.set("results",d);$("#search-spinner").hide()},"json")},200)}});var ToolPanel=Backbone.Collection.extend({url:"/tools",tools:new ToolCollection(),parse:function(a){var b=function(e){var d=e.type;if(d==="tool"){return new Tool(e)}else{if(d==="section"){var c=_.map(e.elems,b);e.elems=c;return new ToolPanelSection(e)}else{if(d==="label"){return new ToolPanelLabel(e)}}}};return _.map(a,b)},initialize:function(a){this.tool_search=a.tool_search;this.tool_search.on("change:results",this.apply_search_results,this);this.on("reset",this.populate_tools,this)},populate_tools:function(){var a=this;a.tools=new ToolCollection();this.each(function(b){if(b instanceof ToolPanelSection){_.each(b.attributes.elems,function(c){if(c instanceof Tool){a.tools.push(c)}})}else{if(b instanceof Tool){a.tools.push(b)}}})},clear_search_results:function(){this.each(function(a){if(a instanceof ToolPanelSection){a.clear_search_results()}else{a.show()}})},apply_search_results:function(){var b=this.tool_search.attributes.results;if(b===null){this.clear_search_results();return}var a=null;this.each(function(c){if(c instanceof ToolPanelLabel){a=c;a.hide()}else{if(c instanceof Tool){if(c.apply_search_results(b)){if(a){a.show()}}}else{a=null;c.apply_search_results(b)}}})}});var BaseView=Backbone.View.extend({initialize:function(){this.model.on("change:hidden",this.update_visible,this);this.update_visible()},update_visible:function(){(this.model.attributes.hidden?this.$el.hide():this.$el.show())}});var ToolLinkView=BaseView.extend({tagName:"div",template:Handlebars.templates.tool_link,render:function(){this.$el.append(this.template(this.model.toJSON()));return this}});var ToolPanelLabelView=BaseView.extend({tagName:"div",className:"toolPanelLabel",template:Handlebars.templates.panel_label,render:function(){this.$el.append(this.template(this.model.toJSON()));return this},});var ToolPanelSectionView=BaseView.extend({tagName:"div",className:"toolSectionWrapper",template:Handlebars.templates.panel_section,initialize:function(){BaseView.prototype.initialize.call(this);this.model.on("change:open",this.update_open,this)},render:function(){this.$el.append(this.template(this.model.toJSON()));var a=this.$el.find(".toolSectionBody");_.each(this.model.attributes.elems,function(b){if(b instanceof Tool){var c=new ToolLinkView({model:b,className:"toolTitle"});c.render();a.append(c.$el)}else{if(b instanceof ToolPanelLabel){var d=new ToolPanelLabelView({model:b});d.render();a.append(d.$el)}else{}}});return this},events:{"click .toolSectionTitle > a":"toggle"},toggle:function(){this.model.set("open",!this.model.attributes.open)},update_open:function(){(this.model.attributes.open?this.$el.children(".toolSectionBody").slideDown("fast"):this.$el.children(".toolSectionBody").slideUp("fast"))}});var ToolSearchView=Backbone.View.extend({tagName:"div",id:"tool-search",className:"bar",template:Handlebars.templates.tool_search,events:{click:"focus_and_select","keyup :input":"query_changed"},render:function(){this.$el.append(this.template(this.model.toJSON()));if(!this.model.is_visible()){this.$el.hide()}return this},focus_and_select:function(){this.$el.find(":input").focus().select()},query_changed:function(){this.model.set("query",this.$el.find(":input").val())}});var ToolPanelView=Backbone.View.extend({tagName:"div",className:"toolMenu",initialize:function(){this.collection.tool_search.on("change:results",this.handle_search_results,this)},render:function(){var a=this;var b=new ToolSearchView({model:this.collection.tool_search});b.render();a.$el.append(b.$el);this.collection.each(function(d){if(d instanceof ToolPanelSection){var c=new ToolPanelSectionView({model:d});c.render();a.$el.append(c.$el)}else{if(d instanceof Tool){var e=new ToolLinkView({model:d,className:"toolTitleNoSection"});e.render();a.$el.append(e.$el)}else{if(d instanceof ToolPanelLabel){var f=new ToolPanelLabelView({model:d});f.render();a.$el.append(f.$el)}}}});a.$el.find("a.tool-link").click(function(f){var d=$(this).attr("class").split(/\s+/)[0],c=a.collection.tools.get(d);a.trigger("tool_link_click",f,c)});return this},handle_search_results:function(){var a=this.collection.tool_search.attributes.results;if(a&&a.length===0){$("#search-no-results").show()}else{$("#search-no-results").hide()}}});var ToolView=Backbone.View.extend({className:"toolForm",render:function(){var a=this}});var IntegratedToolMenuAndView=Backbone.View.extend({className:"toolMenuAndView",initialize:function(){this.tool_panel_view=new ToolPanelView({collection:this.collection})},render:function(){this.tool_panel_view.render();this.tool_panel_view.$el.css("float","left");this.$el.append(this.tool_panel_view.$el);var a=this;this.tool_panel_view.on("tool_link_click",function(c,b){c.preventDefault();a.show_tool(b)})},show_tool:function(a){a.fetch().done(function(){console.log(a);var b=new ToolView({model:a});b.render();b.$el.css("float","left");this.$el.append(b.$el);$("#left").width("500px")})}});
\ No newline at end of file
diff -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d -r e7dc2ec85d1ba124bd7f4558b3c5c89b56d55a0f static/scripts/packed/backbone/ui.js
--- a/static/scripts/packed/backbone/ui.js
+++ /dev/null
@@ -1,1 +0,0 @@
-var GalaxyPaths=Backbone.Model.extend({defaults:{root_path:"",image_path:""}});var IconButton=Backbone.Model.extend({defaults:{title:"",icon_class:"",on_click:null}});var IconButtonCollection=Backbone.Collection.extend({model:IconButton});var IconButtonMenuView=Backbone.View.extend({tagName:"div",render:function(){var a=this;this.collection.each(function(b){$("<a/>").attr("href","javascript:void(0)").attr("title",b.attributes.title).addClass("icon-button menu-button").addClass(b.attributes.icon_class).appendTo(a.$el).click(b.attributes.on_click)});return this}});var Grid=Backbone.Collection.extend({});var GridView=Backbone.View.extend({});
\ No newline at end of file
diff -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d -r e7dc2ec85d1ba124bd7f4558b3c5c89b56d55a0f static/scripts/packed/mvc/tools.js
--- /dev/null
+++ b/static/scripts/packed/mvc/tools.js
@@ -0,0 +1,1 @@
+var BaseModel=Backbone.RelationalModel.extend({defaults:{name:null,hidden:false},show:function(){this.set("hidden",false)},hide:function(){this.set("hidden",true)},is_visible:function(){return !this.attributes.hidden}});var Tool=BaseModel.extend({defaults:{description:null,target:null,inputs:[]},relations:[{type:Backbone.HasMany,key:"inputs",relatedModel:"ToolInput",reverseRelation:{key:"tool"}}],url:function(){return galaxy_paths.attributes.root_path+"tools/show?id="+this.id},apply_search_results:function(a){(_.indexOf(a,this.attributes.id)!==-1?this.show():this.hide());return this.is_visible()}});var ToolInput=Backbone.RelationalModel.extend({});var ToolCollection=Backbone.Collection.extend({model:Tool});var ToolPanelLabel=BaseModel.extend({});var ToolPanelSection=BaseModel.extend({defaults:{elems:[],open:false},clear_search_results:function(){_.each(this.attributes.elems,function(a){a.show()});this.show();this.set("open",false)},apply_search_results:function(b){var c=true,a;_.each(this.attributes.elems,function(d){if(d instanceof ToolPanelLabel){a=d;a.hide()}else{if(d instanceof Tool){if(d.apply_search_results(b)){c=false;if(a){a.show()}}}}});if(c){this.hide()}else{this.show();this.set("open",true)}}});var ToolSearch=BaseModel.extend({defaults:{spinner_url:"",search_url:"",visible:true,query:"",results:null},initialize:function(){this.on("change:query",this.do_search)},do_search:function(){var c=this.attributes.query;if(c.length<3){this.set("results",null);return}var b=c+"*";if(this.timer){clearTimeout(this.timer)}$("#search-spinner").show();var a=this;this.timer=setTimeout(function(){$.get(a.attributes.search_url,{query:b},function(d){a.set("results",d);$("#search-spinner").hide()},"json")},200)}});var ToolPanel=Backbone.Collection.extend({url:"/tools",tools:new ToolCollection(),parse:function(a){var b=function(e){var d=e.type;if(d==="tool"){return new Tool(e)}else{if(d==="section"){var c=_.map(e.elems,b);e.elems=c;return new ToolPanelSection(e)}else{if(d==="label"){return new ToolPanelLabel(e)}}}};return _.map(a,b)},initialize:function(a){this.tool_search=a.tool_search;this.tool_search.on("change:results",this.apply_search_results,this);this.on("reset",this.populate_tools,this)},populate_tools:function(){var a=this;a.tools=new ToolCollection();this.each(function(b){if(b instanceof ToolPanelSection){_.each(b.attributes.elems,function(c){if(c instanceof Tool){a.tools.push(c)}})}else{if(b instanceof Tool){a.tools.push(b)}}})},clear_search_results:function(){this.each(function(a){if(a instanceof ToolPanelSection){a.clear_search_results()}else{a.show()}})},apply_search_results:function(){var b=this.tool_search.attributes.results;if(b===null){this.clear_search_results();return}var a=null;this.each(function(c){if(c instanceof ToolPanelLabel){a=c;a.hide()}else{if(c instanceof Tool){if(c.apply_search_results(b)){if(a){a.show()}}}else{a=null;c.apply_search_results(b)}}})}});var BaseView=Backbone.View.extend({initialize:function(){this.model.on("change:hidden",this.update_visible,this);this.update_visible()},update_visible:function(){(this.model.attributes.hidden?this.$el.hide():this.$el.show())}});var ToolLinkView=BaseView.extend({tagName:"div",template:Handlebars.templates.tool_link,render:function(){this.$el.append(this.template(this.model.toJSON()));return this}});var ToolPanelLabelView=BaseView.extend({tagName:"div",className:"toolPanelLabel",template:Handlebars.templates.panel_label,render:function(){this.$el.append(this.template(this.model.toJSON()));return this},});var ToolPanelSectionView=BaseView.extend({tagName:"div",className:"toolSectionWrapper",template:Handlebars.templates.panel_section,initialize:function(){BaseView.prototype.initialize.call(this);this.model.on("change:open",this.update_open,this)},render:function(){this.$el.append(this.template(this.model.toJSON()));var a=this.$el.find(".toolSectionBody");_.each(this.model.attributes.elems,function(b){if(b instanceof Tool){var c=new ToolLinkView({model:b,className:"toolTitle"});c.render();a.append(c.$el)}else{if(b instanceof ToolPanelLabel){var d=new ToolPanelLabelView({model:b});d.render();a.append(d.$el)}else{}}});return this},events:{"click .toolSectionTitle > a":"toggle"},toggle:function(){this.model.set("open",!this.model.attributes.open)},update_open:function(){(this.model.attributes.open?this.$el.children(".toolSectionBody").slideDown("fast"):this.$el.children(".toolSectionBody").slideUp("fast"))}});var ToolSearchView=Backbone.View.extend({tagName:"div",id:"tool-search",className:"bar",template:Handlebars.templates.tool_search,events:{click:"focus_and_select","keyup :input":"query_changed"},render:function(){this.$el.append(this.template(this.model.toJSON()));if(!this.model.is_visible()){this.$el.hide()}return this},focus_and_select:function(){this.$el.find(":input").focus().select()},query_changed:function(){this.model.set("query",this.$el.find(":input").val())}});var ToolPanelView=Backbone.View.extend({tagName:"div",className:"toolMenu",initialize:function(){this.collection.tool_search.on("change:results",this.handle_search_results,this)},render:function(){var a=this;var b=new ToolSearchView({model:this.collection.tool_search});b.render();a.$el.append(b.$el);this.collection.each(function(d){if(d instanceof ToolPanelSection){var c=new ToolPanelSectionView({model:d});c.render();a.$el.append(c.$el)}else{if(d instanceof Tool){var e=new ToolLinkView({model:d,className:"toolTitleNoSection"});e.render();a.$el.append(e.$el)}else{if(d instanceof ToolPanelLabel){var f=new ToolPanelLabelView({model:d});f.render();a.$el.append(f.$el)}}}});a.$el.find("a.tool-link").click(function(f){var d=$(this).attr("class").split(/\s+/)[0],c=a.collection.tools.get(d);a.trigger("tool_link_click",f,c)});return this},handle_search_results:function(){var a=this.collection.tool_search.attributes.results;if(a&&a.length===0){$("#search-no-results").show()}else{$("#search-no-results").hide()}}});var ToolView=Backbone.View.extend({className:"toolForm",render:function(){var a=this}});var IntegratedToolMenuAndView=Backbone.View.extend({className:"toolMenuAndView",initialize:function(){this.tool_panel_view=new ToolPanelView({collection:this.collection})},render:function(){this.tool_panel_view.render();this.tool_panel_view.$el.css("float","left");this.$el.append(this.tool_panel_view.$el);var a=this;this.tool_panel_view.on("tool_link_click",function(c,b){c.preventDefault();a.show_tool(b)})},show_tool:function(a){a.fetch().done(function(){console.log(a);var b=new ToolView({model:a});b.render();b.$el.css("float","left");this.$el.append(b.$el);$("#left").width("500px")})}});
\ No newline at end of file
diff -r 98c2b1689ab32e5f15aa57906d95f1753c593c3d -r e7dc2ec85d1ba124bd7f4558b3c5c89b56d55a0f static/scripts/packed/mvc/ui.js
--- /dev/null
+++ b/static/scripts/packed/mvc/ui.js
@@ -0,0 +1,1 @@
+var GalaxyPaths=Backbone.Model.extend({defaults:{root_path:"",image_path:""}});var IconButton=Backbone.Model.extend({defaults:{title:"",icon_class:"",on_click:null}});var IconButtonCollection=Backbone.Collection.extend({model:IconButton});var IconButtonMenuView=Backbone.View.extend({tagName:"div",render:function(){var a=this;this.collection.each(function(b){$("<a/>").attr("href","javascript:void(0)").attr("title",b.attributes.title).addClass("icon-button menu-button").addClass(b.attributes.icon_class).appendTo(a.$el).click(b.attributes.on_click)});return this}});var Grid=Backbone.Collection.extend({});var GridView=Backbone.View.extend({});
\ No newline at end of file
https://bitbucket.org/galaxy/galaxy-central/changeset/98213ceeac03/
changeset: 98213ceeac03
user: jgoecks
date: 2012-04-12 21:44:12
summary: Automated merge with https://bitbucket.org/galaxy/galaxy-central
affected #: 4 files
diff -r e7dc2ec85d1ba124bd7f4558b3c5c89b56d55a0f -r 98213ceeac03f0089b23ba64500802d69f3e77bb lib/galaxy/web/controllers/root.py
--- a/lib/galaxy/web/controllers/root.py
+++ b/lib/galaxy/web/controllers/root.py
@@ -250,7 +250,7 @@
valid_chars = '.,^_-()[]0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
fname = data.name
fname = ''.join(c in valid_chars and c or '_' for c in fname)[0:150]
- trans.response.headers["Content-Disposition"] = "attachment; filename=GalaxyHistoryItem-%s-[%s]%s" % (data.hid, fname, toext)
+ trans.response.headers["Content-Disposition"] = 'attachment; filename="GalaxyHistoryItem-%s-[%s]%s"' % (data.hid, fname, toext)
trans.log_event( "Display dataset id: %s" % str(id) )
try:
return open( data.file_name )
diff -r e7dc2ec85d1ba124bd7f4558b3c5c89b56d55a0f -r 98213ceeac03f0089b23ba64500802d69f3e77bb lib/galaxy/web/controllers/workflow.py
--- a/lib/galaxy/web/controllers/workflow.py
+++ b/lib/galaxy/web/controllers/workflow.py
@@ -1109,7 +1109,7 @@
valid_chars = '.,^_-()[]0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
sname = stored.name
sname = ''.join(c in valid_chars and c or '_' for c in sname)[0:150]
- trans.response.headers["Content-Disposition"] = "attachment; filename=Galaxy-Workflow-%s.ga" % ( sname )
+ trans.response.headers["Content-Disposition"] = 'attachment; filename="Galaxy-Workflow-%s.ga"' % ( sname )
trans.response.set_content_type( 'application/galaxy-archive' )
return stored_dict
@web.expose
diff -r e7dc2ec85d1ba124bd7f4558b3c5c89b56d55a0f -r 98213ceeac03f0089b23ba64500802d69f3e77bb static/scripts/templates/compiled/panel_section.js
--- a/static/scripts/templates/compiled/panel_section.js
+++ b/static/scripts/templates/compiled/panel_section.js
@@ -10,7 +10,7 @@
stack1 = foundHelper || depth0.id;
if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "id", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\">\n <a href=\"#\"><span>";
+ buffer += escapeExpression(stack1) + "\">\n <a href=\"javascript:void(0)\"><span>";
foundHelper = helpers.name;
stack1 = foundHelper || depth0.name;
if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
diff -r e7dc2ec85d1ba124bd7f4558b3c5c89b56d55a0f -r 98213ceeac03f0089b23ba64500802d69f3e77bb static/scripts/templates/panel_section.handlebars
--- a/static/scripts/templates/panel_section.handlebars
+++ b/static/scripts/templates/panel_section.handlebars
@@ -1,5 +1,5 @@
<div class="toolSectionTitle" id="title_{{id}}">
- <a href="#"><span>{{name}}</span></a>
+ <a href="javascript:void(0)"><span>{{name}}</span></a></div><div id="{{id}}" class="toolSectionBody" style="display: none; "><div class="toolSectionBg"></div>
https://bitbucket.org/galaxy/galaxy-central/changeset/398905e25268/
changeset: 398905e25268
user: jgoecks
date: 2012-04-13 16:04:42
summary: Update templates to reflect changes in javascript directories organization.
affected #: 4 files
diff -r 98213ceeac03f0089b23ba64500802d69f3e77bb -r 398905e25268a18e53eb2a01f9eb504020ece352 lib/galaxy/web/framework/helpers/__init__.py
--- a/lib/galaxy/web/framework/helpers/__init__.py
+++ b/lib/galaxy/web/framework/helpers/__init__.py
@@ -61,12 +61,12 @@
"""
return js_helper( '/static/scripts/', *args )
-def handlebars( *args ):
+def templates( *args ):
"""
Take a list of template names (no extension) and return appropriate
string of script tags.
"""
- return js_helper( '/static/scripts/handlebars/compiled/', *args )
+ return js_helper( '/static/scripts/templates/compiled/', *args )
# Hashes
diff -r 98213ceeac03f0089b23ba64500802d69f3e77bb -r 398905e25268a18e53eb2a01f9eb504020ece352 templates/base.mako
--- a/templates/base.mako
+++ b/templates/base.mako
@@ -26,7 +26,7 @@
## <!--[if lt IE 7]>
## <script type='text/javascript' src="/static/scripts/IE7.js"></script>
## <![endif]-->
- ${h.js( "jquery", "galaxy.base", "libs/underscore", "libs/backbone", "libs/backbone-relational", "libs/handlebars.runtime", "backbone/ui" )}
+ ${h.js( "jquery", "galaxy.base", "libs/underscore", "libs/backbone", "libs/backbone-relational", "libs/handlebars.runtime", "mvc/ui" )}
<script type="text/javascript">
// Set up needed paths.
var galaxy_paths = new GalaxyPaths({
diff -r 98213ceeac03f0089b23ba64500802d69f3e77bb -r 398905e25268a18e53eb2a01f9eb504020ece352 templates/base_panels.mako
--- a/templates/base_panels.mako
+++ b/templates/base_panels.mako
@@ -47,7 +47,7 @@
<!--[if lt IE 7]>
${h.js( 'IE7', 'ie7-recalc' )}
<![endif]-->
- ${h.js( 'jquery', 'libs/underscore', 'libs/backbone', 'libs/backbone-relational', 'libs/handlebars.runtime', 'backbone/ui' )}
+ ${h.js( 'jquery', 'libs/underscore', 'libs/backbone', 'libs/backbone-relational', 'libs/handlebars.runtime', 'mvc/ui' )}
<script type="text/javascript">
// Set up needed paths.
var galaxy_paths = new GalaxyPaths({
diff -r 98213ceeac03f0089b23ba64500802d69f3e77bb -r 398905e25268a18e53eb2a01f9eb504020ece352 templates/root/tool_menu.mako
--- a/templates/root/tool_menu.mako
+++ b/templates/root/tool_menu.mako
@@ -16,8 +16,8 @@
<%def name="javascripts()">
${parent.javascripts()}
- ${h.handlebars( "tool_link", "panel_label", "panel_section", "tool_search" )}
- ${h.js( "galaxy.base", "json2", "autocomplete_tagging", "backbone/tools" )}
+ ${h.templates( "tool_link", "panel_label", "panel_section", "tool_search" )}
+ ${h.js( "galaxy.base", "json2", "autocomplete_tagging", "mvc/tools" )}
<%
# Set up for creating tool panel.
https://bitbucket.org/galaxy/galaxy-central/changeset/afd1b16d7ec5/
changeset: afd1b16d7ec5
user: jgoecks
date: 2012-04-13 16:05:24
summary: Merge
affected #: 1 file
diff -r 398905e25268a18e53eb2a01f9eb504020ece352 -r afd1b16d7ec5d86dbe4f4a8d8636ec1d82d49f98 lib/galaxy/web/controllers/user.py
--- a/lib/galaxy/web/controllers/user.py
+++ b/lib/galaxy/web/controllers/user.py
@@ -60,8 +60,6 @@
auto_associate = util.string_as_bool( kwd.get( 'auto_associate', False ) )
use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
action = 'login'
- if not redirect:
- redirect = url_for( '/' )
consumer = trans.app.openid_manager.get_consumer( trans )
if openid_url:
openid_provider_obj = trans.app.openid_providers.new_provider_from_identifier( openid_url )
@@ -113,7 +111,7 @@
consumer = trans.app.openid_manager.get_consumer( trans )
info = consumer.complete( kwd, trans.request.url )
display_identifier = info.getDisplayIdentifier()
- redirect = kwd.get( 'redirect', url_for( '/' ) )
+ redirect = kwd.get( 'redirect', '' )
openid_provider = kwd.get( 'openid_provider', None )
if info.status == trans.app.openid_manager.FAILURE and display_identifier:
message = "Login via OpenID failed. The technical reason for this follows, please include this message in your email if you need to %s to resolve this problem: %s" % ( contact, info.message )
@@ -163,6 +161,8 @@
openid_provider_obj.post_authentication( trans, trans.app.openid_manager, info )
if redirect:
message = '%s<br>Click <a href="%s"><strong>here</strong></a> to return to the page you were previously viewing.' % ( message, redirect )
+ if redirect and status != "error":
+ return trans.response.send_redirect( redirect )
return trans.response.send_redirect( url_for( controller='user',
action='openid_manage',
use_panels=True,
@@ -173,6 +173,8 @@
trans.handle_user_login( user_openid.user, webapp )
trans.log_event( "User logged in via OpenID: %s" % display_identifier )
openid_provider_obj.post_authentication( trans, trans.app.openid_manager, info )
+ if not redirect:
+ redirect = url_for( '/' )
return trans.response.send_redirect( redirect )
trans.sa_session.add( user_openid )
trans.sa_session.flush()
@@ -252,14 +254,19 @@
message = '%s<li><a href="%s" target="_blank">%s</a></li>' % ( message, url_for( controller='user', action='openid_auth', openid_provider=openid.id, redirect=redirect, auto_associate=True ), openid.name )
message = "%s</ul>" % ( message )
return trans.response.send_redirect( url_for( controller='user',
- action='openid_manage',
- use_panels=True,
- redirect=redirect,
- message=message,
- status='info' ) )
- if not redirect:
- redirect = url_for( '/' )
- return trans.response.send_redirect( redirect )
+ action='openid_manage',
+ use_panels=use_panels,
+ redirect=redirect,
+ message=message,
+ status='info' ) )
+ if redirect:
+ return trans.response.send_redirect( redirect )
+ return trans.response.send_redirect( url_for( controller='user',
+ action='openid_manage',
+ use_panels=use_panels,
+ redirect=redirect,
+ message=message,
+ status='info' ) )
if kwd.get( 'create_user_button', False ):
password = kwd.get( 'password', '' )
confirm = kwd.get( 'confirm', '' )
@@ -304,9 +311,14 @@
redirect=redirect,
message=message,
status='info' ) )
- if not redirect:
- redirect = url_for( '/' )
- return trans.response.send_redirect( redirect )
+ if redirect:
+ return trans.response.send_redirect( redirect )
+ return trans.response.send_redirect( url_for( controller='user',
+ action='openid_manage',
+ use_panels=use_panels,
+ redirect=redirect,
+ message=message,
+ status='info' ) )
else:
message = error
status = 'error'
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dan: Minor tweeks for redirect flow during OpenID process.
by Bitbucket 13 Apr '12
by Bitbucket 13 Apr '12
13 Apr '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/f6e790d94282/
changeset: f6e790d94282
user: dan
date: 2012-04-13 15:57:08
summary: Minor tweeks for redirect flow during OpenID process.
affected #: 1 file
diff -r a30f98b4b463f32a133f7a42d36411f0f9e63658 -r f6e790d9428273e2775b3e428c1fdd5f946a0ca3 lib/galaxy/web/controllers/user.py
--- a/lib/galaxy/web/controllers/user.py
+++ b/lib/galaxy/web/controllers/user.py
@@ -60,8 +60,6 @@
auto_associate = util.string_as_bool( kwd.get( 'auto_associate', False ) )
use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
action = 'login'
- if not redirect:
- redirect = url_for( '/' )
consumer = trans.app.openid_manager.get_consumer( trans )
if openid_url:
openid_provider_obj = trans.app.openid_providers.new_provider_from_identifier( openid_url )
@@ -113,7 +111,7 @@
consumer = trans.app.openid_manager.get_consumer( trans )
info = consumer.complete( kwd, trans.request.url )
display_identifier = info.getDisplayIdentifier()
- redirect = kwd.get( 'redirect', url_for( '/' ) )
+ redirect = kwd.get( 'redirect', '' )
openid_provider = kwd.get( 'openid_provider', None )
if info.status == trans.app.openid_manager.FAILURE and display_identifier:
message = "Login via OpenID failed. The technical reason for this follows, please include this message in your email if you need to %s to resolve this problem: %s" % ( contact, info.message )
@@ -163,6 +161,8 @@
openid_provider_obj.post_authentication( trans, trans.app.openid_manager, info )
if redirect:
message = '%s<br>Click <a href="%s"><strong>here</strong></a> to return to the page you were previously viewing.' % ( message, redirect )
+ if redirect and status != "error":
+ return trans.response.send_redirect( redirect )
return trans.response.send_redirect( url_for( controller='user',
action='openid_manage',
use_panels=True,
@@ -173,6 +173,8 @@
trans.handle_user_login( user_openid.user, webapp )
trans.log_event( "User logged in via OpenID: %s" % display_identifier )
openid_provider_obj.post_authentication( trans, trans.app.openid_manager, info )
+ if not redirect:
+ redirect = url_for( '/' )
return trans.response.send_redirect( redirect )
trans.sa_session.add( user_openid )
trans.sa_session.flush()
@@ -252,14 +254,19 @@
message = '%s<li><a href="%s" target="_blank">%s</a></li>' % ( message, url_for( controller='user', action='openid_auth', openid_provider=openid.id, redirect=redirect, auto_associate=True ), openid.name )
message = "%s</ul>" % ( message )
return trans.response.send_redirect( url_for( controller='user',
- action='openid_manage',
- use_panels=True,
- redirect=redirect,
- message=message,
- status='info' ) )
- if not redirect:
- redirect = url_for( '/' )
- return trans.response.send_redirect( redirect )
+ action='openid_manage',
+ use_panels=use_panels,
+ redirect=redirect,
+ message=message,
+ status='info' ) )
+ if redirect:
+ return trans.response.send_redirect( redirect )
+ return trans.response.send_redirect( url_for( controller='user',
+ action='openid_manage',
+ use_panels=use_panels,
+ redirect=redirect,
+ message=message,
+ status='info' ) )
if kwd.get( 'create_user_button', False ):
password = kwd.get( 'password', '' )
confirm = kwd.get( 'confirm', '' )
@@ -304,9 +311,14 @@
redirect=redirect,
message=message,
status='info' ) )
- if not redirect:
- redirect = url_for( '/' )
- return trans.response.send_redirect( redirect )
+ if redirect:
+ return trans.response.send_redirect( redirect )
+ return trans.response.send_redirect( url_for( controller='user',
+ action='openid_manage',
+ use_panels=use_panels,
+ redirect=redirect,
+ message=message,
+ status='info' ) )
else:
message = error
status = 'error'
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jgoecks: Use javascript:void(0) rather than # in tool section links to avoid unwanted scrolling to top of page.
by Bitbucket 12 Apr '12
by Bitbucket 12 Apr '12
12 Apr '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/a30f98b4b463/
changeset: a30f98b4b463
user: jgoecks
date: 2012-04-12 21:36:06
summary: Use javascript:void(0) rather than # in tool section links to avoid unwanted scrolling to top of page.
affected #: 2 files
diff -r de28eda68d0c40f1a71c5ebf95e06cb816dc890b -r a30f98b4b463f32a133f7a42d36411f0f9e63658 static/scripts/handlebars/compiled/panel_section.js
--- a/static/scripts/handlebars/compiled/panel_section.js
+++ b/static/scripts/handlebars/compiled/panel_section.js
@@ -10,7 +10,7 @@
stack1 = foundHelper || depth0.id;
if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "id", { hash: {} }); }
- buffer += escapeExpression(stack1) + "\">\n <a href=\"#\"><span>";
+ buffer += escapeExpression(stack1) + "\">\n <a href=\"javascript:void(0)\"><span>";
foundHelper = helpers.name;
stack1 = foundHelper || depth0.name;
if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
diff -r de28eda68d0c40f1a71c5ebf95e06cb816dc890b -r a30f98b4b463f32a133f7a42d36411f0f9e63658 static/scripts/handlebars/panel_section.handlebars
--- a/static/scripts/handlebars/panel_section.handlebars
+++ b/static/scripts/handlebars/panel_section.handlebars
@@ -1,5 +1,5 @@
<div class="toolSectionTitle" id="title_{{id}}">
- <a href="#"><span>{{name}}</span></a>
+ <a href="javascript:void(0)"><span>{{name}}</span></a></div><div id="{{id}}" class="toolSectionBody" style="display: none; "><div class="toolSectionBg"></div>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dan: Fix two more places where filenames in content-dispositions were not being surrounded by quotes.
by Bitbucket 12 Apr '12
by Bitbucket 12 Apr '12
12 Apr '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/de28eda68d0c/
changeset: de28eda68d0c
user: dan
date: 2012-04-12 20:14:45
summary: Fix two more places where filenames in content-dispositions were not being surrounded by quotes.
affected #: 2 files
diff -r 84d49e39069d965a45097ade1b71a57cdc0a0386 -r de28eda68d0c40f1a71c5ebf95e06cb816dc890b lib/galaxy/web/controllers/root.py
--- a/lib/galaxy/web/controllers/root.py
+++ b/lib/galaxy/web/controllers/root.py
@@ -250,7 +250,7 @@
valid_chars = '.,^_-()[]0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
fname = data.name
fname = ''.join(c in valid_chars and c or '_' for c in fname)[0:150]
- trans.response.headers["Content-Disposition"] = "attachment; filename=GalaxyHistoryItem-%s-[%s]%s" % (data.hid, fname, toext)
+ trans.response.headers["Content-Disposition"] = 'attachment; filename="GalaxyHistoryItem-%s-[%s]%s"' % (data.hid, fname, toext)
trans.log_event( "Display dataset id: %s" % str(id) )
try:
return open( data.file_name )
diff -r 84d49e39069d965a45097ade1b71a57cdc0a0386 -r de28eda68d0c40f1a71c5ebf95e06cb816dc890b lib/galaxy/web/controllers/workflow.py
--- a/lib/galaxy/web/controllers/workflow.py
+++ b/lib/galaxy/web/controllers/workflow.py
@@ -1109,7 +1109,7 @@
valid_chars = '.,^_-()[]0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
sname = stored.name
sname = ''.join(c in valid_chars and c or '_' for c in sname)[0:150]
- trans.response.headers["Content-Disposition"] = "attachment; filename=Galaxy-Workflow-%s.ga" % ( sname )
+ trans.response.headers["Content-Disposition"] = 'attachment; filename="Galaxy-Workflow-%s.ga"' % ( sname )
trans.response.set_content_type( 'application/galaxy-archive' )
return stored_dict
@web.expose
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dan: Minor fix for clicking an OpenID provider to refresh credentials.
by Bitbucket 12 Apr '12
by Bitbucket 12 Apr '12
12 Apr '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/84d49e39069d/
changeset: 84d49e39069d
user: dan
date: 2012-04-12 18:16:24
summary: Minor fix for clicking an OpenID provider to refresh credentials.
affected #: 1 file
diff -r d88a9fa7041c02f8c448eecb2a86c93b5c47d6a0 -r 84d49e39069d965a45097ade1b71a57cdc0a0386 lib/galaxy/web/controllers/user.py
--- a/lib/galaxy/web/controllers/user.py
+++ b/lib/galaxy/web/controllers/user.py
@@ -29,7 +29,7 @@
default_filter = { "openid" : "All" }
default_sort_key = "-create_time"
columns = [
- grids.TextColumn( "OpenID URL", key="openid", link=( lambda x: dict( operation='openid_auth', login_button="Login", openid_url=x.openid if not x.provider else '', openid_provider=x.provider, auto_associate=True ) ) ),
+ grids.TextColumn( "OpenID URL", key="openid", link=( lambda x: dict( action='openid_auth', login_button="Login", openid_url=x.openid if not x.provider else '', openid_provider=x.provider, auto_associate=True ) ) ),
grids.GridColumn( "Created", key="create_time", format=time_ago ),
]
operations = [
@@ -395,8 +395,6 @@
action='openid_disassociate',
use_panels=use_panels,
id=kwd['id'] ) )
- elif operation == 'openid_auth':
- return trans.response.send_redirect( url_for( controller='user', action='openid_auth', **kwd ) )
kwd['redirect'] = kwd.get( 'redirect', url_for( controller='user', action='openid_manage', use_panels=True ) )
kwd['openid_providers'] = trans.app.openid_providers
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/d88a9fa7041c/
changeset: d88a9fa7041c
user: dan
date: 2012-04-12 17:32:01
summary: Rework OpenID process.
Add a never_associate_with_user flag to OpenID providers that will prevent an OpenID Provider from being able to be used for logging in to Galaxy. Post authentication actions will still be performed. This is now used for the GenomeSpace OpenID Provider until it is working correctly.
affected #: 10 files
diff -r 8376ad08ae41b9b7efa06622b031cb731e2c0bcf -r d88a9fa7041c02f8c448eecb2a86c93b5c47d6a0 lib/galaxy/model/mapping.py
--- a/lib/galaxy/model/mapping.py
+++ b/lib/galaxy/model/mapping.py
@@ -76,6 +76,7 @@
Column( "session_id", Integer, ForeignKey( "galaxy_session.id" ), index=True ),
Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
Column( "openid", TEXT, index=True, unique=True ),
+ Column( "provider", TrimmedString( 255 ) ),
)
History.table = Table( "history", metadata,
diff -r 8376ad08ae41b9b7efa06622b031cb731e2c0bcf -r d88a9fa7041c02f8c448eecb2a86c93b5c47d6a0 lib/galaxy/model/migrate/versions/0096_openid_provider.py
--- /dev/null
+++ b/lib/galaxy/model/migrate/versions/0096_openid_provider.py
@@ -0,0 +1,45 @@
+"""
+Migration script to add column to openid table for provider.
+Remove any OpenID entries with nonunique GenomeSpace Identifier
+"""
+
+BAD_IDENTIFIER = 'https://identity.genomespace.org/identityServer/xrd.jsp'
+from sqlalchemy import *
+from sqlalchemy.orm import *
+from migrate import *
+from migrate.changeset import *
+from galaxy.model.custom_types import TrimmedString
+
+import logging
+log = logging.getLogger( __name__ )
+
+metadata = MetaData( migrate_engine )
+db_session = scoped_session( sessionmaker( bind=migrate_engine, autoflush=False, autocommit=True ) )
+
+def upgrade():
+ print __doc__
+ metadata.reflect()
+
+ try:
+ OpenID_table = Table( "galaxy_user_openid", metadata, autoload=True )
+ c = Column( "provider", TrimmedString( 255 ) )
+ c.create( OpenID_table )
+ assert c is OpenID_table.c.provider
+ except Exception, e:
+ print "Adding provider column to galaxy_user_openid table failed: %s" % str( e )
+ log.debug( "Adding provider column to galaxy_user_openid table failed: %s" % str( e ) )
+
+ try:
+ cmd = "DELETE FROM galaxy_user_openid WHERE openid='%s'" % ( BAD_IDENTIFIER )
+ db_session.execute( cmd )
+ except Exception, e:
+ log.debug( "Deleting bad Identifiers from galaxy_user_openid failed: %s" % str( e ) )
+
+def downgrade():
+ metadata.reflect()
+ try:
+ OpenID_table = Table( "galaxy_user_openid", metadata, autoload=True )
+ OpenID_table.c.provider.drop()
+ except Exception, e:
+ print "Dropping provider column from galaxy_user_openid table failed: %s" % str( e )
+ log.debug( "Dropping provider column from galaxy_user_openid table failed: %s" % str( e ) )
\ No newline at end of file
diff -r 8376ad08ae41b9b7efa06622b031cb731e2c0bcf -r d88a9fa7041c02f8c448eecb2a86c93b5c47d6a0 lib/galaxy/openid/providers.py
--- a/lib/galaxy/openid/providers.py
+++ b/lib/galaxy/openid/providers.py
@@ -9,6 +9,9 @@
log = logging.getLogger( __name__ )
+NO_PROVIDER_ID = 'None'
+RESERVED_PROVIDER_IDS = [ NO_PROVIDER_ID ]
+
class OpenIDProvider( object ):
'''An OpenID Provider object.'''
@classmethod
@@ -22,7 +25,9 @@
op_endpoint_url = provider_elem.find( 'op_endpoint_url' )
if op_endpoint_url is not None:
op_endpoint_url = op_endpoint_url.text
+ never_associate_with_user = string_as_bool( provider_elem.get( 'never_associate_with_user', 'False' ) )
assert (provider_id and provider_name and op_endpoint_url), Exception( "OpenID Provider improperly configured" )
+ assert provider_id not in RESERVED_PROVIDER_IDS, Exception( 'Specified OpenID Provider uses a reserved id: %s' % ( provider_id ) )
sreg_required = []
sreg_optional = []
use_for = {}
@@ -45,8 +50,8 @@
sreg_required = None
sreg_optional = None
use_for = None
- return cls( provider_id, provider_name, op_endpoint_url, sreg_required, sreg_optional, use_for, store_user_preference )
- def __init__( self, id, name, op_endpoint_url, sreg_required=None, sreg_optional=None, use_for=None, store_user_preference=None ):
+ return cls( provider_id, provider_name, op_endpoint_url, sreg_required=sreg_required, sreg_optional=sreg_optional, use_for=use_for, store_user_preference=store_user_preference, never_associate_with_user=never_associate_with_user )
+ def __init__( self, id, name, op_endpoint_url, sreg_required=None, sreg_optional=None, use_for=None, store_user_preference=None, never_associate_with_user=None ):
'''When sreg options are not specified, defaults are used.'''
self.id = id
self.name = name
@@ -71,6 +76,10 @@
self.store_user_preference = store_user_preference
else:
self.store_user_preference = {}
+ if never_associate_with_user:
+ self.never_associate_with_user = True
+ else:
+ self.never_associate_with_user = False
def post_authentication( self, trans, openid_manager, info ):
sreg_attributes = openid_manager.get_sreg( info )
for store_pref_name, store_pref_value_name in self.store_user_preference.iteritems():
@@ -80,9 +89,12 @@
raise Exception( 'Only sreg is currently supported.' )
trans.sa_session.add( trans.user )
trans.sa_session.flush()
+ def has_post_authentication_actions( self ):
+ return bool( self.store_user_preference )
class OpenIDProviders( object ):
'''Collection of OpenID Providers'''
+ NO_PROVIDER_ID = NO_PROVIDER_ID
@classmethod
def from_file( cls, filename ):
try:
@@ -107,6 +119,7 @@
self.providers = providers
else:
self.providers = odict()
+ self._banned_identifiers = [ provider.op_endpoint_url for provider in self.providers.itervalues() if provider.never_associate_with_user ]
def __iter__( self ):
for provider in self.providers.itervalues():
yield provider
@@ -115,3 +128,5 @@
return self.providers[ name ]
else:
return default
+ def new_provider_from_identifier( self, identifier ):
+ return OpenIDProvider( None, identifier, identifier, never_associate_with_user = identifier in self._banned_identifiers )
diff -r 8376ad08ae41b9b7efa06622b031cb731e2c0bcf -r d88a9fa7041c02f8c448eecb2a86c93b5c47d6a0 lib/galaxy/web/controllers/tool_runner.py
--- a/lib/galaxy/web/controllers/tool_runner.py
+++ b/lib/galaxy/web/controllers/tool_runner.py
@@ -59,7 +59,7 @@
trans.log_event( "Tool id '%s' does not exist" % tool_id )
return "Tool '%s' does not exist, kwd=%s " % (tool_id, kwd)
if tool.require_login and not trans.user:
- return trans.response.send_redirect( url_for( controller='user', action='login', cntrller='user', message="You must be logged in to use this tool.", status="info", referer=url_for( controller='/tool_runner', action='index', tool_id=tool_id, **kwd ) ) )
+ return trans.response.send_redirect( url_for( controller='user', action='login', cntrller='user', message="You must be logged in to use this tool.", status="info", redirect=url_for( controller='/tool_runner', action='index', tool_id=tool_id, **kwd ) ) )
params = util.Params( kwd, sanitize = False ) #Sanitize parameters when substituting into command line via input wrappers
#do param translation here, used by datasource tools
if tool.input_translator:
diff -r 8376ad08ae41b9b7efa06622b031cb731e2c0bcf -r d88a9fa7041c02f8c448eecb2a86c93b5c47d6a0 lib/galaxy/web/controllers/user.py
--- a/lib/galaxy/web/controllers/user.py
+++ b/lib/galaxy/web/controllers/user.py
@@ -11,7 +11,6 @@
from galaxy.util.json import from_json_string, to_json_string
from galaxy.web.framework.helpers import iff
from galaxy.security.validate_user_input import validate_email, validate_publicname, validate_password
-from galaxy.openid.providers import OpenIDProvider
log = logging.getLogger( __name__ )
@@ -30,7 +29,7 @@
default_filter = { "openid" : "All" }
default_sort_key = "-create_time"
columns = [
- grids.TextColumn( "OpenID URL", key="openid" ),
+ grids.TextColumn( "OpenID URL", key="openid", link=( lambda x: dict( operation='openid_auth', login_button="Login", openid_url=x.openid if not x.provider else '', openid_provider=x.provider, auto_associate=True ) ) ),
grids.GridColumn( "Created", key="create_time", format=time_ago ),
]
operations = [
@@ -48,32 +47,30 @@
return trans.fill_template( '/user/index.mako', cntrller=cntrller, webapp=webapp )
@web.expose
def openid_auth( self, trans, webapp='galaxy', **kwd ):
+ '''Handles user request to access an OpenID provider'''
if not trans.app.config.enable_openid:
return trans.show_error_message( 'OpenID authentication is not enabled in this instance of Galaxy' )
message = 'Unspecified failure authenticating via OpenID'
status = kwd.get( 'status', 'done' )
openid_url = kwd.get( 'openid_url', '' )
openid_provider = kwd.get( 'openid_provider', '' )
- referer = kwd.get( 'referer', trans.request.referer )
+ if not openid_provider or openid_url:
+ openid_provider = trans.app.openid_providers.NO_PROVIDER_ID #empty fields cause validation errors
+ redirect = kwd.get( 'redirect', '' )
auto_associate = util.string_as_bool( kwd.get( 'auto_associate', False ) )
use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
action = 'login'
- if auto_associate:
- action = 'openid_manage'
- if not referer:
- referer = url_for( '/' )
+ if not redirect:
+ redirect = url_for( '/' )
consumer = trans.app.openid_manager.get_consumer( trans )
- openid_provider_obj = None
- if not openid_url and openid_provider and trans.app.openid_providers.get( openid_provider ):
+ if openid_url:
+ openid_provider_obj = trans.app.openid_providers.new_provider_from_identifier( openid_url )
+ else:
openid_provider_obj = trans.app.openid_providers.get( openid_provider )
- elif openid_url:
- openid_provider_obj = OpenIDProvider( openid_url, openid_url, openid_url ) #for manually entered links use the link for id, name and url
- elif openid_provider:
- message = 'Invalid OpenID provider specified: %s' % ( openid_provider )
- else:
+ if not openid_url and openid_provider == trans.app.openid_providers.NO_PROVIDER_ID:
message = 'An OpenID provider was not specified'
- process_url = trans.request.base.rstrip( '/' ) + url_for( controller='user', action='openid_process', referer=referer, auto_associate=auto_associate, openid_provider=openid_provider )
- if openid_provider_obj is not None:
+ elif openid_provider_obj:
+ process_url = trans.request.base.rstrip( '/' ) + url_for( controller='user', action='openid_process', redirect=redirect, openid_provider=openid_provider, auto_associate=auto_associate )
request = None
try:
request = consumer.begin( openid_provider_obj.op_endpoint_url )
@@ -87,84 +84,96 @@
redirect_url = request.redirectURL(
trans.request.base, process_url )
trans.app.openid_manager.persist_session( trans, consumer )
- trans.response.send_redirect( redirect_url )
- return
+ return trans.response.send_redirect( redirect_url )
else:
form = request.htmlMarkup( trans.request.base, process_url, form_tag_attrs={'id':'openid_message','target':'_top'} )
trans.app.openid_manager.persist_session( trans, consumer )
return form
return trans.response.send_redirect( url_for( controller='user',
action=action,
+ redirect=redirect,
use_panels=use_panels,
message=message,
status='error' ) )
@web.expose
def openid_process( self, trans, webapp='galaxy', **kwd ):
+ '''Handle's response from OpenID Providers'''
if not trans.app.config.enable_openid:
return trans.show_error_message( 'OpenID authentication is not enabled in this instance of Galaxy' )
auto_associate = util.string_as_bool( kwd.get( 'auto_associate', False ) )
action = 'login'
- if auto_associate:
+ if trans.user:
action = 'openid_manage'
if trans.app.config.support_url is not None:
contact = '<a href="%s">support</a>' % trans.app.config.support_url
else:
contact = 'support'
- message = 'Verification failed for an unknown reason. Please contact support for assistance.'
+ message = 'Verification failed for an unknown reason. Please contact %s for assistance.' % ( contact )
status = 'error'
consumer = trans.app.openid_manager.get_consumer( trans )
info = consumer.complete( kwd, trans.request.url )
display_identifier = info.getDisplayIdentifier()
- redirect_url = kwd.get( 'referer', url_for( '/' ) )
- openid_provider = kwd.get( 'openid_provider', '' )
+ redirect = kwd.get( 'redirect', url_for( '/' ) )
+ openid_provider = kwd.get( 'openid_provider', None )
if info.status == trans.app.openid_manager.FAILURE and display_identifier:
message = "Login via OpenID failed. The technical reason for this follows, please include this message in your email if you need to %s to resolve this problem: %s" % ( contact, info.message )
return trans.response.send_redirect( url_for( controller='user',
action=action,
use_panels=True,
+ redirect=redirect,
message=message,
status='error' ) )
elif info.status == trans.app.openid_manager.SUCCESS:
if info.endpoint.canonicalID:
display_identifier = info.endpoint.canonicalID
+ openid_provider_obj = trans.app.openid_providers.get( openid_provider )
user_openid = trans.sa_session.query( trans.app.model.UserOpenID ).filter( trans.app.model.UserOpenID.table.c.openid == display_identifier ).first()
- openid_provider_obj = trans.app.openid_providers.get( openid_provider )
+ if not openid_provider_obj and user_openid and user_openid.provider:
+ openid_provider_obj = trans.app.openid_providers.get( user_openid.provider )
if not openid_provider_obj:
- openid_provider_obj = OpenIDProvider( display_identifier, display_identifier, display_identifier )
+ openid_provider_obj = trans.app.openid_providers.new_provider_from_identifier( display_identifier )
if not user_openid:
user_openid = trans.app.model.UserOpenID( session=trans.galaxy_session, openid=display_identifier )
- elif not user_openid.user and user_openid.session.id != trans.galaxy_session.id:
+ if not user_openid.user:
user_openid.session = trans.galaxy_session
- elif user_openid.user and not auto_associate:
+ if not user_openid.provider and openid_provider:
+ user_openid.provider = openid_provider
+ if trans.user:
+ if user_openid.user and user_openid.user.id != trans.user.id:
+ message = "The OpenID <strong>%s</strong> is already associated with another Galaxy account, <strong>%s</strong>. Please disassociate it from that account before attempting to associate it with a new account." % ( display_identifier, user_openid.user.email )
+ status = "error"
+ elif not user_openid.user or user_openid.user == trans.user:
+ if openid_provider_obj.id:
+ user_openid.provider = openid_provider_obj.id
+ user_openid.session = trans.galaxy_session
+ if not openid_provider_obj.never_associate_with_user:
+ if not auto_associate and ( user_openid.user and user_openid.user.id == trans.user.id ):
+ message = "The OpenID <strong>%s</strong> is already associated with your Galaxy account, <strong>%s</strong>." % ( display_identifier, trans.user.email )
+ status = "warning"
+ else:
+ message = "The OpenID <strong>%s</strong> has been associated with your Galaxy account, <strong>%s</strong>." % ( display_identifier, trans.user.email )
+ status = "done"
+ user_openid.user = trans.user
+ trans.sa_session.add( user_openid )
+ trans.sa_session.flush()
+ trans.log_event( "User associated OpenID: %s" % display_identifier )
+ else:
+ message = "The OpenID <strong>%s</strong> cannot be used to log into your Galaxy account, but any post authentication actions have been performed." % ( openid_provider_obj.name )
+ status ="info"
+ openid_provider_obj.post_authentication( trans, trans.app.openid_manager, info )
+ if redirect:
+ message = '%s<br>Click <a href="%s"><strong>here</strong></a> to return to the page you were previously viewing.' % ( message, redirect )
+ return trans.response.send_redirect( url_for( controller='user',
+ action='openid_manage',
+ use_panels=True,
+ redirect=redirect,
+ message=message,
+ status=status ) )
+ elif user_openid.user:
trans.handle_user_login( user_openid.user, webapp )
trans.log_event( "User logged in via OpenID: %s" % display_identifier )
openid_provider_obj.post_authentication( trans, trans.app.openid_manager, info )
- trans.response.send_redirect( redirect_url )
- return
- if auto_associate and trans.user:
- # The user is already logged in and requested association from
- # the user prefs as opposed to using the OpenID form on the
- # login page.
- if user_openid.user and user_openid.user.id != trans.user.id:
- message = "The OpenID <strong>%s</strong> is already associated with another Galaxy account, <strong>%s</strong>. Please disassociate it from that account before attempting to associate it with a new account." % ( display_identifier, user_openid.user.email )
- status = "error"
- elif user_openid.user and user_openid.user.id == trans.user.id:
- message = "The OpenID <strong>%s</strong> is already associated with your Galaxy account, <strong>%s</strong>." % ( display_identifier, trans.user.email )
- status = "warning"
- else:
- user_openid.user_id = trans.user.id
- trans.sa_session.add( user_openid )
- trans.sa_session.flush()
- trans.log_event( "User associated OpenID: %s" % display_identifier )
- message = "The OpenID <strong>%s</strong> has been associated with your Galaxy account, <strong>%s</strong>." % ( display_identifier, trans.user.email )
- status = "done"
- openid_provider_obj.post_authentication( trans, trans.app.openid_manager, info )
- trans.response.send_redirect( url_for( controller='user',
- action='openid_manage',
- use_panels=True,
- message=message,
- status=status ) )
- return
+ return trans.response.send_redirect( redirect )
trans.sa_session.add( user_openid )
trans.sa_session.flush()
message = "OpenID authentication was successful, but you need to associate your OpenID with a Galaxy account."
@@ -179,10 +188,11 @@
email = sreg_resp.get( sreg_email_name, '' )
except AttributeError:
email = ''
- trans.response.send_redirect( url_for( controller='user',
+ #OpenID success, but user not logged in, and not previously associated
+ return trans.response.send_redirect( url_for( controller='user',
action='openid_associate',
- openid_provider=openid_provider,
use_panels=True,
+ redirect=redirect,
username=username,
email=email,
message=message,
@@ -198,10 +208,12 @@
return trans.response.send_redirect( url_for( controller='user',
action=action,
use_panels=True,
+ redirect=redirect,
message=message,
status=status ) )
@web.expose
def openid_associate( self, trans, cntrller='user', webapp='galaxy', **kwd ):
+ '''Associates a user with an OpenID log in'''
if not trans.app.config.enable_openid:
return trans.show_error_message( 'OpenID authentication is not enabled in this instance of Galaxy' )
use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
@@ -209,9 +221,7 @@
status = kwd.get( 'status', 'done' )
email = kwd.get( 'email', '' )
username = kwd.get( 'username', '' )
- referer = kwd.get( 'referer', trans.request.referer )
- openid_provider = kwd.get( 'openid_provider', '' )
- openid_provider_obj = trans.app.openid_providers.get( openid_provider )
+ redirect = kwd.get( 'redirect', '' )
params = util.Params( kwd )
is_admin = cntrller == 'admin' and trans.user_is_admin()
openids = trans.galaxy_session.openids
@@ -223,18 +233,33 @@
if kwd.get( 'login_button', False ):
message, status, user, success = self.__validate_login( trans, webapp, **kwd )
if success:
+ openid_objs = []
for openid in openids:
- openid.user = user
- trans.sa_session.add( openid )
+ openid_provider_obj = trans.app.openid_providers.get( openid.provider )
+ if not openid_provider_obj or not openid_provider_obj.never_associate_with_user:
+ openid.user = user
+ trans.sa_session.add( openid )
+ trans.log_event( "User associated OpenID: %s" % openid.openid )
+ if openid_provider_obj and openid_provider_obj.has_post_authentication_actions():
+ openid_objs.append( openid_provider_obj )
trans.sa_session.flush()
- for openid in openids:
- trans.log_event( "User associated OpenID: %s" % openid.openid )
- redirect_url = referer
- if not redirect_url:
- redirect_url = url_for( '/' )
- if openid_provider_obj:
- return trans.response.send_redirect( url_for( controller='user', action='openid_auth', openid_provider=openid_provider, referer=redirect_url ) )
- return trans.response.send_redirect( redirect_url )
+ if len( openid_objs ) == 1:
+ return trans.response.send_redirect( url_for( controller='user', action='openid_auth', openid_provider=openid_objs[0].id, redirect=redirect, auto_associate=True ) )
+ elif openid_objs:
+ message = 'You have authenticated with several OpenID providers, please click the following links to execute the post authentication actions. '
+ message = "%s<br/><ul>" % ( message )
+ for openid in openid_objs:
+ message = '%s<li><a href="%s" target="_blank">%s</a></li>' % ( message, url_for( controller='user', action='openid_auth', openid_provider=openid.id, redirect=redirect, auto_associate=True ), openid.name )
+ message = "%s</ul>" % ( message )
+ return trans.response.send_redirect( url_for( controller='user',
+ action='openid_manage',
+ use_panels=True,
+ redirect=redirect,
+ message=message,
+ status='info' ) )
+ if not redirect:
+ redirect = url_for( '/' )
+ return trans.response.send_redirect( redirect )
if kwd.get( 'create_user_button', False ):
password = kwd.get( 'password', '' )
confirm = kwd.get( 'confirm', '' )
@@ -253,21 +278,35 @@
subscribe_checked,
**kwd )
if success:
- trans.handle_user_login( user, webapp )
- trans.log_event( "User created a new account" )
- trans.log_event( "User logged in" )
+ openid_objs = []
for openid in openids:
- openid.user = user
- trans.sa_session.add( openid )
+ openid_provider_obj = trans.app.openid_providers.get( openid.provider )
+ if not openid_provider_obj:
+ openid_provider_obj = trans.app.openid_providers.new_provider_from_identifier( openid.identifier )
+ if not openid_provider_obj.never_associate_with_user:
+ openid.user = user
+ trans.sa_session.add( openid )
+ trans.log_event( "User associated OpenID: %s" % openid.openid )
+ if openid_provider_obj.has_post_authentication_actions():
+ openid_objs.append( openid_provider_obj )
trans.sa_session.flush()
- for openid in openids:
- trans.log_event( "User associated OpenID: %s" % openid.openid )
- redirect_url = referer
- if not redirect_url:
- redirect_url = url_for( '/' )
- if openid_provider_obj:
- return trans.response.send_redirect( url_for( controller='user', action='openid_auth', openid_provider=openid_provider, referer=redirect_url ) )
- return trans.response.send_redirect( redirect_url )
+ if len( openid_objs ) == 1:
+ return trans.response.send_redirect( url_for( controller='user', action='openid_auth', openid_provider=openid_objs[0].id, redirect=redirect, auto_associate=True ) )
+ elif openid_objs:
+ message = 'You have authenticated with several OpenID providers, please click the following links to execute the post authentication actions. '
+ message = "%s<br/><ul>" % ( message )
+ for openid in openid_objs:
+ message = '%s<li><a href="%s" target="_blank">%s</a></li>' % ( message, url_for( controller='user', action='openid_auth', openid_provider=openid.id, redirect=redirect, auto_associate=True ), openid.name )
+ message = "%s</ul>" % ( message )
+ return trans.response.send_redirect( url_for( controller='user',
+ action='openid_manage',
+ use_panels=True,
+ redirect=redirect,
+ message=message,
+ status='info' ) )
+ if not redirect:
+ redirect = url_for( '/' )
+ return trans.response.send_redirect( redirect )
else:
message = error
status = 'error'
@@ -291,8 +330,7 @@
username=username,
header='',
use_panels=use_panels,
- redirect_url='',
- referer='',
+ redirect=redirect,
refresh_frames=[],
message=message,
status=status,
@@ -301,11 +339,11 @@
user_type_fd_id_select_field=user_type_fd_id_select_field,
user_type_form_definition=user_type_form_definition,
widgets=widgets,
- openids=openids,
- openid_provider=openid_provider )
+ openids=openids )
@web.expose
@web.require_login( 'manage OpenIDs' )
def openid_disassociate( self, trans, webapp='galaxy', **kwd ):
+ '''Disassociates a user with an OpenID'''
if not trans.app.config.enable_openid:
return trans.show_error_message( 'OpenID authentication is not enabled in this instance of Galaxy' )
params = util.Params( kwd )
@@ -338,7 +376,7 @@
trans.log_event( "User disassociated OpenID: %s" % deleted_url )
message = '%s OpenIDs were disassociated from your Galaxy account.' % len( ids )
status = 'done'
- trans.response.send_redirect( url_for( controller='user',
+ return trans.response.send_redirect( url_for( controller='user',
action='openid_manage',
use_panels=use_panels,
message=message,
@@ -346,29 +384,33 @@
@web.expose
@web.require_login( 'manage OpenIDs' )
def openid_manage( self, trans, webapp='galaxy', **kwd ):
+ '''Manage OpenIDs for user'''
if not trans.app.config.enable_openid:
return trans.show_error_message( 'OpenID authentication is not enabled in this instance of Galaxy' )
use_panels = kwd.get( 'use_panels', False )
if 'operation' in kwd:
operation = kwd['operation'].lower()
if operation == "delete":
- trans.response.send_redirect( url_for( controller='user',
+ return trans.response.send_redirect( url_for( controller='user',
action='openid_disassociate',
use_panels=use_panels,
id=kwd['id'] ) )
- kwd['referer'] = url_for( controller='user', action='openid_manage', use_panels=True )
+ elif operation == 'openid_auth':
+ return trans.response.send_redirect( url_for( controller='user', action='openid_auth', **kwd ) )
+
+ kwd['redirect'] = kwd.get( 'redirect', url_for( controller='user', action='openid_manage', use_panels=True ) )
kwd['openid_providers'] = trans.app.openid_providers
return self.user_openid_grid( trans, **kwd )
@web.expose
def login( self, trans, webapp='galaxy', redirect_url='', refresh_frames=[], **kwd ):
- referer = kwd.get( 'referer', trans.request.referer )
+ '''Handle Galaxy Log in'''
+ redirect = kwd.get( 'redirect', trans.request.referer )
use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
message = kwd.get( 'message', '' )
status = kwd.get( 'status', 'done' )
header = ''
user = None
email = kwd.get( 'email', '' )
- openid_provider = kwd.get( 'openid_provider', '' )
if kwd.get( 'login_button', False ):
if webapp == 'galaxy' and not refresh_frames:
if trans.app.config.require_login:
@@ -376,8 +418,8 @@
else:
refresh_frames = [ 'masthead', 'history' ]
message, status, user, success = self.__validate_login( trans, webapp, **kwd )
- if success and referer and not referer.startswith( trans.request.base + url_for( controller='user', action='logout' ) ):
- redirect_url = referer
+ if success and redirect and not redirect.startswith( trans.request.base + url_for( controller='user', action='logout' ) ):
+ redirect_url = redirect
elif success:
redirect_url = url_for( '/' )
if not user and trans.app.config.require_login:
@@ -399,7 +441,7 @@
header=header,
use_panels=use_panels,
redirect_url=redirect_url,
- referer=referer,
+ redirect=redirect,
refresh_frames=refresh_frames,
message=message,
status=status,
@@ -410,7 +452,7 @@
status = kwd.get( 'status', 'done' )
email = kwd.get( 'email', '' )
password = kwd.get( 'password', '' )
- referer = kwd.get( 'referer', trans.request.referer )
+ redirect = kwd.get( 'redirect', trans.request.referer )
success = False
user = trans.sa_session.query( trans.app.model.User ).filter( trans.app.model.User.table.c.email==email ).first()
if not user:
@@ -430,7 +472,7 @@
if webapp == 'galaxy':
trans.log_event( "User logged in" )
message = 'You are now logged in as %s.<br>You can <a target="_top" href="%s">go back to the page you were visiting</a> or <a target="_top" href="%s">go to the home page</a>.' % \
- ( user.email, referer, url_for( '/' ) )
+ ( user.email, redirect, url_for( '/' ) )
if trans.app.config.require_login:
message += ' <a target="_top" href="%s">Click here</a> to continue to the home page.' % web.url_for( '/static/welcome.html' )
success = True
@@ -470,7 +512,7 @@
username = util.restore_text( params.get( 'username', '' ) )
subscribe = params.get( 'subscribe', '' )
subscribe_checked = CheckboxField.is_checked( subscribe )
- referer = kwd.get( 'referer', trans.request.referer )
+ redirect = kwd.get( 'redirect', trans.request.referer )
is_admin = cntrller == 'admin' and trans.user_is_admin
if not trans.app.config.allow_user_creation and not trans.user_is_admin():
message = 'User registration is disabled. Please contact your Galaxy administrator for an account.'
@@ -534,7 +576,7 @@
widgets=widgets,
webapp=webapp,
use_panels=use_panels,
- referer=referer,
+ redirect=redirect,
redirect_url=redirect_url,
refresh_frames=refresh_frames,
message=message,
diff -r 8376ad08ae41b9b7efa06622b031cb731e2c0bcf -r d88a9fa7041c02f8c448eecb2a86c93b5c47d6a0 openid/genomespace.xml
--- a/openid/genomespace.xml
+++ b/openid/genomespace.xml
@@ -1,5 +1,5 @@
<?xml version="1.0"?>
-<provider id="genomespace" name="GenomeSpace">
+<provider id="genomespace" name="GenomeSpace" never_associate_with_user="True"><op_endpoint_url>https://identity.genomespace.org/identityServer/xrd.jsp</op_endpoint_url><sreg><field name="nickname" required="True">
diff -r 8376ad08ae41b9b7efa06622b031cb731e2c0bcf -r d88a9fa7041c02f8c448eecb2a86c93b5c47d6a0 templates/user/login.mako
--- a/templates/user/login.mako
+++ b/templates/user/login.mako
@@ -50,7 +50,7 @@
%if trans.app.config.enable_openid:
<br/>
- ${render_openid_form( referer, False, openid_providers )}
+ ${render_openid_form( redirect, False, openid_providers )}
%endif
%endif
@@ -59,7 +59,7 @@
</%def>
-<%def name="render_login_form( form_action=None, openid_provider='' )">
+<%def name="render_login_form( form_action=None )"><%
if form_action is None:
@@ -76,8 +76,7 @@
<label>Email address:</label><input type="text" name="email" value="${email}" size="40"/><input type="hidden" name="webapp" value="${webapp}" size="40"/>
- <input type="hidden" name="referer" value="${referer}" size="40"/>
- <input type="hidden" name="openid_provider" value="${openid_provider}" />
+ <input type="hidden" name="redirect" value="${redirect}" size="40"/></div><div class="form-row"><label>Password:</label>
@@ -94,7 +93,7 @@
</%def>
-<%def name="render_openid_form( referer, auto_associate, openid_providers )">
+<%def name="render_openid_form( redirect, auto_associate, openid_providers )"><div class="toolForm"><div class="toolFormTitle">OpenID Login</div><form name="openid" id="openid" action="${h.url_for( controller='user', action='openid_auth' )}" method="post" target="_parent" >
@@ -102,8 +101,7 @@
<label>OpenID URL:</label><input type="text" name="openid_url" size="60" style="background-image:url('${h.url_for( '/static/images/openid-16x16.gif' )}' ); background-repeat: no-repeat; padding-right: 20px; background-position: 99% 50%;"/><input type="hidden" name="webapp" value="${webapp}" size="40"/>
- <input type="hidden" name="referer" value="${referer}" size="40"/>
- <input type="hidden" name="auto_associate" value="${auto_associate}" size="40"/>
+ <input type="hidden" name="redirect" value="${redirect}" size="40"/></div><div class="form-row">
Or, authenticate with your <select name="openid_provider">
diff -r 8376ad08ae41b9b7efa06622b031cb731e2c0bcf -r d88a9fa7041c02f8c448eecb2a86c93b5c47d6a0 templates/user/openid_associate.mako
--- a/templates/user/openid_associate.mako
+++ b/templates/user/openid_associate.mako
@@ -65,11 +65,11 @@
<% form_action = h.url_for( cntrller=cntrller, use_panels=use_panels ) %>
- ${render_login_form( form_action=form_action, openid_provider=openid_provider )}
+ ${render_login_form( form_action=form_action )}
<br/>
- ${render_registration_form( form_action=form_action, openid_provider=openid_provider )}
+ ${render_registration_form( form_action=form_action )}
</div></div>
diff -r 8376ad08ae41b9b7efa06622b031cb731e2c0bcf -r d88a9fa7041c02f8c448eecb2a86c93b5c47d6a0 templates/user/openid_manage.mako
--- a/templates/user/openid_manage.mako
+++ b/templates/user/openid_manage.mako
@@ -7,7 +7,7 @@
<%def name="grid_body( grid )">
${make_grid( grid )}
<h2>Associate more OpenIDs</h2>
- ${render_openid_form( kwargs['referer'], True, kwargs['openid_providers'] )}
+ ${render_openid_form( kwargs['redirect'], True, kwargs['openid_providers'] )}
</%def><%def name="center_panel()">
diff -r 8376ad08ae41b9b7efa06622b031cb731e2c0bcf -r d88a9fa7041c02f8c448eecb2a86c93b5c47d6a0 templates/user/register.mako
--- a/templates/user/register.mako
+++ b/templates/user/register.mako
@@ -21,7 +21,7 @@
${render_registration_form()}
%endif
-<%def name="render_registration_form( form_action=None, openid_provider='' )">
+<%def name="render_registration_form( form_action=None )"><%
if form_action is None:
@@ -37,8 +37,7 @@
<label>Email address:</label><input type="text" name="email" value="${email}" size="40"/><input type="hidden" name="webapp" value="${webapp}" size="40"/>
- <input type="hidden" name="referer" value="${referer}" size="40"/>
- <input type="hidden" name="openid_provider" value="${openid_provider}" />
+ <input type="hidden" name="redirect" value="${redirect}" size="40"/></div><div class="form-row"><label>Password:</label>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jgoecks: Remove enable_api flag; API is now enabled by default and cannot be disabled.
by Bitbucket 11 Apr '12
by Bitbucket 11 Apr '12
11 Apr '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/8376ad08ae41/
changeset: 8376ad08ae41
user: jgoecks
date: 2012-04-11 20:45:44
summary: Remove enable_api flag; API is now enabled by default and cannot be disabled.
affected #: 9 files
diff -r bb7f51fb545d0517eeceb902fa83dc5a659c64df -r 8376ad08ae41b9b7efa06622b031cb731e2c0bcf lib/galaxy/config.py
--- a/lib/galaxy/config.py
+++ b/lib/galaxy/config.py
@@ -42,8 +42,6 @@
tempfile.tempdir = self.new_file_path
self.openid_consumer_cache_path = resolve_path( kwargs.get( "openid_consumer_cache_path", "database/openid_consumer_cache" ), self.root )
self.cookie_path = kwargs.get( "cookie_path", "/" )
- # web API
- self.enable_api = string_as_bool( kwargs.get( 'enable_api', False ) )
# Galaxy OpenID settings
self.enable_openid = string_as_bool( kwargs.get( 'enable_openid', False ) )
self.openid_config = kwargs.get( 'openid_config_file', 'openid_conf.xml' )
diff -r bb7f51fb545d0517eeceb902fa83dc5a659c64df -r 8376ad08ae41b9b7efa06622b031cb731e2c0bcf lib/galaxy/web/buildapp.py
--- a/lib/galaxy/web/buildapp.py
+++ b/lib/galaxy/web/buildapp.py
@@ -103,37 +103,37 @@
webapp.add_route( '/u/:username/h/:slug', controller='history', action='display_by_username_and_slug' )
webapp.add_route( '/u/:username/w/:slug', controller='workflow', action='display_by_username_and_slug' )
webapp.add_route( '/u/:username/v/:slug', controller='visualization', action='display_by_username_and_slug' )
- # If enabled, add the web API
- if asbool( kwargs.get( 'enable_api', False ) ):
- add_api_controllers( webapp, app )
- webapp.api_mapper.resource( 'content',
- 'contents',
- controller='library_contents',
- name_prefix='library_',
- path_prefix='/api/libraries/:library_id',
- parent_resources=dict( member_name='library', collection_name='libraries' ) )
- webapp.api_mapper.resource( 'content',
- 'contents',
- controller='history_contents',
- name_prefix='history_',
- path_prefix='/api/histories/:history_id',
- parent_resources=dict( member_name='history', collection_name='histories' ) )
- webapp.api_mapper.resource( 'permission',
- 'permissions',
- path_prefix='/api/libraries/:library_id',
- parent_resources=dict( member_name='library', collection_name='libraries' ) )
- webapp.api_mapper.resource( 'library', 'libraries', path_prefix='/api' )
- webapp.api_mapper.resource( 'sample', 'samples', path_prefix='/api' )
- webapp.api_mapper.resource( 'request', 'requests', path_prefix='/api' )
- webapp.api_mapper.resource( 'form', 'forms', path_prefix='/api' )
- webapp.api_mapper.resource( 'request_type', 'request_types', path_prefix='/api' )
- webapp.api_mapper.resource( 'role', 'roles', path_prefix='/api' )
- webapp.api_mapper.resource_with_deleted( 'quota', 'quotas', path_prefix='/api' )
- webapp.api_mapper.resource( 'tool', 'tools', path_prefix='/api' )
- webapp.api_mapper.resource_with_deleted( 'user', 'users', path_prefix='/api' )
- webapp.api_mapper.resource( 'workflow', 'workflows', path_prefix='/api' )
- webapp.api_mapper.resource_with_deleted( 'history', 'histories', path_prefix='/api' )
- #webapp.api_mapper.connect( 'run_workflow', '/api/workflow/{workflow_id}/library/{library_id}', controller='workflows', action='run', workflow_id=None, library_id=None, conditions=dict(method=["GET"]) )
+
+ # Add the web API
+ add_api_controllers( webapp, app )
+ webapp.api_mapper.resource( 'content',
+ 'contents',
+ controller='library_contents',
+ name_prefix='library_',
+ path_prefix='/api/libraries/:library_id',
+ parent_resources=dict( member_name='library', collection_name='libraries' ) )
+ webapp.api_mapper.resource( 'content',
+ 'contents',
+ controller='history_contents',
+ name_prefix='history_',
+ path_prefix='/api/histories/:history_id',
+ parent_resources=dict( member_name='history', collection_name='histories' ) )
+ webapp.api_mapper.resource( 'permission',
+ 'permissions',
+ path_prefix='/api/libraries/:library_id',
+ parent_resources=dict( member_name='library', collection_name='libraries' ) )
+ webapp.api_mapper.resource( 'library', 'libraries', path_prefix='/api' )
+ webapp.api_mapper.resource( 'sample', 'samples', path_prefix='/api' )
+ webapp.api_mapper.resource( 'request', 'requests', path_prefix='/api' )
+ webapp.api_mapper.resource( 'form', 'forms', path_prefix='/api' )
+ webapp.api_mapper.resource( 'request_type', 'request_types', path_prefix='/api' )
+ webapp.api_mapper.resource( 'role', 'roles', path_prefix='/api' )
+ webapp.api_mapper.resource_with_deleted( 'quota', 'quotas', path_prefix='/api' )
+ webapp.api_mapper.resource( 'tool', 'tools', path_prefix='/api' )
+ webapp.api_mapper.resource_with_deleted( 'user', 'users', path_prefix='/api' )
+ webapp.api_mapper.resource( 'workflow', 'workflows', path_prefix='/api' )
+ webapp.api_mapper.resource_with_deleted( 'history', 'histories', path_prefix='/api' )
+ #webapp.api_mapper.connect( 'run_workflow', '/api/workflow/{workflow_id}/library/{library_id}', controller='workflows', action='run', workflow_id=None, library_id=None, conditions=dict(method=["GET"]) )
webapp.finalize_config()
# Wrap the webapp in some useful middleware
diff -r bb7f51fb545d0517eeceb902fa83dc5a659c64df -r 8376ad08ae41b9b7efa06622b031cb731e2c0bcf lib/galaxy/web/controllers/requests_admin.py
--- a/lib/galaxy/web/controllers/requests_admin.py
+++ b/lib/galaxy/web/controllers/requests_admin.py
@@ -625,9 +625,6 @@
or not scp_configs.get( 'user_name', '' ) \
or not scp_configs.get( 'password', '' ):
err_msg += "Error in external service login information. "
- # Make sure web API is enabled and API key exists
- if not trans.app.config.enable_api:
- err_msg += "The 'enable_api = True' setting is not correctly set in the Galaxy config file. "
if not trans.user.api_keys:
err_msg += "Set your API Key in your User Preferences to transfer datasets. "
# Check if library_import_dir is set
diff -r bb7f51fb545d0517eeceb902fa83dc5a659c64df -r 8376ad08ae41b9b7efa06622b031cb731e2c0bcf lib/galaxy/webapps/community/config.py
--- a/lib/galaxy/webapps/community/config.py
+++ b/lib/galaxy/webapps/community/config.py
@@ -39,8 +39,6 @@
self.file_path = resolve_path( kwargs.get( "file_path", "database/files" ), self.root )
self.new_file_path = resolve_path( kwargs.get( "new_file_path", "database/tmp" ), self.root )
self.cookie_path = kwargs.get( "cookie_path", "/" )
- # web API
- self.enable_api = string_as_bool( kwargs.get( 'enable_api', False ) )
self.enable_quotas = string_as_bool( kwargs.get( 'enable_quotas', False ) )
self.datatypes_config = kwargs.get( 'datatypes_config_file', 'datatypes_conf.xml' )
self.test_conf = resolve_path( kwargs.get( "test_conf", "" ), self.root )
diff -r bb7f51fb545d0517eeceb902fa83dc5a659c64df -r 8376ad08ae41b9b7efa06622b031cb731e2c0bcf scripts/api/README
--- a/scripts/api/README
+++ b/scripts/api/README
@@ -3,7 +3,6 @@
Set these options in universe_wsgi.ini and start the server:
-enable_api = True
admin_users = you(a)example.org
library_import_dir = /path/to/some/directory
diff -r bb7f51fb545d0517eeceb902fa83dc5a659c64df -r 8376ad08ae41b9b7efa06622b031cb731e2c0bcf templates/user/index.mako
--- a/templates/user/index.mako
+++ b/templates/user/index.mako
@@ -12,9 +12,7 @@
%if webapp == 'galaxy':
<li><a href="${h.url_for( controller='user', action='manage_user_info', cntrller=cntrller, webapp=webapp )}">${_('Manage your information')}</a></li><li><a href="${h.url_for( controller='user', action='set_default_permissions', cntrller=cntrller, webapp=webapp )}">${_('Change default permissions')}</a> for new histories</li>
- %if trans.app.config.enable_api:
- <li><a href="${h.url_for( controller='user', action='api_keys', cntrller=cntrller, webapp=webapp )}">${_('Manage your API keys')}</a></li>
- %endif
+ <li><a href="${h.url_for( controller='user', action='api_keys', cntrller=cntrller, webapp=webapp )}">${_('Manage your API keys')}</a></li>
%if trans.app.config.enable_openid:
<li><a href="${h.url_for( controller='user', action='openid_manage', cntrller=cntrller, webapp=webapp )}">${_('Manage OpenIDs')}</a> linked to your account</li>
%endif
diff -r bb7f51fb545d0517eeceb902fa83dc5a659c64df -r 8376ad08ae41b9b7efa06622b031cb731e2c0bcf templates/webapps/galaxy/base_panels.mako
--- a/templates/webapps/galaxy/base_panels.mako
+++ b/templates/webapps/galaxy/base_panels.mako
@@ -166,8 +166,7 @@
menu_options.append( [ _('Saved Datasets'), h.url_for( controller='/dataset', action='list' ), "galaxy_main" ] )
if app.config.get_bool( 'enable_pages', False ):
menu_options.append( [ _('Saved Pages'), h.url_for( controller='/page', action='list' ), "_top" ] )
- if app.config.enable_api:
- menu_options.append( [ _('API Keys'), h.url_for( controller='/user', action='api_keys', cntrller='user', webapp='galaxy' ), "galaxy_main" ] )
+ menu_options.append( [ _('API Keys'), h.url_for( controller='/user', action='api_keys', cntrller='user', webapp='galaxy' ), "galaxy_main" ] )
if app.config.use_remote_user:
menu_options.append( [ _('Public Name'), h.url_for( controller='/user', action='edit_username', cntrller='user', webapp='galaxy' ), "galaxy_main" ] )
diff -r bb7f51fb545d0517eeceb902fa83dc5a659c64df -r 8376ad08ae41b9b7efa06622b031cb731e2c0bcf test/functional/test_sample_tracking.py
--- a/test/functional/test_sample_tracking.py
+++ b/test/functional/test_sample_tracking.py
@@ -853,7 +853,7 @@
sample_dataset_ids = [ self.security.encode_id( dataset.id ) for dataset in request1_sample1.datasets ]
strings_displayed = [ 'Manage "%s" datasets' % request1_sample1.name ]
strings_displayed_count = [ ( galaxy.model.SampleDataset.transfer_status.NOT_STARTED, len( request1_sample1.datasets ) ) ]
- strings_displayed_after_submit = [ "Error in sequencer login information. The 'enable_api = True' setting is not correctly set in the Galaxy config file. Set your API Key in your User Preferences to transfer datasets." ]
+ strings_displayed_after_submit = [ "Error in sequencer login information. Please set your API Key in your User Preferences to transfer datasets." ]
strings_not_displayed = [ galaxy.model.SampleDataset.transfer_status.IN_QUEUE,
galaxy.model.SampleDataset.transfer_status.TRANSFERRING,
galaxy.model.SampleDataset.transfer_status.ADD_TO_LIBRARY,
diff -r bb7f51fb545d0517eeceb902fa83dc5a659c64df -r 8376ad08ae41b9b7efa06622b031cb731e2c0bcf universe_wsgi.ini.sample
--- a/universe_wsgi.ini.sample
+++ b/universe_wsgi.ini.sample
@@ -504,9 +504,6 @@
#enable_openid = False
#openid_config_file = openid_conf.xml
-# Enable the (experimental! beta!) Web API. Documentation forthcoming.
-#enable_api = False
-
# Optional list of email addresses of API users who can make calls on behalf of
# other users
#api_allow_run_as = None
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dannon: Tabular dataset display - Remove logs, revert scroll detection to base.
by Bitbucket 11 Apr '12
by Bitbucket 11 Apr '12
11 Apr '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/bb7f51fb545d/
changeset: bb7f51fb545d
user: dannon
date: 2012-04-11 18:03:51
summary: Tabular dataset display - Remove logs, revert scroll detection to base.
affected #: 1 file
diff -r ff62ddc66b1a454e9b3ba11297c0bd8e2a74dc8d -r bb7f51fb545d0517eeceb902fa83dc5a659c64df templates/dataset/tabular_chunked.mako
--- a/templates/dataset/tabular_chunked.mako
+++ b/templates/dataset/tabular_chunked.mako
@@ -39,11 +39,7 @@
$(document).ready(function(){
fillTable();
$(window).scroll(function(){
- console.log($(window).scrollTop());
- console.log($(document).height());
- console.log($(window).height());
- // if ($(window).scrollTop() == $(document).height() - $(window).height()){
- if ($(document).height() - $(window).scrollTop() <= $(window).height()){
+ if ($(window).scrollTop() == $(document).height() - $(window).height()){
fillTable();
}
});
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
11 Apr '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/ff62ddc66b1a/
changeset: ff62ddc66b1a
user: dannon
date: 2012-04-11 17:52:52
summary: Incremental display for tabular datatypes.
affected #: 9 files
diff -r 60061d1a369635facf858766c7a992272b806750 -r ff62ddc66b1a454e9b3ba11297c0bd8e2a74dc8d lib/galaxy/datatypes/binary.py
--- a/lib/galaxy/datatypes/binary.py
+++ b/lib/galaxy/datatypes/binary.py
@@ -34,6 +34,17 @@
"""Returns the mime type of the datatype"""
return 'application/octet-stream'
+ def display_data(self, trans, dataset, preview=False, filename=None, to_ext=None, size=None, offset=None, **kwd):
+ trans.response.set_content_type(dataset.get_mime())
+ trans.log_event( "Display dataset id: %s" % str( dataset.id ) )
+ trans.response.headers['Content-Length'] = int( os.stat( dataset.file_name ).st_size )
+ to_ext = dataset.extension
+ valid_chars = '.,^_-()[]0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ fname = ''.join(c in valid_chars and c or '_' for c in dataset.name)[0:150]
+ trans.response.set_content_type( "application/octet-stream" ) #force octet-stream so Safari doesn't append mime extensions to filename
+ trans.response.headers["Content-Disposition"] = 'attachment; filename="Galaxy%s-[%s].%s"' % (dataset.hid, fname, to_ext)
+ return open( dataset.file_name )
+
class Ab1( Binary ):
"""Class describing an ab1 binary sequence file"""
file_ext = "ab1"
diff -r 60061d1a369635facf858766c7a992272b806750 -r ff62ddc66b1a454e9b3ba11297c0bd8e2a74dc8d lib/galaxy/datatypes/data.py
--- a/lib/galaxy/datatypes/data.py
+++ b/lib/galaxy/datatypes/data.py
@@ -39,7 +39,7 @@
'test'
>>> type( DataTest.metadata_spec.test.param )
<class 'galaxy.datatypes.metadata.MetadataParameter'>
-
+
"""
__metaclass__ = DataMeta
# Add metadata elements
@@ -60,7 +60,7 @@
primary_file_name = 'index'
#A per datatype setting (inherited): max file size (in bytes) for setting optional metadata
_max_optional_metadata_filesize = None
-
+
def __init__(self, **kwd):
"""Initialize the datatype"""
object.__init__(self, **kwd)
@@ -118,7 +118,7 @@
to_check = dataset.metadata.items()
for key, value in to_check:
if key in skip or ( not check and dataset.metadata.spec[key].get( "optional" ) ):
- continue #we skip check for optional and nonrequested values here
+ continue #we skip check for optional and nonrequested values here
if not value:
return True
return False
@@ -142,6 +142,7 @@
else:
dataset.peek = 'file does not exist'
dataset.blurb = 'file purged from disk'
+
def display_peek(self, dataset ):
"""Create HTML table, used for displaying peek"""
out = ['<table cellspacing="0" cellpadding="3">']
@@ -163,6 +164,158 @@
except Exception, exc:
out = "Can't create peek %s" % str( exc )
return out
+
+ def _archive_composite_dataset( self, trans, data=None, **kwd ):
+ # save a composite object into a compressed archive for downloading
+ params = util.Params( kwd )
+ valid_chars = '.,^_-()[]0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ outfname = data.name[0:150]
+ outfname = ''.join(c in valid_chars and c or '_' for c in outfname)
+ if (params.do_action == None):
+ params.do_action = 'zip' # default
+ msg = util.restore_text( params.get( 'msg', '' ) )
+ messagetype = params.get( 'messagetype', 'done' )
+ if not data:
+ msg = "You must select at least one dataset"
+ messagetype = 'error'
+ else:
+ error = False
+ try:
+ if (params.do_action == 'zip'):
+ # Can't use mkstemp - the file must not exist first
+ tmpd = tempfile.mkdtemp()
+ tmpf = os.path.join( tmpd, 'library_download.' + params.do_action )
+ if ziptype == '64':
+ archive = zipfile.ZipFile( tmpf, 'w', zipfile.ZIP_DEFLATED, True )
+ else:
+ archive = zipfile.ZipFile( tmpf, 'w', zipfile.ZIP_DEFLATED )
+ archive.add = lambda x, y: archive.write( x, y.encode('CP437') )
+ elif params.do_action == 'tgz':
+ archive = util.streamball.StreamBall( 'w|gz' )
+ elif params.do_action == 'tbz':
+ archive = util.streamball.StreamBall( 'w|bz2' )
+ except (OSError, zipfile.BadZipFile):
+ error = True
+ log.exception( "Unable to create archive for download" )
+ msg = "Unable to create archive for %s for download, please report this error" % outfname
+ messagetype = 'error'
+ if not error:
+ current_user_roles = trans.get_current_user_roles()
+ ext = data.extension
+ path = data.file_name
+ fname = os.path.split(path)[-1]
+ efp = data.extra_files_path
+ htmlname = os.path.splitext(outfname)[0]
+ if not htmlname.endswith(ext):
+ htmlname = '%s_%s' % (htmlname,ext)
+ archname = '%s.html' % htmlname # fake the real nature of the html file
+ try:
+ archive.add(data.file_name,archname)
+ except IOError:
+ error = True
+ log.exception( "Unable to add composite parent %s to temporary library download archive" % data.file_name)
+ msg = "Unable to create archive for download, please report this error"
+ messagetype = 'error'
+ for root, dirs, files in os.walk(efp):
+ for fname in files:
+ fpath = os.path.join(root,fname)
+ rpath = os.path.relpath(fpath,efp)
+ try:
+ archive.add( fpath,rpath )
+ except IOError:
+ error = True
+ log.exception( "Unable to add %s to temporary library download archive" % rpath)
+ msg = "Unable to create archive for download, please report this error"
+ messagetype = 'error'
+ continue
+ if not error:
+ if params.do_action == 'zip':
+ archive.close()
+ tmpfh = open( tmpf )
+ # CANNOT clean up - unlink/rmdir was always failing because file handle retained to return - must rely on a cron job to clean up tmp
+ trans.response.set_content_type( "application/x-zip-compressed" )
+ trans.response.headers[ "Content-Disposition" ] = 'attachment; filename="%s.zip"' % outfname
+ return tmpfh
+ else:
+ trans.response.set_content_type( "application/x-tar" )
+ outext = 'tgz'
+ if params.do_action == 'tbz':
+ outext = 'tbz'
+ trans.response.headers[ "Content-Disposition" ] = 'attachment; filename="%s.%s"' % (outfname,outext)
+ archive.wsgi_status = trans.response.wsgi_status()
+ archive.wsgi_headeritems = trans.response.wsgi_headeritems()
+ return archive.stream
+ return trans.show_error_message( msg )
+
+ def _serve_raw(self, trans, dataset, to_ext):
+ trans.response.headers['Content-Length'] = int( os.stat( dataset.file_name ).st_size )
+ valid_chars = '.,^_-()[]0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ fname = ''.join(c in valid_chars and c or '_' for c in dataset.name)[0:150]
+ trans.response.set_content_type( "application/octet-stream" ) #force octet-stream so Safari doesn't append mime extensions to filename
+ trans.response.headers["Content-Disposition"] = 'attachment; filename="Galaxy%s-[%s].%s"' % (dataset.hid, fname, to_ext)
+ return open( dataset.file_name )
+
+ def display_data(self, trans, dataset, preview=False, filename=None, to_ext=None, size=None, offset=None, **kwd):
+ """ Old display method, for transition """
+ #Relocate all composite datatype display to a common location.
+ composite_extensions = trans.app.datatypes_registry.get_composite_extensions( )
+ composite_extensions.append('html') # for archiving composite datatypes
+ if isinstance( dataset, basestring ):
+ return dataset
+ if filename and filename != "index":
+ # For files in extra_files_path
+ file_path = trans.app.object_store.get_filename(dataset, extra_dir='dataset_%s_files' % dataset.id, alt_name=filename)
+ if os.path.exists( file_path ):
+ if os.path.isdir( file_path ):
+ return trans.show_error_message( "Directory listing is not allowed." ) #TODO: Reconsider allowing listing of directories?
+ mime, encoding = mimetypes.guess_type( file_path )
+ if not mime:
+ try:
+ mime = trans.app.datatypes_registry.get_mimetype_by_extension( ".".split( file_path )[-1] )
+ except:
+ mime = "text/plain"
+ trans.response.set_content_type( mime )
+ return open( file_path )
+ else:
+ return trans.show_error_message( "Could not find '%s' on the extra files path %s." % ( filename, file_path ) )
+ trans.response.set_content_type(dataset.get_mime())
+ trans.log_event( "Display dataset id: %s" % str( dataset.id ) )
+ from galaxy import datatypes #DBTODO REMOVE THIS AT REFACTOR
+ if to_ext or isinstance(dataset.datatype, datatypes.binary.Binary): # Saving the file, or binary file
+ if dataset.extension in composite_extensions:
+ return self._archive_composite_dataset( trans, dataset, **kwd )
+ else:
+ trans.response.headers['Content-Length'] = int( os.stat( dataset.file_name ).st_size )
+ if not to_ext:
+ to_ext = dataset.extension
+ valid_chars = '.,^_-()[]0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ fname = ''.join(c in valid_chars and c or '_' for c in dataset.name)[0:150]
+ trans.response.set_content_type( "application/octet-stream" ) #force octet-stream so Safari doesn't append mime extensions to filename
+ trans.response.headers["Content-Disposition"] = 'attachment; filename="Galaxy%s-[%s].%s"' % (dataset.hid, fname, to_ext)
+ return open( dataset.file_name )
+ if not os.path.exists( dataset.file_name ):
+ raise paste.httpexceptions.HTTPNotFound( "File Not Found (%s)." % dataset.file_name )
+ max_peek_size = 1000000 # 1 MB
+ if isinstance(dataset.datatype, datatypes.images.Html):
+ max_peek_size = 10000000 # 10 MB for html
+ if not preview or isinstance(dataset.datatype, datatypes.images.Image) or os.stat( dataset.file_name ).st_size < max_peek_size:
+ if trans.app.config.sanitize_all_html and trans.response.get_content_type() == "text/html":
+ # Sanitize anytime we respond with plain text/html content.
+ return sanitize_html(open( dataset.file_name ).read())
+ return open( dataset.file_name )
+ else:
+ trans.response.set_content_type( "text/html" )
+ return trans.stream_template_mako( "/dataset/large_file.mako",
+ truncated_data = open( dataset.file_name ).read(max_peek_size),
+ data = dataset )
+ """Returns dataset contents for display.
+ This allows for customization of subtype displays"""
+ file_path = trans.app.object_store.get_filename(dataset, extra_dir='dataset_%s_files' % dataset.id, alt_name=filename)
+ if size:
+ return open(dataset.file_path).read(size)
+ else:
+ open(dataset.file_path)
+
def display_name(self, dataset):
"""Returns formatted html of dataset name"""
try:
@@ -183,11 +336,11 @@
info = info.replace( '\r', '<br/>' )
if info.find( '\n' ) >= 0:
info = info.replace( '\n', '<br/>' )
-
+
# Convert to unicode to display non-ascii characters.
if type( info ) is not unicode:
info = unicode( info, 'utf-8')
-
+
return info
except:
return "info unavailable"
@@ -272,7 +425,7 @@
def convert_dataset(self, trans, original_dataset, target_type, return_output=False, visible=True, deps=None, set_output_history=True):
"""This function adds a job to the queue to convert a dataset to another type. Returns a message about success/failure."""
converter = trans.app.datatypes_registry.get_converter_by_target_type( original_dataset.ext, target_type )
-
+
if converter is None:
raise Exception( "A converter does not exist for %s to %s." % ( original_dataset.ext, target_type ) )
#Generate parameter dictionary
@@ -284,7 +437,7 @@
params[value.name] = deps[value.name]
elif value.type == 'data':
input_name = key
-
+
params[input_name] = original_dataset
#Run converter, job is dispatched through Queue
converted_dataset = converter.execute( trans, incoming=params, set_output_hid=visible, set_output_history=set_output_history)[1]
@@ -351,18 +504,18 @@
@property
def has_resolution(self):
return False
-
-
- def merge( split_files, output_file):
+
+
+ def merge( split_files, output_file):
"""
TODO: Do we need to merge gzip files using gzjoin? cat seems to work,
but might be brittle. Need to revisit this.
"""
if len(split_files) == 1:
- cmd = 'mv -f %s %s' % ( split_files[0], output_file )
+ cmd = 'mv -f %s %s' % ( split_files[0], output_file )
else:
- cmd = 'cat %s > %s' % ( ' '.join(split_files), output_file )
+ cmd = 'cat %s > %s' % ( ' '.join(split_files), output_file )
result = os.system(cmd)
if result != 0:
raise Exception('Result %s from %s' % (result, cmd))
@@ -377,7 +530,7 @@
def write_from_stream(self, dataset, stream):
"""Writes data from a stream"""
- # write it twice for now
+ # write it twice for now
fd, temp_name = tempfile.mkstemp()
while 1:
chunk = stream.read(1048576)
@@ -468,11 +621,11 @@
"""
if split_params is None:
return
-
+
if len(input_datasets) > 1:
raise Exception("Text file splitting does not support multiple files")
input_files = [ds.file_name for ds in input_datasets]
-
+
lines_per_file = None
chunk_size = None
if split_params['split_mode'] == 'number_of_parts':
@@ -501,7 +654,7 @@
chunk_size = int(split_params['split_size'])
else:
raise Exception('Unsupported split mode %s' % split_params['split_mode'])
-
+
f = open(input_files[0], 'rt')
try:
chunk_idx = 0
@@ -562,7 +715,7 @@
def get_file_peek( file_name, is_multi_byte=False, WIDTH=256, LINE_COUNT=5, skipchars=[] ):
"""
Returns the first LINE_COUNT lines wrapped to WIDTH
-
+
## >>> fname = get_test_fname('4.bed')
## >>> get_file_peek(fname)
## 'chr22 30128507 31828507 uc003bnx.1_cds_2_0_chr22_29227_f 0 +\n'
@@ -601,11 +754,12 @@
lines.append( line )
count += 1
temp.close()
- if file_type in [ 'gzipped', 'binary' ]:
- text = "%s file" % file_type
+ if file_type in [ 'gzipped', 'binary' ]:
+ text = "%s file" % file_type
else:
try:
text = unicode( '\n'.join( lines ), 'utf-8' )
except UnicodeDecodeError:
text = "binary/unknown file"
return text
+
diff -r 60061d1a369635facf858766c7a992272b806750 -r ff62ddc66b1a454e9b3ba11297c0bd8e2a74dc8d lib/galaxy/datatypes/tabular.py
--- a/lib/galaxy/datatypes/tabular.py
+++ b/lib/galaxy/datatypes/tabular.py
@@ -13,11 +13,13 @@
from galaxy.datatypes.metadata import MetadataElement
import galaxy_utils.sequence.vcf
from sniff import *
+from galaxy.util.json import to_json_string
log = logging.getLogger(__name__)
class Tabular( data.Text ):
"""Tab delimited data"""
+ CHUNK_SIZE = 20000
"""Add metadata elements"""
MetadataElement( name="comment_lines", default=0, desc="Number of comment lines", readonly=False, optional=True, no_value=0 )
@@ -33,15 +35,15 @@
that contain numerical values in the dataset. A skip parameter is
used because various tabular data types reuse this function, and
their data type classes are responsible to determine how many invalid
- comment lines should be skipped. Using None for skip will cause skip
- to be zero, but the first line will be processed as a header. A
- max_data_lines parameter is used because various tabular data types
- reuse this function, and their data type classes are responsible to
+ comment lines should be skipped. Using None for skip will cause skip
+ to be zero, but the first line will be processed as a header. A
+ max_data_lines parameter is used because various tabular data types
+ reuse this function, and their data type classes are responsible to
determine how many data lines should be processed to ensure that the
- non-optional metadata parameters are properly set; if used, optional
- metadata parameters will be set to None, unless the entire file has
- already been read. Using None (default) for max_data_lines will
- process all data lines.
+ non-optional metadata parameters are properly set; if used, optional
+ metadata parameters will be set to None, unless the entire file has
+ already been read. Using None (default) for max_data_lines will
+ process all data lines.
Items of interest:
1. We treat 'overwrite' as always True (we always want to set tabular metadata when called).
@@ -58,7 +60,7 @@
column_type_set_order = [ 'int', 'float', 'list', 'str' ] #Order to set column types in
default_column_type = column_type_set_order[-1] # Default column type is lowest in list
column_type_compare_order = list( column_type_set_order ) #Order to compare column types
- column_type_compare_order.reverse()
+ column_type_compare_order.reverse()
def type_overrules_type( column_type1, column_type2 ):
if column_type1 is None or column_type1 == column_type2:
return False
@@ -75,13 +77,13 @@
try:
int( column_text )
return True
- except:
+ except:
return False
def is_float( column_text ):
try:
float( column_text )
return True
- except:
+ except:
if column_text.strip().lower() == 'na':
return True #na is special cased to be a float
return False
@@ -126,7 +128,7 @@
if type_overrules_type( column_type, column_types[field_count] ):
column_types[field_count] = column_type
if i == 0 and requested_skip is None:
- # This is our first line, people seem to like to upload files that have a header line, but do not
+ # This is our first line, people seem to like to upload files that have a header line, but do not
# start with '#' (i.e. all column types would then most likely be detected as str). We will assume
# that the first line is always a header (this was previous behavior - it was always skipped). When
# the requested skip is None, we only use the data from the first line if we have no other data for
@@ -148,7 +150,7 @@
break
i += 1
dataset_fh.close()
-
+
#we error on the larger number of columns
#first we pad our column_types by using data from first line
if len( first_line_column_types ) > len( column_types ):
@@ -177,6 +179,7 @@
except Exception, exc:
out = "Can't create peek %s" % str( exc )
return out
+
def make_html_peek_header( self, dataset, skipchars=[], column_names=[], column_number_format='%s', column_parameter_alias={}, **kwargs ):
out = []
try:
@@ -212,6 +215,7 @@
except Exception, exc:
raise Exception, "Can't create peek header %s" % str( exc )
return "".join( out )
+
def make_html_peek_rows( self, dataset, skipchars=[], **kwargs ):
out = []
try:
@@ -233,6 +237,28 @@
except Exception, exc:
raise Exception, "Can't create peek rows %s" % str( exc )
return "".join( out )
+
+ def display_data(self, trans, dataset, preview=False, filename=None, to_ext=None, chunk=None):
+ #TODO Prevent failure when displaying extremely long > 50kb lines.
+ if to_ext:
+ return self._serve_raw(trans, dataset, to_ext)
+ if chunk:
+ ck_index = int(chunk)
+ f = open(dataset.file_name)
+ f.seek(ck_index * self.CHUNK_SIZE)
+ # If we aren't at the start of the file, seek to next newline. Do this better eventually.
+ if f.tell() != 0:
+ cursor = f.read(1)
+ while cursor and cursor != '\n':
+ cursor = f.read(1)
+ ck_data = f.read(self.CHUNK_SIZE)
+ cursor = f.read(1)
+ while cursor and ck_data[-1] != '\n':
+ ck_data += cursor
+ cursor = f.read(1)
+ return to_json_string({'ck_data': ck_data, 'ck_index': ck_index+1})
+ return trans.fill_template( "/dataset/tabular_chunked.mako",dataset = dataset)
+
def set_peek( self, dataset, line_count=None, is_multi_byte=False):
super(Tabular, self).set_peek( dataset, line_count=line_count, is_multi_byte=is_multi_byte)
if dataset.metadata.comment_lines:
@@ -281,7 +307,7 @@
def sniff( self, filename ):
"""
Determines whether the file is in SAM format
-
+
A file in SAM format consists of lines of tab-separated data.
The following header line may be the first line:
@QNAME FLAG RNAME POS MAPQ CIGAR MRNM MPOS ISIZE SEQ QUAL
@@ -290,12 +316,12 @@
Data in the OPT column is optional and can consist of tab-separated data
For complete details see http://samtools.sourceforge.net/SAM1.pdf
-
+
Rules for sniffing as True:
There must be 11 or more columns of data on each line
Columns 2 (FLAG), 4(POS), 5 (MAPQ), 8 (MPOS), and 9 (ISIZE) must be numbers (9 can be negative)
We will only check that up to the first 5 alignments are correctly formatted.
-
+
>>> fname = get_test_fname( 'sequence.maf' )
>>> Sam().sniff( fname )
False
@@ -311,7 +337,7 @@
line = line.strip()
if not line:
break #EOF
- if line:
+ if line:
if line[0] != '@':
linePieces = line.split('\t')
if len(linePieces) < 11:
@@ -373,10 +399,10 @@
if result != 0:
raise Exception('Result %s from %s' % (result, cmd))
merge = staticmethod(merge)
-
+
def get_track_type( self ):
return "ReadTrack", {"data": "bam", "index": "summary_tree"}
-
+
class Pileup( Tabular ):
"""Tab delimited data in pileup (6- or 10-column) format"""
file_ext = "pileup"
@@ -402,7 +428,7 @@
"""
Checks for 'pileup-ness'
- There are two main types of pileup: 6-column and 10-column. For both,
+ There are two main types of pileup: 6-column and 10-column. For both,
the first three and last two columns are the same. We only check the
first three to allow for some personalization of the format.
@@ -436,27 +462,27 @@
class ElandMulti( Tabular ):
file_ext = 'elandmulti'
-
+
def sniff( self, filename ):
return False
-
+
class Vcf( Tabular ):
""" Variant Call Format for describing SNPs and other simple genome variations. """
-
+
file_ext = 'vcf'
column_names = [ 'Chrom', 'Pos', 'ID', 'Ref', 'Alt', 'Qual', 'Filter', 'Info', 'Format', 'data' ]
-
+
MetadataElement( name="columns", default=10, desc="Number of columns", readonly=True, visible=False )
MetadataElement( name="column_types", default=['str','int','str','str','str','int','str','list','str','str'], param=metadata.ColumnTypesParameter, desc="Column types", readonly=True, visible=False )
MetadataElement( name="viz_filter_cols", desc="Score column for visualization", default=[5], param=metadata.ColumnParameter, multiple=True )
-
+
def sniff( self, filename ):
headers = get_headers( filename, '\n', count=1 )
return headers[0][0].startswith("##fileformat=VCF")
def display_peek( self, dataset ):
"""Returns formated html of peek"""
return Tabular.make_html_table( self, dataset, column_names=self.column_names )
-
+
def get_track_type( self ):
return "VcfTrack", {"data": "tabix", "index": "summary_tree"}
@@ -500,10 +526,10 @@
def sniff( self, filename ):
"""
Determines whether the file is in ELAND export format
-
+
A file in ELAND export format consists of lines of tab-separated data.
There is no header.
-
+
Rules for sniffing as True:
There must be 22 columns on each line
LANE, TILEm X, Y, INDEX, READ_NO, SEQ, QUAL, POSITION, *STRAND, FILT must be correct
@@ -522,7 +548,7 @@
line = line.strip()
if not line:
break #EOF
- if line:
+ if line:
linePieces = line.split('\t')
if len(linePieces) != 22:
return False
@@ -568,7 +594,7 @@
#else:
# # Otherwise, read the whole thing and set num data lines.
for i, line in enumerate(dataset_fh):
- if line:
+ if line:
linePieces = line.split('\t')
if len(linePieces) != 22:
raise Exception('%s:%d:Corrupt line!' % (dataset.file_name,i))
@@ -586,5 +612,5 @@
dataset.metadata.tiles = ["%04d" % int(t) for t in tiles.keys()]
dataset.metadata.barcodes = filter(lambda x: x != '0', barcodes.keys()) + ['NoIndex' for x in barcodes.keys() if x == '0']
dataset.metadata.reads = reads.keys()
-
-
+
+
diff -r 60061d1a369635facf858766c7a992272b806750 -r ff62ddc66b1a454e9b3ba11297c0bd8e2a74dc8d lib/galaxy/web/controllers/dataset.py
--- a/lib/galaxy/web/controllers/dataset.py
+++ b/lib/galaxy/web/controllers/dataset.py
@@ -1,17 +1,22 @@
-import logging, os, string, shutil, re, socket, mimetypes, urllib, tempfile, zipfile, glob, sys
+import logging
+import mimetypes
+import os
+import string
+import sys
+import tempfile
+import urllib
+import zipfile
from galaxy.web.base.controller import *
from galaxy.web.framework.helpers import time_ago, iff, grids
-from galaxy import util, datatypes, jobs, web, model
-from cgi import escape, FieldStorage
+from galaxy import util, datatypes, web, model
from galaxy.datatypes.display_applications.util import encode_dataset_user, decode_dataset_user
from galaxy.util.sanitize_html import sanitize_html
from galaxy.util import inflector
from galaxy.model.item_attrs import *
-from galaxy.model import LibraryDatasetDatasetAssociation, HistoryDatasetAssociation
from galaxy.web.framework.helpers import to_unicode
-import pkg_resources;
+import pkg_resources;
pkg_resources.require( "Paste" )
import paste.httpexceptions
@@ -32,7 +37,7 @@
except RuntimeError:
log.exception( "Compression error when testing zip compression. This option will be disabled for library downloads." )
except (TypeError, zipfile.LargeZipFile): # ZIP64 is only in Python2.5+. Remove TypeError when 2.4 support is dropped
- log.warning( 'Max zip file size is 2GB, ZIP64 not supported' )
+ log.warning( 'Max zip file size is 2GB, ZIP64 not supported' )
comptypes.append( 'zip' )
try:
os.unlink( tmpf )
@@ -53,7 +58,7 @@
-----------------------------------------------------------------------------
You should be able to view the history containing the related history item
-${hid}: ${history_item_name}
+${hid}: ${history_item_name}
by logging in as a Galaxy admin user to the Galaxy instance referenced above
and pointing your browser to the following link.
@@ -90,7 +95,7 @@
class HistoryColumn( grids.GridColumn ):
def get_value( self, trans, grid, hda):
return hda.history.name
-
+
class StatusColumn( grids.GridColumn ):
def get_value( self, trans, grid, hda ):
if hda.deleted:
@@ -111,19 +116,19 @@
template='/dataset/grid.mako'
default_sort_key = "-update_time"
columns = [
- grids.TextColumn( "Name", key="name",
+ grids.TextColumn( "Name", key="name",
# Link name to dataset's history.
link=( lambda item: iff( item.history.deleted, None, dict( operation="switch", id=item.id ) ) ), filterable="advanced", attach_popup=True ),
- HistoryColumn( "History", key="history",
+ HistoryColumn( "History", key="history",
link=( lambda item: iff( item.history.deleted, None, dict( operation="switch_history", id=item.id ) ) ) ),
grids.IndividualTagsColumn( "Tags", key="tags", model_tag_association_class=model.HistoryDatasetAssociationTagAssociation, filterable="advanced", grid_name="HistoryDatasetAssocationListGrid" ),
StatusColumn( "Status", key="deleted", attach_popup=False ),
grids.GridColumn( "Last Updated", key="update_time", format=time_ago ),
]
- columns.append(
- grids.MulticolFilterColumn(
- "Search",
- cols_to_filter=[ columns[0], columns[2] ],
+ columns.append(
+ grids.MulticolFilterColumn(
+ "Search",
+ cols_to_filter=[ columns[0], columns[2] ],
key="free-text-search", visible=False, filterable="standard" )
)
operations = [
@@ -136,17 +141,17 @@
num_rows_per_page = 50
def build_initial_query( self, trans, **kwargs ):
# Show user's datasets that are not deleted, not in deleted histories, and not hidden.
- # To filter HDAs by user, need to join model class/HDA and History table so that it is
- # possible to filter by user. However, for dictionary-based filtering to work, need a
+ # To filter HDAs by user, need to join model class/HDA and History table so that it is
+ # possible to filter by user. However, for dictionary-based filtering to work, need a
# primary table for the query.
return trans.sa_session.query( self.model_class ).select_from( self.model_class.table.join( model.History.table ) ) \
.filter( model.History.user == trans.user ) \
.filter( self.model_class.deleted==False ) \
.filter( model.History.deleted==False ) \
.filter( self.model_class.visible==True )
-
+
class DatasetInterface( BaseUIController, UsesAnnotations, UsesHistory, UsesHistoryDatasetAssociation, UsesItemRatings ):
-
+
stored_list_grid = HistoryDatasetAssociationListGrid()
@web.expose
@@ -202,7 +207,7 @@
job_stdout=job.stdout,
job_info=job.info,
job_traceback=job.traceback,
- email=email,
+ email=email,
message=message )
frm = to_address
# Check email a bit
@@ -219,130 +224,45 @@
return trans.show_ok_message( "Your error report has been sent" )
except Exception, e:
return trans.show_error_message( "An error occurred sending the report by email: %s" % str( e ) )
-
+
@web.expose
def default(self, trans, dataset_id=None, **kwd):
return 'This link may not be followed from within Galaxy.'
-
- @web.expose
- def archive_composite_dataset( self, trans, data=None, **kwd ):
- # save a composite object into a compressed archive for downloading
- params = util.Params( kwd )
- valid_chars = '.,^_-()[]0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
- outfname = data.name[0:150]
- outfname = ''.join(c in valid_chars and c or '_' for c in outfname)
- if (params.do_action == None):
- params.do_action = 'zip' # default
- msg = util.restore_text( params.get( 'msg', '' ) )
- messagetype = params.get( 'messagetype', 'done' )
- if not data:
- msg = "You must select at least one dataset"
- messagetype = 'error'
- else:
- error = False
- try:
- if (params.do_action == 'zip'):
- # Can't use mkstemp - the file must not exist first
- tmpd = tempfile.mkdtemp()
- tmpf = os.path.join( tmpd, 'library_download.' + params.do_action )
- if ziptype == '64':
- archive = zipfile.ZipFile( tmpf, 'w', zipfile.ZIP_DEFLATED, True )
- else:
- archive = zipfile.ZipFile( tmpf, 'w', zipfile.ZIP_DEFLATED )
- archive.add = lambda x, y: archive.write( x, y.encode('CP437') )
- elif params.do_action == 'tgz':
- archive = util.streamball.StreamBall( 'w|gz' )
- elif params.do_action == 'tbz':
- archive = util.streamball.StreamBall( 'w|bz2' )
- except (OSError, zipfile.BadZipFile):
- error = True
- log.exception( "Unable to create archive for download" )
- msg = "Unable to create archive for %s for download, please report this error" % outfname
- messagetype = 'error'
- if not error:
- current_user_roles = trans.get_current_user_roles()
- ext = data.extension
- path = data.file_name
- fname = os.path.split(path)[-1]
- efp = data.extra_files_path
- htmlname = os.path.splitext(outfname)[0]
- if not htmlname.endswith(ext):
- htmlname = '%s_%s' % (htmlname,ext)
- archname = '%s.html' % htmlname # fake the real nature of the html file
- try:
- archive.add(data.file_name,archname)
- except IOError:
- error = True
- log.exception( "Unable to add composite parent %s to temporary library download archive" % data.file_name)
- msg = "Unable to create archive for download, please report this error"
- messagetype = 'error'
- for root, dirs, files in os.walk(efp):
- for fname in files:
- fpath = os.path.join(root,fname)
- rpath = os.path.relpath(fpath,efp)
- try:
- archive.add( fpath,rpath )
- except IOError:
- error = True
- log.exception( "Unable to add %s to temporary library download archive" % rpath)
- msg = "Unable to create archive for download, please report this error"
- messagetype = 'error'
- continue
- if not error:
- if params.do_action == 'zip':
- archive.close()
- tmpfh = open( tmpf )
- # CANNOT clean up - unlink/rmdir was always failing because file handle retained to return - must rely on a cron job to clean up tmp
- trans.response.set_content_type( "application/x-zip-compressed" )
- trans.response.headers[ "Content-Disposition" ] = 'attachment; filename="%s.zip"' % outfname
- return tmpfh
- else:
- trans.response.set_content_type( "application/x-tar" )
- outext = 'tgz'
- if params.do_action == 'tbz':
- outext = 'tbz'
- trans.response.headers[ "Content-Disposition" ] = 'attachment; filename="%s.%s"' % (outfname,outext)
- archive.wsgi_status = trans.response.wsgi_status()
- archive.wsgi_headeritems = trans.response.wsgi_headeritems()
- return archive.stream
- return trans.show_error_message( msg )
-
+
@web.expose
def get_metadata_file(self, trans, hda_id, metadata_name):
""" Allows the downloading of metadata files associated with datasets (eg. bai index for bam files) """
data = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( trans.security.decode_id( hda_id ) )
if not data or not trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), data.dataset ):
return trans.show_error_message( "You are not allowed to access this dataset" )
-
+
valid_chars = '.,^_-()[]0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
fname = ''.join(c in valid_chars and c or '_' for c in data.name)[0:150]
-
+
file_ext = data.metadata.spec.get(metadata_name).get("file_ext", metadata_name)
trans.response.headers["Content-Type"] = "application/octet-stream"
trans.response.headers["Content-Disposition"] = 'attachment; filename="Galaxy%s-[%s].%s"' % (data.hid, fname, file_ext)
return open(data.metadata.get(metadata_name).file_name)
-
- def _check_dataset(self, trans, dataset_id):
+
+ def _check_dataset(self, trans, hda_id):
# DEPRECATION: We still support unencoded ids for backward compatibility
try:
- data = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( trans.security.decode_id( dataset_id ) )
+ data = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( trans.security.decode_id( hda_id) )
if data is None:
- raise ValueError( 'Invalid reference dataset id: %s.' % dataset_id )
+ raise ValueError( 'Invalid reference dataset id: %s.' % hda_id)
except:
try:
- data = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( int( dataset_id ) )
+ data = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( int( hda_id ) )
except:
data = None
if not data:
- raise paste.httpexceptions.HTTPRequestRangeNotSatisfiable( "Invalid reference dataset id: %s." % str( dataset_id ) )
+ raise paste.httpexceptions.HTTPRequestRangeNotSatisfiable( "Invalid reference dataset id: %s." % str( hda_id ) )
if not trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), data.dataset ):
return trans.show_error_message( "You are not allowed to access this dataset" )
-
if data.state == trans.model.Dataset.states.UPLOAD:
return trans.show_error_message( "Please wait until this dataset finishes uploading before attempting to view it." )
-
return data
-
+
@web.expose
@web.json
def transfer_status(self, trans, dataset_id, filename=None):
@@ -352,7 +272,7 @@
if isinstance( data, basestring ):
return data
log.debug( "Checking transfer status for dataset %s..." % data.dataset.id )
-
+
# Pulling files in extra_files_path into cache is not handled via this
# method but that's primarily because those files are typically linked to
# through tool's output page anyhow so tying a JavaScript event that will
@@ -361,63 +281,11 @@
return True
else:
return trans.app.object_store.file_ready(data.dataset)
-
+
@web.expose
- def display(self, trans, dataset_id=None, preview=False, filename=None, to_ext=None, **kwd):
- """Catches the dataset id and displays file contents as directed"""
- composite_extensions = trans.app.datatypes_registry.get_composite_extensions( )
- composite_extensions.append('html') # for archiving composite datatypes
+ def display(self, trans, dataset_id=None, preview=False, filename=None, to_ext=None, chunk=None, **kwd):
data = self._check_dataset(trans, dataset_id)
- if isinstance( data, basestring ):
- return data
-
- if filename and filename != "index":
- # For files in extra_files_path
- file_path = trans.app.object_store.get_filename(data.dataset, extra_dir='dataset_%s_files' % data.dataset.id, alt_name=filename)
- if os.path.exists( file_path ):
- if os.path.isdir( file_path ):
- return trans.show_error_message( "Directory listing is not allowed." ) #TODO: Reconsider allowing listing of directories?
- mime, encoding = mimetypes.guess_type( file_path )
- if not mime:
- try:
- mime = trans.app.datatypes_registry.get_mimetype_by_extension( ".".split( file_path )[-1] )
- except:
- mime = "text/plain"
- trans.response.set_content_type( mime )
- return open( file_path )
- else:
- return trans.show_error_message( "Could not find '%s' on the extra files path %s." % ( filename, file_path ) )
-
- trans.response.set_content_type(data.get_mime())
- trans.log_event( "Display dataset id: %s" % str( dataset_id ) )
-
- if to_ext or isinstance(data.datatype, datatypes.binary.Binary): # Saving the file, or binary file
- if data.extension in composite_extensions:
- return self.archive_composite_dataset( trans, data, **kwd )
- else:
- trans.response.headers['Content-Length'] = int( os.stat( data.file_name ).st_size )
- if not to_ext:
- to_ext = data.extension
- valid_chars = '.,^_-()[]0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
- fname = ''.join(c in valid_chars and c or '_' for c in data.name)[0:150]
- trans.response.set_content_type( "application/octet-stream" ) #force octet-stream so Safari doesn't append mime extensions to filename
- trans.response.headers["Content-Disposition"] = 'attachment; filename="Galaxy%s-[%s].%s"' % (data.hid, fname, to_ext)
- return open( data.file_name )
- if not os.path.exists( data.file_name ):
- raise paste.httpexceptions.HTTPNotFound( "File Not Found (%s)." % data.file_name )
- max_peek_size = 1000000 # 1 MB
- if isinstance(data.datatype, datatypes.images.Html):
- max_peek_size = 10000000 # 10 MB for html
- if not preview or isinstance(data.datatype, datatypes.images.Image) or os.stat( data.file_name ).st_size < max_peek_size:
- if trans.app.config.sanitize_all_html and trans.response.get_content_type() == "text/html":
- # Sanitize anytime we respond with plain text/html content.
- return sanitize_html(open( data.file_name ).read())
- return open( data.file_name )
- else:
- trans.response.set_content_type( "text/html" )
- return trans.stream_template_mako( "/dataset/large_file.mako",
- truncated_data = open( data.file_name ).read(max_peek_size),
- data = data )
+ return data.datatype.display_data(trans, data, preview, filename, to_ext, chunk, **kwd)
@web.expose
def edit(self, trans, dataset_id=None, filename=None, hid=None, **kwd):
@@ -443,7 +311,7 @@
# TODO: hid handling
data = history.datasets[ int( hid ) - 1 ]
id = None
- elif dataset_id is not None:
+ elif dataset_id is not None:
id = trans.app.security.decode_id( dataset_id )
data = trans.sa_session.query( self.app.model.HistoryDatasetAssociation ).get( id )
else:
@@ -463,7 +331,7 @@
# permission. In this case, we'll reset this permission to the hda user's private role.
manage_permissions_action = trans.app.security_agent.get_action( trans.app.security_agent.permitted_actions.DATASET_MANAGE_PERMISSIONS.action )
permissions = { manage_permissions_action : [ trans.app.security_agent.get_private_user_role( data.history.user ) ] }
- trans.app.security_agent.set_dataset_permission( data.dataset, permissions )
+ trans.app.security_agent.set_dataset_permission( data.dataset, permissions )
if trans.app.security_agent.can_access_dataset( current_user_roles, data.dataset ):
if data.state == trans.model.Dataset.states.UPLOAD:
return trans.show_error_message( "Please wait until this dataset finishes uploading before attempting to edit its metadata." )
@@ -600,7 +468,7 @@
refresh_frames=refresh_frames )
else:
return trans.show_error_message( "You do not have permission to edit this dataset's ( id: %s ) information." % str( dataset_id ) )
-
+
@web.expose
@web.require_login( "see all available datasets" )
def list( self, trans, **kwargs ):
@@ -610,7 +478,7 @@
if 'operation' in kwargs:
operation = kwargs['operation'].lower()
hda_ids = util.listify( kwargs.get( 'id', [] ) )
-
+
# Display no message by default
status, message = None, None
@@ -630,15 +498,15 @@
if hdas:
if operation == "switch" or operation == "switch_history":
# Switch to a history that the HDA resides in.
-
+
# Convert hda to histories.
histories = []
for hda in hdas:
histories.append( hda.history )
-
+
# Use history controller to switch the history. TODO: is this reasonable?
status, message = trans.webapp.controllers['history']._list_switch( trans, histories )
-
+
# Current history changed, refresh history frame; if switching to a dataset, set hda seek.
trans.template_context['refresh_frames'] = ['history']
if operation == "switch":
@@ -648,35 +516,35 @@
# Copy a dataset to the current history.
target_histories = [ trans.get_history() ]
status, message = self._copy_datasets( trans, hda_ids, target_histories )
-
+
# Current history changed, refresh history frame.
trans.template_context['refresh_frames'] = ['history']
# Render the list view
return self.stored_list_grid( trans, status=status, message=message, **kwargs )
-
+
@web.expose
def imp( self, trans, dataset_id=None, **kwd ):
""" Import another user's dataset via a shared URL; dataset is added to user's current history. """
msg = ""
-
+
# Set referer message.
referer = trans.request.referer
if referer is not "":
referer_message = "<a href='%s'>return to the previous page</a>" % referer
else:
referer_message = "<a href='%s'>go to Galaxy's start page</a>" % url_for( '/' )
-
+
# Error checking.
if not dataset_id:
return trans.show_error_message( "You must specify a dataset to import. You can %s." % referer_message, use_panels=True )
-
+
# Do import.
cur_history = trans.get_history( create=True )
status, message = self._copy_datasets( trans, [ dataset_id ], [ cur_history ], imported=True )
message = "Dataset imported. <br>You can <a href='%s'>start using the dataset</a> or %s." % ( url_for('/'), referer_message )
return trans.show_message( message, type=status, use_panels=True )
-
+
@web.expose
@web.json
@web.require_login( "use Galaxy datasets" )
@@ -685,7 +553,7 @@
dataset = self.get_dataset( trans, id, False, True )
return_dict = { "name" : dataset.name, "link" : url_for( action="display_by_username_and_slug", username=dataset.history.user.username, slug=trans.security.encode_id( dataset.id ) ) }
return return_dict
-
+
@web.expose
def get_embed_html_async( self, trans, id ):
""" Returns HTML for embedding a dataset in a page. """
@@ -698,7 +566,7 @@
def set_accessible_async( self, trans, id=None, accessible=False ):
""" Does nothing because datasets do not have an importable/accessible attribute. This method could potentially set another attribute. """
return
-
+
@web.expose
@web.require_login( "rate items" )
@web.json
@@ -713,7 +581,7 @@
dataset_rating = self.rate_item( rate_item, trans.get_user(), dataset, rating )
return self.get_ave_item_rating_data( trans.sa_session, dataset )
-
+
@web.expose
def display_by_username_and_slug( self, trans, username, slug, filename=None, preview=True ):
""" Display dataset by username and slug; because datasets do not yet have slugs, the slug is the dataset's id. """
@@ -722,10 +590,10 @@
# Filename used for composite types.
if filename:
return self.display( trans, dataset_id=slug, filename=filename)
-
+
truncated, dataset_data = self.get_data( dataset, preview )
dataset.annotation = self.get_item_annotation_str( trans.sa_session, dataset.history.user, dataset )
-
+
# If data is binary or an image, stream without template; otherwise, use display template.
# TODO: figure out a way to display images in display template.
if isinstance(dataset.datatype, datatypes.binary.Binary) or isinstance(dataset.datatype, datatypes.images.Image) or isinstance(dataset.datatype, datatypes.images.Html):
@@ -741,12 +609,12 @@
else:
user_item_rating = 0
ave_item_rating, num_ratings = self.get_ave_item_rating_data( trans.sa_session, dataset )
-
+
return trans.fill_template_mako( "/dataset/display.mako", item=dataset, item_data=dataset_data, truncated=truncated,
user_item_rating = user_item_rating, ave_item_rating=ave_item_rating, num_ratings=num_ratings )
else:
raise web.httpexceptions.HTTPNotFound()
-
+
@web.expose
def get_item_content_async( self, trans, id ):
""" Returns item content in HTML format. """
@@ -758,7 +626,7 @@
# Get annotation.
dataset.annotation = self.get_item_annotation_str( trans.sa_session, trans.user, dataset )
return trans.stream_template_mako( "/dataset/item_content.mako", item=dataset, item_data=dataset_data, truncated=truncated )
-
+
@web.expose
def annotate_async( self, trans, id, new_annotation=None, **kwargs ):
dataset = self.get_dataset( trans, id, False, True )
@@ -770,7 +638,7 @@
self.add_item_annotation( trans.sa_session, trans.get_user(), dataset, new_annotation )
trans.sa_session.flush()
return new_annotation
-
+
@web.expose
def get_annotation_async( self, trans, id ):
dataset = self.get_dataset( trans, id, False, True )
@@ -841,7 +709,7 @@
if app_action in [ 'data', 'param' ]:
assert action_param, "An action param must be provided for a data or param action"
#data is used for things with filenames that could be passed off to a proxy
- #in case some display app wants all files to be in the same 'directory',
+ #in case some display app wants all files to be in the same 'directory',
#data can be forced to param, but not the other way (no filename for other direction)
#get param name from url param name
try:
@@ -960,7 +828,7 @@
trans.log_event( "Dataset id %s has been unhidden" % str(id) )
return True
return False
-
+
def _purge( self, trans, dataset_id ):
message = None
status = 'done'
@@ -1037,7 +905,7 @@
return "OK"
else:
raise Exception( message )
-
+
@web.expose
def unhide( self, trans, dataset_id, filename ):
if self._unhide( trans, dataset_id ):
@@ -1070,7 +938,7 @@
"""
Show the parameters used for an HDA
"""
-
+
def source_dataset_chain( dataset, lst ):
try:
cp_from_ldda = dataset.copied_from_library_dataset_dataset_association
@@ -1084,13 +952,13 @@
except:
pass
return lst
-
+
hda = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( trans.security.decode_id( dataset_id ) )
if not hda:
raise paste.httpexceptions.HTTPRequestRangeNotSatisfiable( "Invalid reference dataset id: %s." % str( dataset_id ) )
if not trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), hda.dataset ):
return trans.show_error_message( "You are not allowed to access this dataset" )
-
+
# Get the associated job, if any. If this hda was copied from another,
# we need to find the job that created the origial hda
params_objects = None
@@ -1102,7 +970,7 @@
job = None
for assoc in job_hda.creating_job_associations:
job = assoc.job
- break
+ break
if job:
# Get the tool object
try:
@@ -1113,10 +981,10 @@
params_objects = job.get_param_values( trans.app )
except:
pass
-
+
inherit_chain = source_dataset_chain(hda, [])
return trans.fill_template( "show_params.mako", inherit_chain=inherit_chain, history=trans.get_history(), hda=hda, tool=tool, params_objects=params_objects )
-
+
@web.expose
def copy_datasets( self, trans, source_history=None, source_dataset_ids="", target_history_id=None, target_history_ids="", new_history_name="", do_copy=False, **kwd ):
params = util.Params( kwd )
@@ -1175,7 +1043,7 @@
if history in target_histories:
refresh_frames = ['history']
trans.sa_session.flush()
- hist_names_str = ", ".join( ['<a href="%s" target="_top">%s</a>' %
+ hist_names_str = ", ".join( ['<a href="%s" target="_top">%s</a>' %
( url_for( controller="history", action="switch_to_history", \
hist_id=trans.security.encode_id( hist.id ) ), hist.name ) \
for hist in target_histories ] )
@@ -1186,7 +1054,7 @@
source_datasets = history.visible_datasets
target_histories = [history]
if user:
- target_histories = user.active_histories
+ target_histories = user.active_histories
return trans.fill_template( "/dataset/copy_view.mako",
source_history = history,
current_history = trans.get_history(),
@@ -1204,7 +1072,7 @@
""" Helper method for copying datasets. """
user = trans.get_user()
done_msg = error_msg = ""
-
+
invalid_datasets = 0
if not dataset_ids or not target_histories:
error_msg = "You must provide both source datasets and target histories."
@@ -1229,7 +1097,7 @@
done_msg = "%i dataset%s copied to %i histor%s." % \
( num_datasets_copied, iff( num_datasets_copied == 1, "", "s"), len( target_histories ), iff( len ( target_histories ) == 1, "y", "ies") )
trans.sa_session.refresh( history )
-
+
if error_msg != "":
status = ERROR
message = error_msg
diff -r 60061d1a369635facf858766c7a992272b806750 -r ff62ddc66b1a454e9b3ba11297c0bd8e2a74dc8d static/june_2007_style/base.less
--- a/static/june_2007_style/base.less
+++ b/static/june_2007_style/base.less
@@ -1700,5 +1700,22 @@
position: relative;
}
+// Dataset Display Styles
+
+#loading_indicator{
+ position:fixed;
+ right:10px;
+ top:10px;
+ height:32px;
+ width:32px;
+ background:url(largespinner.gif);
+}
+
+#content_table td{
+ text-align:right;
+ white-space:nowrap;
+ padding:2px 10px;
+}
+
@import "base_sprites";
diff -r 60061d1a369635facf858766c7a992272b806750 -r ff62ddc66b1a454e9b3ba11297c0bd8e2a74dc8d static/june_2007_style/blue/base.css
--- a/static/june_2007_style/blue/base.css
+++ b/static/june_2007_style/blue/base.css
@@ -723,6 +723,8 @@
div.toolSectionBody div.toolPanelLabel{padding-top:5px;padding-bottom:5px;margin-left:16px;margin-right:10px;display:list-item;list-style:none outside;}
div.toolTitleNoSection{padding-bottom:5px;font-weight:bold;}
#tool-search{padding-top:5px;padding-bottom:10px;position:relative;}
+#loading_indicator{position:fixed;right:10px;top:10px;height:32px;width:32px;background:url(largespinner.gif);}
+#content_table td{text-align:right;white-space:nowrap;padding:2px 10px;}
.icon-button.display{background:url(history-buttons.png) no-repeat 0px 0px;}
.icon-button.display:hover{background:url(history-buttons.png) no-repeat 0px -26px;}
.icon-button.display_disabled{background:url(history-buttons.png) no-repeat 0px -52px;}
diff -r 60061d1a369635facf858766c7a992272b806750 -r ff62ddc66b1a454e9b3ba11297c0bd8e2a74dc8d static/june_2007_style/blue/largespinner.gif
Binary file static/june_2007_style/blue/largespinner.gif has changed
diff -r 60061d1a369635facf858766c7a992272b806750 -r ff62ddc66b1a454e9b3ba11297c0bd8e2a74dc8d templates/dataset/tabular_chunked.mako
--- /dev/null
+++ b/templates/dataset/tabular_chunked.mako
@@ -0,0 +1,65 @@
+<%inherit file="/base.mako"/>
+
+
+<%def name="title()">Dataset Display</%def>
+
+<%def name="javascripts()">
+ ${parent.javascripts()}
+ <script type="text/javascript">
+ var DATASET_URL = "${h.url_for( controller='/dataset', action='display', dataset_id=trans.security.encode_id( dataset.id ))}";
+ var DATASET_COLS = ${dataset.metadata.columns};
+ var current_chunk = 0;
+
+ function fillTable(){
+ if (current_chunk !== -1){
+ var table = $('#content_table');
+ $.getJSON(DATASET_URL, {chunk: current_chunk}, function (result) {
+ if (result.ck_data !== ""){
+ var lines = result.ck_data.split('\n');
+ $.each(lines, function(){
+ var line = this;
+ var cells = line.split('\t');
+ /* Check length of cells to ensure this is a complete row. */
+ if (cells.length == DATASET_COLS){
+ table.append('<tr><td>' + cells.join('</td><td>') + '</td></tr>');
+ }
+ else{
+ table.append('<tr><td colspan="'+ DATASET_COLS+ '">' + line + '</td></tr>');
+ }
+ });
+ current_chunk = result.ck_index;
+ }
+ else {
+ current_chunk = -1;
+ }
+ });
+ }
+ }
+
+ $(document).ready(function(){
+ fillTable();
+ $(window).scroll(function(){
+ console.log($(window).scrollTop());
+ console.log($(document).height());
+ console.log($(window).height());
+ // if ($(window).scrollTop() == $(document).height() - $(window).height()){
+ if ($(document).height() - $(window).scrollTop() <= $(window).height()){
+ fillTable();
+ }
+ });
+ $('#loading_indicator').ajaxStart(function(){
+ $(this).show();
+ }).ajaxStop(function(){
+ $(this).hide();
+ });
+ });
+ </script>
+</%def>
+
+<%def name="stylesheets()">
+ ${parent.stylesheets()}
+</%def>
+
+<div id="loading_indicator" ></div>
+<table id="content_table" cellpadding="0">
+</table>
diff -r 60061d1a369635facf858766c7a992272b806750 -r ff62ddc66b1a454e9b3ba11297c0bd8e2a74dc8d templates/display_base.mako
--- a/templates/display_base.mako
+++ b/templates/display_base.mako
@@ -361,4 +361,4 @@
</div></div>
-</%def>
\ No newline at end of file
+</%def>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jgoecks: Move tools controller from UI controller to an API controller and add show method for tool.
by Bitbucket 11 Apr '12
by Bitbucket 11 Apr '12
11 Apr '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/60061d1a3696/
changeset: 60061d1a3696
user: jgoecks
date: 2012-04-11 17:37:08
summary: Move tools controller from UI controller to an API controller and add show method for tool.
affected #: 3 files
diff -r 423f4f2910ac90098e799d354a2936513242a21e -r 60061d1a369635facf858766c7a992272b806750 lib/galaxy/web/api/tools.py
--- /dev/null
+++ b/lib/galaxy/web/api/tools.py
@@ -0,0 +1,32 @@
+from galaxy import config, tools, web, util
+from galaxy.web.base.controller import BaseController, BaseAPIController
+
+class ToolsController( BaseAPIController ):
+ """
+ RESTful controller for interactions with tools.
+ """
+
+ @web.json
+ def index( self, trans, **kwds ):
+ """
+ GET /api/tools: returns a list of tools defined by parameters
+ parameters:
+ in_panel - if true, tools are returned in panel structure, including sections and labels
+ trackster - if true, only tools that are compatible with Trackster are returned
+ """
+
+ # Read params.
+ in_panel = util.string_as_bool( kwds.get( 'in_panel', 'True' ) )
+ trackster = util.string_as_bool( kwds.get( 'trackster', 'False' ) )
+
+ # Create return value.
+ return self.app.toolbox.to_dict( trans, in_panel=in_panel, trackster=trackster )
+
+ @web.expose_api
+ def show( self, trans, id, **kwd ):
+ """
+ GET /api/tools/{tool_id}
+ Returns tool information, including parameters and inputs.
+ """
+ return self.app.toolbox.tools_by_id[ id ].to_dict( trans, all=True )
+
\ No newline at end of file
diff -r 423f4f2910ac90098e799d354a2936513242a21e -r 60061d1a369635facf858766c7a992272b806750 lib/galaxy/web/buildapp.py
--- a/lib/galaxy/web/buildapp.py
+++ b/lib/galaxy/web/buildapp.py
@@ -129,6 +129,7 @@
webapp.api_mapper.resource( 'request_type', 'request_types', path_prefix='/api' )
webapp.api_mapper.resource( 'role', 'roles', path_prefix='/api' )
webapp.api_mapper.resource_with_deleted( 'quota', 'quotas', path_prefix='/api' )
+ webapp.api_mapper.resource( 'tool', 'tools', path_prefix='/api' )
webapp.api_mapper.resource_with_deleted( 'user', 'users', path_prefix='/api' )
webapp.api_mapper.resource( 'workflow', 'workflows', path_prefix='/api' )
webapp.api_mapper.resource_with_deleted( 'history', 'histories', path_prefix='/api' )
diff -r 423f4f2910ac90098e799d354a2936513242a21e -r 60061d1a369635facf858766c7a992272b806750 lib/galaxy/web/controllers/tools.py
--- a/lib/galaxy/web/controllers/tools.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from galaxy import config, tools, web, util
-from galaxy.web.base.controller import BaseController, BaseUIController
-
-class ToolsController( BaseUIController ):
- """
- RESTful controller for interactions with tools. Once session-based
- authentication can be done with API controllers, this will be moved
- to be part of the API.
- """
-
- @web.json
- def index( self, trans, **kwds ):
- """
- GET /api/tools: returns a list of tools defined by parameters
- parameters:
- in_panel - if true, tools are returned in panel structure, including sections and labels
- trackster - if true, only tools that are compatible with Trackster are returned
- """
-
- # Read params.
- in_panel = util.string_as_bool( kwds.get( 'in_panel', 'True' ) )
- trackster = util.string_as_bool( kwds.get( 'trackster', 'False' ) )
-
- # Create return value.
- return self.app.toolbox.to_dict( trans, in_panel=in_panel, trackster=trackster )
-
\ No newline at end of file
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0