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
September 2010
- 1 participants
- 70 discussions
galaxy-dist commit 26a0b620490d: Quick fix to hide outputs until they're nicer.
by commits-noreply@bitbucket.org 08 Sep '10
by commits-noreply@bitbucket.org 08 Sep '10
08 Sep '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Dannon Baker <dannonbaker(a)me.com>
# Date 1282572262 14400
# Node ID 26a0b620490dd8698deb907ecaa540e7fa19a6ee
# Parent d9e099daa8279880d5e054680ab28e8fc3064f77
Quick fix to hide outputs until they're nicer.
--- a/templates/workflow/list.mako
+++ b/templates/workflow/list.mako
@@ -58,7 +58,6 @@
<td><div popupmenu="wf-${i}-popup"><a class="action-button" href="${h.url_for( action='editor', id=trans.security.encode_id(workflow.id) )}" target="_parent">Edit</a>
- <a class="action-button" href="${h.url_for( action='tag_outputs', id=trans.security.encode_id(workflow.id) )}">Tag Outputs</a><a class="action-button" href="${h.url_for( controller='root', action='index', workflow_id=trans.security.encode_id(workflow.id) )}" target="_parent">Run</a><a class="action-button" href="${h.url_for( action='sharing', id=trans.security.encode_id(workflow.id) )}">Share or Publish</a><a class="action-button" href="${h.url_for( action='clone', id=trans.security.encode_id(workflow.id) )}">Clone</a>
--- a/templates/workflow/editor.mako
+++ b/templates/workflow/editor.mako
@@ -132,7 +132,7 @@
make_popupmenu( $("#workflow-options-button"), {
##"Create New" : create_new_workflow_dialog,
"Edit Attributes" : edit_workflow_attributes,
- "Edit Workflow Outputs": edit_workflow_outputs,
+ ##"Edit Workflow Outputs": edit_workflow_outputs,
"Layout": layout_editor,
"Save" : save_current_workflow,
##"Load a Workflow" : load_workflow,
@@ -399,7 +399,7 @@
}
function show_form_for_tool( text, node ) {
- $("#edit-attributes").hide();
+ $('.right-content').hide();
$("#right-content").show().html( text );
// Add metadata form to tool.
if (node) {
--- a/templates/workflow/tag_outputs.mako
+++ /dev/null
@@ -1,161 +0,0 @@
-<%inherit file="/base.mako"/>
-
-<%def name="javascripts()">
- ${parent.javascripts()}
- ${h.js( "jquery.autocomplete" )}
- <script type="text/javascript">
- $( function() {
- $( "select[refresh_on_change='true']").change( function() {
- $( "#tool_form" ).submit();
- });
- });
- </script>
-</%def>
-
-<%def name="stylesheets()">
- ${parent.stylesheets()}
- ${h.css( "autocomplete_tagging" )}
- <style type="text/css">
- div.toolForm{
- margin-top: 10px;
- margin-bottom: 10px;
- }
- </style>
-</%def>
-
-<%
-from galaxy.tools.parameters import DataToolParameter, RuntimeValue
-from galaxy.jobs.actions.post import ActionBox
-%>
-
-<%def name="do_inputs( inputs, values, errors, prefix, step, other_values = None )">
- %if other_values is None:
- <% other_values = values %>
- %endif
- %for input_index, input in enumerate( inputs.itervalues() ):
- %if input.type == "repeat":
- <div class="repeat-group">
- <div class="form-title-row"><b>${input.title_plural}</b></div>
- <% repeat_values = values[input.name] %>
- %for i in range( len( repeat_values ) ):
- %if input.name in errors:
- <% rep_errors = errors[input.name][i] %>
- %else:
- <% rep_errors = dict() %>
- %endif
- <div class="repeat-group-item">
- <% index = repeat_values[i]['__index__'] %>
- <div class="form-title-row"><b>${input.title} ${i + 1}</b></div>
- ${do_inputs( input.inputs, repeat_values[ i ], rep_errors, prefix + input.name + "_" + str(index) + "|", step, other_values )}
- ## <div class="form-row"><input type="submit" name="${step.id}|${prefix}${input.name}_${i}_remove" value="Remove ${input.title} ${i+1}" /></div>
- </div>
- %endfor
- ## <div class="form-row"><input type="submit" name="${step.id}|${prefix}${input.name}_add" value="Add new ${input.title}" /></div>
- </div>
- %elif input.type == "conditional":
- <% group_values = values[input.name] %>
- <% current_case = group_values['__current_case__'] %>
- <% new_prefix = prefix + input.name + "|" %>
- <% group_errors = errors.get( input.name, {} ) %>
- ${row_for_param( input.test_param, group_values[ input.test_param.name ], other_values, group_errors, prefix, step )}
- ${do_inputs( input.cases[ current_case ].inputs, group_values, group_errors, new_prefix, step, other_values )}
- %else:
- ${row_for_param( input, values[ input.name ], other_values, errors, prefix, step )}
- %endif
- %endfor
-</%def>
-
-<%def name="row_for_param( param, value, other_values, error_dict, prefix, step )">
- ## -- ${param.name} -- ${step.state.inputs} --
- %if error_dict.has_key( param.name ):
- <% cls = "form-row form-row-error" %>
- %else:
- <% cls = "form-row" %>
- %endif
- <div class="${cls}">
- <label>${param.get_label()}</label>
- <div>
- %if isinstance( param, DataToolParameter ):
- %if ( prefix + param.name ) in step.input_connections_by_name:
- <%
- conn = step.input_connections_by_name[ prefix + param.name ]
- %>
- Output dataset '${conn.output_name}' from step ${int(conn.output_step.order_index)+1}
- %else:
- ## FIXME: Initialize in the controller
- <%
- if value is None:
- value = other_values[ param.name ] = param.get_initial_value( t, other_values )
- %>
- ${param.get_html_field( t, value, other_values ).get_html( str(step.id) + "|" + prefix )}
- <input type="hidden" name="${step.id}|__force_update__${prefix}${param.name}" value="true" />
- %endif
- %elif isinstance( value, RuntimeValue ) or ( str(step.id) + '|__runtime__' + prefix + param.name ) in incoming:
- ## On the first load we may see a RuntimeValue, so we write
- ## an input field using the initial value for the param.
- ## Subsequents posts will no longer have the runtime value
- ## (since an actualy value will be posted) so we add a hidden
- ## field so we know to continue drawing form for this param.
- ## FIXME: This logic shouldn't be in the template. The
- ## controller should go through the inputs on the first
- ## load, fill in initial values where needed, and mark
- ## all that are runtime modifiable in some way.
- <% value = other_values[ param.name ] = param.get_initial_value( t, other_values ) %>
- ${param.get_html_field( t, value, other_values ).get_html( str(step.id) + "|" + prefix )}
- <input type="hidden" name="${step.id}|__runtime__${prefix}${param.name}" value="true" />
- %else:
- ${param.value_to_display_text( value, app )}
- %endif
- </div>
- %if step.upgrade_messages and param.name in step.upgrade_messages:
- <div class="warningmark">${step.upgrade_messages[param.name]}</div>
- %endif
- %if error_dict.has_key( param.name ):
- <div style="color: red; font-weight: bold; padding-top: 1px; padding-bottom: 3px;">
- <div style="width: 300px;"><img style="vertical-align: middle;" src="${h.url_for('/static/style/error_small.png')}"> <span style="vertical-align: middle;">${error_dict[param.name]}</span></div>
- </div>
- %endif
- <div style="clear: both"></div>
- </div>
-</%def>
-
-<h2>Set outputs for workflow "${workflow.name}"</h2>
-<p>Select the checkboxes for step outputs you would like to mark as whole-workflow outputs.</p>
-%if has_upgrade_messages:
-<div class="warningmessage">
- Problems were encourered when loading this workflow, likely due to tool
- version changes. Missing parameter values have been replaced with default.
- Please review the parameter values below.
-</div>
-%endif
-
-<form id="tool_form" name="tool_form" method="POST">
-## <input type="hidden" name="workflow_name" value="${workflow.name | h}" />
-%for i, step in enumerate( steps ):
- %if step.type == 'tool':
- <% tool = app.toolbox.tools_by_id[step.tool_id] %>
- <input type="hidden" name="${step.id}|tool_state" value="${step.state.encode( tool, app )}">
- <div class="toolForm">
- <div class="toolFormTitle">Step ${int(step.order_index)+1}: ${tool.name}</div>
- <div class="toolFormBody">
- % for output in tool.outputs:
- <div class='form-row'>
- %if step.workflow_outputs and output in [wf_output.output_name for wf_output in step.workflow_outputs]:
- <p>${output} <input type="checkbox" name="${step.id}|otag|${output}" checked /></p>
- %else:
- <p>${output} <input type="checkbox" name="${step.id}|otag|${output}"/></p>
- %endif
- </div>
- % endfor
- % if step.annotations:
- <hr/>
- <div class='form-row'>
- <label>Annotation:</label> ${step.annotations[0].annotation}
- </div>
- % endif
- </div>
- </div>
- %endif
-%endfor
-<input type="submit" name="save_outputs" value="Save output settings" />
-</form>
1
0
galaxy-dist commit 31fe9ca3a088: Zero out optional metadata when file size exceeds max_optional_metadata_filesize cut off. Fixes a bug where an output which has metadata copied to it from an input would erroneously retain the input's value.
by commits-noreply@bitbucket.org 08 Sep '10
by commits-noreply@bitbucket.org 08 Sep '10
08 Sep '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Dan Blankenberg <dan(a)bx.psu.edu>
# Date 1282330290 14400
# Node ID 31fe9ca3a08849ac0160e7e25033487030babec0
# Parent 4464d55104b8a33407bf03d822612afd4a679eb0
Zero out optional metadata when file size exceeds max_optional_metadata_filesize cut off. Fixes a bug where an output which has metadata copied to it from an input would erroneously retain the input's value.
--- a/lib/galaxy/datatypes/sequence.py
+++ b/lib/galaxy/datatypes/sequence.py
@@ -151,6 +151,8 @@ class csFasta( Sequence ):
def set_meta( self, dataset, **kwd ):
if self.max_optional_metadata_filesize >= 0 and dataset.get_size() > self.max_optional_metadata_filesize:
+ dataset.metadata.data_lines = None
+ dataset.metadata.sequences = None
return
return Sequence.set_meta( self, dataset, **kwd )
@@ -164,6 +166,8 @@ class Fastq ( Sequence ):
in dataset.
"""
if self.max_optional_metadata_filesize >= 0 and dataset.get_size() > self.max_optional_metadata_filesize:
+ dataset.metadata.data_lines = None
+ dataset.metadata.sequences = None
return
data_lines = 0
sequences = 0
--- a/lib/galaxy/datatypes/qualityscore.py
+++ b/lib/galaxy/datatypes/qualityscore.py
@@ -66,6 +66,7 @@ class QualityScoreSOLiD ( QualityScore )
def set_meta( self, dataset, **kwd ):
if self.max_optional_metadata_filesize >= 0 and dataset.get_size() > self.max_optional_metadata_filesize:
+ dataset.metadata.data_lines = None
return
return QualityScore.set_meta( self, dataset, **kwd )
1
0
galaxy-dist commit 6358247a4559: Job running: When finishing jobs, don't flush until all datasets have finished processing. Otherwise, the terminal job state is set once the first dataset is processed, and if the runner restarts, remaining datasets will not be processed.
by commits-noreply@bitbucket.org 08 Sep '10
by commits-noreply@bitbucket.org 08 Sep '10
08 Sep '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Nate Coraor <nate(a)bx.psu.edu>
# Date 1282333327 14400
# Node ID 6358247a4559c9ec757484e16c618a831711fbc9
# Parent 8242280e5c74d1fb60daa12f2ddb37cc06bc7e75
Job running: When finishing jobs, don't flush until all datasets have finished processing. Otherwise, the terminal job state is set once the first dataset is processed, and if the runner restarts, remaining datasets will not be processed.
--- a/lib/galaxy/jobs/__init__.py
+++ b/lib/galaxy/jobs/__init__.py
@@ -523,7 +523,6 @@ class JobWrapper( object ):
if dataset.ext == 'auto':
dataset.extension = 'txt'
self.sa_session.add( dataset )
- self.sa_session.flush()
if context['stderr']:
dataset_assoc.dataset.dataset.state = model.Dataset.states.ERROR
else:
@@ -535,6 +534,10 @@ class JobWrapper( object ):
# panel stops checking for updates. So allow the
# self.sa_session.flush() at the bottom of this method set
# the state instead.
+
+ # Flush all the dataset and job changes above. Dataset state changes
+ # will now be seen by the user.
+ self.sa_session.flush()
# Save stdout and stderr
if len( stdout ) > 32768:
1
0
galaxy-dist commit 4464d55104b8: Updated column join to handle situation when last column is a join column and a row is missing that column
by commits-noreply@bitbucket.org 08 Sep '10
by commits-noreply@bitbucket.org 08 Sep '10
08 Sep '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Kelly Vincent <kpvincent(a)bx.psu.edu>
# Date 1282329639 14400
# Node ID 4464d55104b8a33407bf03d822612afd4a679eb0
# Parent d9e099daa8279880d5e054680ab28e8fc3064f77
Updated column join to handle situation when last column is a join column and a row is missing that column
--- a/tools/new_operations/column_join.py
+++ b/tools/new_operations/column_join.py
@@ -208,7 +208,8 @@ def __main__():
hinges = [ h for h in hinges if h ]
current, loc = hinges[0], hinge_dict[ hinges[0] ]
# first output empty columns for vertical alignment (account for "missing" files)
- # write output if trailing empty columns
+ # write output for leading and trailing empty columns
+ # columns missing from actual file handled further below
current_data = []
if current != old_current:
# fill trailing empty columns with appropriate fill value
@@ -244,17 +245,25 @@ def __main__():
split_line.append( item )
else:
split_line.append( fill_empty[ i + 1 ] )
+ # add actual data to be output below
if ''.join( split_line ):
- # add actual data to be output below
for col in cols:
if col > hinge:
- current_data.append( split_line[ col - 1 ] )
+ # if this column doesn't exist, add the appropriate filler or empty column
+ try:
+ new_item = split_line[ col - 1 ]
+ except IndexError:
+ if fill_empty:
+ new_item = fill_empty[ col ]
+ else:
+ new_item = ''
+ current_data.append( new_item )
# grab next line for selected file
current_lines[ loc ] = tmp_input_files[ loc ].readline().rstrip( '\r\n' )
# write relevant data to file
- if current == old_current:
+ if current == old_current and current_data:
fout.write( '%s%s' % ( delimiter, delimiter.join( current_data ) ) )
- else:
+ elif current_data:
fout.write( '%s%s%s' % ( current, delimiter, delimiter.join( current_data ) ) )
last_loc = loc
old_current = current
--- a/tools/new_operations/column_join.xml
+++ b/tools/new_operations/column_join.xml
@@ -116,17 +116,29 @@ import simplejson
<param name="input" value="column_join_in12.pileup" ftype="pileup" /><output name="output" file="column_join_out4.pileup" ftype="tabular" /></test>
- </tests>
+ <test>
+ <!-- Test for handling missing column -->
+ <param name="input1" value="column_join_in13.tabular" ftype="tabular" />
+ <param name="hinge" value="1" />
+ <param name="columns" value="5" />
+ <param name="fill_empty_columns_switch" value="fill_empty" />
+ <param name="column_fill_type" value="single_fill_value" />
+ <param name="fill_value" value="0" />
+ <param name="input2" value="column_join_in14.tabular" ftype="tabular" />
+ <param name="input" value="column_join_in15.tabular" ftype="tabular" />
+ <output name="output" file="column_join_out5.tabular" ftype="tabular" />
+ </test>
+ </tests><help>
**What it does**
This tool allows you to join several files with the same column structure into one file, removing certain columns if necessary. The user needs to select a 'hinge', which is the number of left-most columns to match on. They also need to select the columns to include in the join, which should include the hinge columns, too.
-Note that the files are expected to have the same number of columns.
+Note that the files are expected to have the same number of columns. If for some reason the join column is missing (this only applies to the last column(s)), the tool attempts to handle this situation by inserting an empty item (or the appropriate filler) for that column on that row. This could lead to the situation where a row has a hinge but entirely empty or filled columns, if the hinge exists in at least one file but every file that has it is missing the join column. Also, note that the tool does not distinguish between a file missing the hinge altogether and a file having the hinge but missing the column (in both cases the column would be empty or filled). There is an example of this below.
-----
-**Example**
+**General Example**
Given the following files::
@@ -213,6 +225,36 @@ To join on columns 3 and 4 combining on
chr2 83 T 8
chr2 84 A 9
+**Example with missing columns**
+
+Given the following input files::
+
+ FILE 1
+ 1 A
+ 2 B b
+ 4 C c
+ 5 D
+ 6 E e
+
+ FILE 2
+ 1 M m
+ 2 N
+ 3 O o
+ 4 P p
+ 5 Q
+ 7 R r
+
+if we join only column 3 using column 1 as the hinge and with a fill value of '0', this is what will be output::
+
+ 1 0 m
+ 2 b 0
+ 3 0 o
+ 4 c p
+ 5 0 0
+ 6 e 0
+ 7 0 r
+
+Row 5 appears in both files with the missing column, so it's got nothing but fill values in the output file.
</help></tool>
1
0
galaxy-dist commit 8a3d3fba0370: Issue # 352: Set content type of HistoryController.list_as_xml to be text/xml
by commits-noreply@bitbucket.org 08 Sep '10
by commits-noreply@bitbucket.org 08 Sep '10
08 Sep '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Greg Von Kuster <greg(a)bx.psu.edu>
# Date 1282334161 14400
# Node ID 8a3d3fba037061a818b4417978542ae7b71f2e1a
# Parent 6358247a4559c9ec757484e16c618a831711fbc9
Issue # 352: Set content type of HistoryController.list_as_xml to be text/xml
Issue # 353: Add additional history attributes to the <history> tag in the ~/templates/root/history_as_xml.mako template
--- a/templates/root/history_as_xml.mako
+++ b/templates/root/history_as_xml.mako
@@ -1,5 +1,5 @@
<?xml version="1.0"?>
-<history>
+<history id="${trans.security.encode_id( history.id )}" num="${len(history.datasets)}" name="${history.name}" create="${history.create_time}" update="${history.update_time}">
%if show_deleted:
%for data in history.activatable_datasets:
<data id="${data.id}" hid="${data.hid}" name="${data.name}" state="${data.state}" dbkey="${data.dbkey}">
--- a/lib/galaxy/web/controllers/history.py
+++ b/lib/galaxy/web/controllers/history.py
@@ -155,6 +155,7 @@ class HistoryController( BaseController,
@web.expose
def list_as_xml( self, trans ):
"""XML history list for functional tests"""
+ trans.response.set_content_type( 'text/xml' )
return trans.fill_template( "/history/list_as_xml.mako" )
stored_list_grid = HistoryListGrid()
1
0
galaxy-dist commit 8242280e5c74: Use image_path for workflows and show_modal instead of relative paths
by commits-noreply@bitbucket.org 08 Sep '10
by commits-noreply@bitbucket.org 08 Sep '10
08 Sep '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Kanwei Li <kanwei(a)gmail.com>
# Date 1282330852 14400
# Node ID 8242280e5c74d1fb60daa12f2ddb37cc06bc7e75
# Parent 31fe9ca3a08849ac0160e7e25033487030babec0
Use image_path for workflows and show_modal instead of relative paths
--- a/static/scripts/packed/galaxy.panels.js
+++ b/static/scripts/packed/galaxy.panels.js
@@ -1,1 +1,1 @@
-function ensure_dd_helper(){if($("#DD-helper").length==0){$("<div id='DD-helper'/>").css({background:"white",opacity:0,zIndex:9000,position:"absolute",top:0,left:0,width:"100%",height:"100%"}).appendTo("body").hide()}}function make_left_panel(h,c,e){var g=false;var f=null;var d=function(i){var j=i;if(i<0){i=0}$(h).css("width",i);$(e).css("left",j);$(c).css("left",i+7);if(document.recalc){document.recalc()}};var a=function(){if(g){$(e).removeClass("hover");$(e).animate({left:f},"fast");$(h).css("left",-f).show().animate({left:0},"fast",function(){d(f);$(e).removeClass("hidden")});g=false}else{f=$(e).position().left;$(c).css("left",$(e).innerWidth());if(document.recalc){document.recalc()}$(e).removeClass("hover");$(h).animate({left:-f},"fast");$(e).animate({left:-1},"fast",function(){$(this).addClass("hidden")});g=true}};$(e).hover(function(){$(this).addClass("hover")},function(){$(this).removeClass("hover")}).bind("dragstart",function(i){$("#DD-helper").show()}).bind("dragend
",function(i){$("#DD-helper").hide()}).bind("drag",function(i){x=i.offsetX;x=Math.min(400,Math.max(100,x));if(g){$(h).css("left",0);$(e).removeClass("hidden");g=false}d(x)}).bind("dragclickonly",function(i){a()}).find("div").show();var b=function(i){if((g&&i=="show")||(!g&&i=="hide")){a()}};return{force_panel:b}}function make_right_panel(a,e,h){var j=false;var g=false;var c=null;var d=function(k){$(a).css("width",k);$(e).css("right",k+9);$(h).css("right",k).css("left","");if(document.recalc){document.recalc()}};var i=function(){if(j){$(h).removeClass("hover");$(h).animate({right:c},"fast");$(a).css("right",-c).show().animate({right:0},"fast",function(){d(c);$(h).removeClass("hidden")});j=false}else{c=$(document).width()-$(h).position().left-$(h).outerWidth();$(e).css("right",$(h).innerWidth()+1);if(document.recalc){document.recalc()}$(h).removeClass("hover");$(a).animate({right:-c},"fast");$(h).animate({right:-1},"fast",function(){$(this).addClass("hidden")});j=true}g=false}
;var b=function(k){var l=$(e).width()-(j?c:0);if(l<k){if(!j){i();g=true}}else{if(g){i();g=false}}};$(h).hover(function(){$(this).addClass("hover")},function(){$(this).removeClass("hover")}).bind("dragstart",function(k){$("#DD-helper").show()}).bind("dragend",function(k){$("#DD-helper").hide()}).bind("drag",function(k){x=k.offsetX;w=$(window).width();x=Math.min(w-100,x);x=Math.max(w-400,x);if(j){$(a).css("right",0);$(h).removeClass("hidden");j=false}d(w-x-$(this).outerWidth())}).bind("dragclickonly",function(k){i()}).find("div").show();var f=function(k){if((j&&k=="show")||(!j&&k=="hide")){i()}};return{handle_minwidth_hint:b,force_panel:f}}function hide_modal(){$(".dialog-box-container").fadeOut(function(){$("#overlay").hide();$(".dialog-box").find(".body").children().remove()})}function show_modal(g,c,e,d,f){if(g){$(".dialog-box").find(".title").html(g);$(".dialog-box").find(".unified-panel-header").show()}else{$(".dialog-box").find(".unified-panel-header").hide()}var a=$(".d
ialog-box").find(".buttons").html("");if(e){$.each(e,function(b,h){a.append($("<button/>").text(b).click(h));a.append(" ")});a.show()}else{a.hide()}var a=$(".dialog-box").find(".extra_buttons").html("");if(d){$.each(d,function(b,h){a.append($("<button/>").text(b).click(h));a.append(" ")});a.show()}else{a.hide()}if(c=="progress"){c=$("<img src='../images/yui/rel_interstitial_loading.gif')' />")}$(".dialog-box").find(".body").html(c);if(!$(".dialog-box-container").is(":visible")){$("#overlay").show();$(".dialog-box-container").fadeIn()}if(f){f()}}function show_in_overlay(c){var d=c.width||"600";var b=c.height||"400";var a=c.scroll||"auto";$("#overlay-background").bind("click.overlay",function(){hide_modal();$("#overlay-background").unbind("click.overlay")});show_modal(null,$("<div style='margin: -5px;'><img id='close_button' style='position:absolute;right:-17px;top:-15px;' src='../images/closebox.png'><iframe style='margin: 0; padding: 0;' src='"+c.url+"' width='"+d+"' height=
'"+b+"' scrolling='"+a+"' frameborder='0'></iframe></div>"));$("#close_button").bind("click",function(){hide_modal()})}$(function(){$(".tab").each(function(){var a=$(this).children(".submenu");if(a.length>0){if($.browser.msie){a.prepend("<iframe style=\"position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: -1; filter:Alpha(Opacity='0');\"></iframe>")}$(this).hover(function(){a.show()},function(){a.hide()});a.click(function(){a.hide()})}})});function user_changed(a,b){if(a){$(".loggedin-only").show();$(".loggedout-only").hide();$("#user-email").text(a);if(b){$(".admin-only").show()}}else{$(".loggedin-only").hide();$(".loggedout-only").show();$(".admin-only").hide()}};
+function ensure_dd_helper(){if($("#DD-helper").length==0){$("<div id='DD-helper'/>").css({background:"white",opacity:0,zIndex:9000,position:"absolute",top:0,left:0,width:"100%",height:"100%"}).appendTo("body").hide()}}function make_left_panel(h,c,e){var g=false;var f=null;var d=function(i){var j=i;if(i<0){i=0}$(h).css("width",i);$(e).css("left",j);$(c).css("left",i+7);if(document.recalc){document.recalc()}};var a=function(){if(g){$(e).removeClass("hover");$(e).animate({left:f},"fast");$(h).css("left",-f).show().animate({left:0},"fast",function(){d(f);$(e).removeClass("hidden")});g=false}else{f=$(e).position().left;$(c).css("left",$(e).innerWidth());if(document.recalc){document.recalc()}$(e).removeClass("hover");$(h).animate({left:-f},"fast");$(e).animate({left:-1},"fast",function(){$(this).addClass("hidden")});g=true}};$(e).hover(function(){$(this).addClass("hover")},function(){$(this).removeClass("hover")}).bind("dragstart",function(i){$("#DD-helper").show()}).bind("dragend
",function(i){$("#DD-helper").hide()}).bind("drag",function(i){x=i.offsetX;x=Math.min(400,Math.max(100,x));if(g){$(h).css("left",0);$(e).removeClass("hidden");g=false}d(x)}).bind("dragclickonly",function(i){a()}).find("div").show();var b=function(i){if((g&&i=="show")||(!g&&i=="hide")){a()}};return{force_panel:b}}function make_right_panel(a,e,h){var j=false;var g=false;var c=null;var d=function(k){$(a).css("width",k);$(e).css("right",k+9);$(h).css("right",k).css("left","");if(document.recalc){document.recalc()}};var i=function(){if(j){$(h).removeClass("hover");$(h).animate({right:c},"fast");$(a).css("right",-c).show().animate({right:0},"fast",function(){d(c);$(h).removeClass("hidden")});j=false}else{c=$(document).width()-$(h).position().left-$(h).outerWidth();$(e).css("right",$(h).innerWidth()+1);if(document.recalc){document.recalc()}$(h).removeClass("hover");$(a).animate({right:-c},"fast");$(h).animate({right:-1},"fast",function(){$(this).addClass("hidden")});j=true}g=false}
;var b=function(k){var l=$(e).width()-(j?c:0);if(l<k){if(!j){i();g=true}}else{if(g){i();g=false}}};$(h).hover(function(){$(this).addClass("hover")},function(){$(this).removeClass("hover")}).bind("dragstart",function(k){$("#DD-helper").show()}).bind("dragend",function(k){$("#DD-helper").hide()}).bind("drag",function(k){x=k.offsetX;w=$(window).width();x=Math.min(w-100,x);x=Math.max(w-400,x);if(j){$(a).css("right",0);$(h).removeClass("hidden");j=false}d(w-x-$(this).outerWidth())}).bind("dragclickonly",function(k){i()}).find("div").show();var f=function(k){if((j&&k=="show")||(!j&&k=="hide")){i()}};return{handle_minwidth_hint:b,force_panel:f}}function hide_modal(){$(".dialog-box-container").fadeOut(function(){$("#overlay").hide();$(".dialog-box").find(".body").children().remove()})}function show_modal(g,c,e,d,f){if(g){$(".dialog-box").find(".title").html(g);$(".dialog-box").find(".unified-panel-header").show()}else{$(".dialog-box").find(".unified-panel-header").hide()}var a=$(".d
ialog-box").find(".buttons").html("");if(e){$.each(e,function(b,h){a.append($("<button/>").text(b).click(h));a.append(" ")});a.show()}else{a.hide()}var a=$(".dialog-box").find(".extra_buttons").html("");if(d){$.each(d,function(b,h){a.append($("<button/>").text(b).click(h));a.append(" ")});a.show()}else{a.hide()}if(c=="progress"){c=$("<img/>").attr("src",image_path+"/yui/rel_interstitial_loading.gif")}$(".dialog-box").find(".body").html(c);if(!$(".dialog-box-container").is(":visible")){$("#overlay").show();$(".dialog-box-container").fadeIn()}if(f){f()}}function show_in_overlay(c){var d=c.width||"600";var b=c.height||"400";var a=c.scroll||"auto";$("#overlay-background").bind("click.overlay",function(){hide_modal();$("#overlay-background").unbind("click.overlay")});show_modal(null,$("<div style='margin: -5px;'><img id='close_button' style='position:absolute;right:-17px;top:-15px;' src='../images/closebox.png'><iframe style='margin: 0; padding: 0;' src='"+c.url+"' width='"+d+"'
height='"+b+"' scrolling='"+a+"' frameborder='0'></iframe></div>"));$("#close_button").bind("click",function(){hide_modal()})}$(function(){$(".tab").each(function(){var a=$(this).children(".submenu");if(a.length>0){if($.browser.msie){a.prepend("<iframe style=\"position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: -1; filter:Alpha(Opacity='0');\"></iframe>")}$(this).hover(function(){a.show()},function(){a.hide()});a.click(function(){a.hide()})}})});function user_changed(a,b){if(a){$(".loggedin-only").show();$(".loggedout-only").hide();$("#user-email").text(a);if(b){$(".admin-only").show()}}else{$(".loggedin-only").hide();$(".loggedout-only").show();$(".admin-only").hide()}};
--- a/static/scripts/packed/galaxy.workflow_editor.canvas.js
+++ b/static/scripts/packed/galaxy.workflow_editor.canvas.js
@@ -1,1 +1,1 @@
-function Terminal(a){this.element=a;this.connectors=[]}$.extend(Terminal.prototype,{connect:function(a){this.connectors.push(a);if(this.node){this.node.changed()}},disconnect:function(a){this.connectors.splice($.inArray(a,this.connectors),1);if(this.node){this.node.changed()}},redraw:function(){$.each(this.connectors,function(a,b){b.redraw()})},destroy:function(){$.each(this.connectors.slice(),function(a,b){b.destroy()})}});function OutputTerminal(a,b){Terminal.call(this,a);this.datatypes=b}OutputTerminal.prototype=new Terminal();function InputTerminal(a,b){Terminal.call(this,a);this.datatypes=b}InputTerminal.prototype=new Terminal();$.extend(InputTerminal.prototype,{can_accept:function(a){if(this.connectors.length<1){for(var c in this.datatypes){for(var b in a.datatypes){if(a.datatypes[b]=="input"||issubtype(a.datatypes[b],this.datatypes[c])){return true}}}}return false}});function Connector(b,a){this.canvas=null;this.dragging=false;this.inner_color="#FFFFFF";this.outer_col
or="#D8B365";if(b&&a){this.connect(b,a)}}$.extend(Connector.prototype,{connect:function(b,a){this.handle1=b;this.handle1.connect(this);this.handle2=a;this.handle2.connect(this)},destroy:function(){if(this.handle1){this.handle1.disconnect(this)}if(this.handle2){this.handle2.disconnect(this)}$(this.canvas).remove()},redraw:function(){var d=$("#canvas-container");if(!this.canvas){this.canvas=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(this.canvas)}d.append($(this.canvas));if(this.dragging){this.canvas.style.zIndex="300"}}var n=function(c){return $(c).offset().left-d.offset().left};var i=function(c){return $(c).offset().top-d.offset().top};var h=n(this.handle1.element)+5;var g=i(this.handle1.element)+5;var p=n(this.handle2.element)+5;var m=i(this.handle2.element)+5;var f=100;var k=Math.min(h,p);var a=Math.max(h,p);var j=Math.min(g,m);var t=Math.max(g,m);var b=Math.min(Math.max(Math.abs(t-j)/2,100),300);var o=k-f;var s=j-f;var q=a
-k+2*f;var l=t-j+2*f;this.canvas.style.left=o+"px";this.canvas.style.top=s+"px";this.canvas.setAttribute("width",q);this.canvas.setAttribute("height",l);h-=o;g-=s;p-=o;m-=s;var r=this.canvas.getContext("2d");r.lineCap="round";r.strokeStyle=this.outer_color;r.lineWidth=7;r.beginPath();r.moveTo(h,g);r.bezierCurveTo(h+b,g,p-b,m,p,m);r.stroke();r.strokeStyle=this.inner_color;r.lineWidth=5;r.beginPath();r.moveTo(h,g);r.bezierCurveTo(h+b,g,p-b,m,p,m);r.stroke()}});function Node(a){this.element=a;this.input_terminals={};this.output_terminals={};this.tool_errors={}}$.extend(Node.prototype,{enable_input_terminal:function(d,a,b){var c=this;$(d).each(function(){var f=this.terminal=new InputTerminal(this,b);f.node=c;f.name=a;$(this).bind("dropstart",function(g){g.dragProxy.terminal.connectors[0].inner_color="#BBFFBB"}).bind("dropend",function(g){g.dragProxy.terminal.connectors[0].inner_color="#FFFFFF"}).bind("drop",function(g){(new Connector(g.dragTarget.terminal,g.dropTarget.terminal))
.redraw()}).bind("hover",function(){if(f.connectors.length>0){var g=$("<div class='callout'></div>").css({display:"none"}).appendTo("body").append($("<div class='buttons'></div>").append($("<img src='../images/delete_icon.png' />").click(function(){$.each(f.connectors,function(i,h){h.destroy()});g.remove()}))).bind("mouseleave",function(){$(this).remove()});g.css({top:$(this).offset().top-2,left:$(this).offset().left-g.width(),"padding-right":$(this).width()}).show()}});c.input_terminals[a]=f})},enable_output_terminal:function(d,a,b){var c=this;$(d).each(function(){var g=this;var f=this.terminal=new OutputTerminal(this,b);f.node=c;f.name=a;$(this).bind("dragstart",function(j){var i=$('<div class="drag-terminal" style="position: absolute;"></div>').appendTo("#canvas-container").get(0);i.terminal=new OutputTerminal(i);var k=new Connector();k.dragging=true;k.connect(this.terminal,i.terminal);$.dropManage({filter:function(h){return this.terminal.can_accept(f)}}).addClass("input-
terminal-active");return i}).bind("drag",function(i){var h=function(){var k=$(i.dragProxy).offsetParent().offset(),j=i.offsetX-k.left,l=i.offsetY-k.top;$(i.dragProxy).css({left:j,top:l});i.dragProxy.terminal.redraw();canvas_manager.update_viewport_overlay()};h();$("#canvas-container").get(0).scroll_panel.test(i,h)}).bind("dragend",function(h){h.dragProxy.terminal.connectors[0].destroy();$(h.dragProxy).remove();$.dropManage().removeClass("input-terminal-active");$("#canvas-container").get(0).scroll_panel.stop()});c.output_terminals[a]=f})},redraw:function(){$.each(this.input_terminals,function(a,b){b.redraw()});$.each(this.output_terminals,function(a,b){b.redraw()})},destroy:function(){$.each(this.input_terminals,function(a,b){b.destroy()});$.each(this.output_terminals,function(a,b){b.destroy()});workflow.remove_node(this);$(this.element).remove()},make_active:function(){$(this.element).addClass("toolForm-active")},make_inactive:function(){var a=this.element.get(0);(function(
b){b.removeChild(a);b.appendChild(a)})(a.parentNode);$(a).removeClass("toolForm-active")},init_field_data:function(g){var d=this.element;if(g.type){this.type=g.type}this.name=g.name;this.form_html=g.form_html;this.tool_state=g.tool_state;this.tool_errors=g.tool_errors;this.tooltip=g.tooltip?g.tooltip:"";this.annotation=g.annotation;this.post_job_actions=g.post_job_actions;if(this.tool_errors){d.addClass("tool-node-error")}else{d.removeClass("tool-node-error")}var c=this;var a=d.find(".toolFormBody");a.find("div").remove();var h=$("<div class='inputs'></div>").appendTo(a);$.each(g.data_inputs,function(j,b){var f=$("<div class='terminal input-terminal'></div>");c.enable_input_terminal(f,b.name,b.extensions);h.append($("<div class='form-row dataRow input-data-row' name='"+b.name+"'>"+b.label+"</div>").prepend(f))});if((g.data_inputs.length>0)&&(g.data_outputs.length>0)){a.append($("<div class='rule'></div>"))}$.each(g.data_outputs,function(k,b){var j=$("<div class='terminal out
put-terminal'></div>");c.enable_output_terminal(j,b.name,b.extensions);var f=b.name;if(b.extensions.indexOf("input")<0){f=f+" ("+b.extensions+")"}a.append($("<div class='form-row dataRow'>"+f+"</div>").append(j))});workflow.node_changed(this)},update_field_data:function(f){var c=$(this.element),d=this;this.tool_state=f.tool_state;this.form_html=f.form_html;this.tool_errors=f.tool_errors;this.annotation=f.annotation;this.post_job_actions=$.parseJSON(f.post_job_actions);if(this.tool_errors){c.addClass("tool-node-error")}else{c.removeClass("tool-node-error")}var g=c.find("div.inputs");var b=$("<div class='inputs'></div>");var a=g.find("div.input-data-row");$.each(f.data_inputs,function(k,h){var j=$("<div class='terminal input-terminal'></div>");d.enable_input_terminal(j,h.name,h.extensions);g.find("div[name="+h.name+"]").each(function(){$(this).find(".input-terminal").each(function(){var i=this.terminal.connectors[0];if(i){j[0].terminal.connectors[0]=i;i.handle2=j[0].terminal}}
);$(this).remove()});b.append($("<div class='form-row dataRow input-data-row' name='"+h.name+"'>"+h.label+"</div>").prepend(j))});g.replaceWith(b);g.find("div.input-data-row > .terminal").each(function(){this.terminal.destroy()});this.changed();this.redraw()},error:function(d){var a=$(this.element).find(".toolFormBody");a.find("div").remove();var c="<div style='color: red; text-style: italic;'>"+d+"</div>";this.form_html=c;a.html(c);workflow.node_changed(this)},changed:function(){workflow.node_changed(this)}});function Workflow(a){this.canvas_container=a;this.id_counter=0;this.nodes={};this.name=null;this.has_changes=false;this.active_form_has_changes=false}$.extend(Workflow.prototype,{add_node:function(a){a.id=this.id_counter;a.element.attr("id","wf-node-step-"+a.id);this.id_counter++;this.nodes[a.id]=a;this.has_changes=true;a.workflow=this},remove_node:function(a){if(this.active_node==a){this.clear_active_node()}delete this.nodes[a.id];this.has_changes=true},remove_all:fun
ction(){wf=this;$.each(this.nodes,function(b,a){a.destroy();wf.remove_node(a)})},to_simple:function(){var a={};$.each(this.nodes,function(c,f){var g={};$.each(f.input_terminals,function(h,i){g[i.name]=null;$.each(i.connectors,function(j,k){g[i.name]={id:k.handle1.node.id,output_name:k.handle1.name}})});var b={};if(f.post_job_actions){$.each(f.post_job_actions,function(j,h){var k={job_id:h.id,action_type:h.action_type,output_name:h.output_name,action_arguments:h.action_arguments};b[h.type+h.output_name]=null;b[h.type+h.output_name]=k})}var d={id:f.id,type:f.type,tool_id:f.tool_id,tool_state:f.tool_state,tool_errors:f.tool_errors,input_connections:g,position:$(f.element).position(),annotation:f.annotation,post_job_actions:f.post_job_actions};a[f.id]=d});return{steps:a}},from_simple:function(a){wf=this;var b=0;wf.name=a.name;$.each(a.steps,function(f,d){var c=prebuild_node("tool",d.name,d.tool_id);c.init_field_data(d);if(d.position){c.element.css({top:d.position.top,left:d.posi
tion.left})}c.id=d.id;wf.nodes[c.id]=c;b=Math.max(b,parseInt(f))});wf.id_counter=b+1;$.each(a.steps,function(f,d){var c=wf.nodes[f];$.each(d.input_connections,function(h,g){if(g){var i=wf.nodes[g.id];var j=new Connector();j.connect(i.output_terminals[g.output_name],c.input_terminals[h]);j.redraw()}})})},check_changes_in_active_form:function(){if(this.active_form_has_changes){this.has_changes=true;$("#right-content").find("form").submit();this.active_form_has_changes=false}},clear_active_node:function(){if(this.active_node){this.active_node.make_inactive();this.active_node=null}parent.show_form_for_tool("<div>No node selected</div>")},activate_node:function(a){if(this.active_node!=a){this.check_changes_in_active_form();this.clear_active_node();parent.show_form_for_tool(a.form_html+a.tooltip,a);a.make_active();this.active_node=a}},node_changed:function(a){this.has_changes=true;if(this.active_node==a){this.check_changes_in_active_form();parent.show_form_for_tool(a.form_html+a.t
ooltip,a)}},layout:function(){this.check_changes_in_active_form();this.has_changes=true;var i={};var b={};$.each(this.nodes,function(l,k){if(i[l]===undefined){i[l]=0}if(b[l]===undefined){b[l]=[]}});$.each(this.nodes,function(l,k){$.each(k.input_terminals,function(m,n){$.each(n.connectors,function(p,q){var o=q.handle1.node;i[k.id]+=1;b[o.id].push(k.id)})})});node_ids_by_level=[];while(true){level_parents=[];for(var a in i){if(i[a]==0){level_parents.push(a)}}if(level_parents.length==0){break}node_ids_by_level.push(level_parents);for(var f in level_parents){var j=level_parents[f];delete i[j];for(var g in b[j]){i[b[j][g]]-=1}}}if(i.length){return}var d=this.nodes;var h=80;v_pad=30;var c=h;$.each(node_ids_by_level,function(k,l){l.sort(function(p,o){return $(d[p].element).position().top-$(d[o].element).position().top});var m=0;var n=v_pad;$.each(l,function(o,r){var q=d[r];var p=$(q.element);$(p).css({top:n,left:c});m=Math.max(m,$(p).width());n+=$(p).height()+v_pad});c+=m+h});$.eac
h(d,function(k,l){l.redraw()})},bounds_for_all_nodes:function(){var d=Infinity,b=-Infinity,c=Infinity,a=-Infinity,f;$.each(this.nodes,function(h,g){e=$(g.element);f=e.position();d=Math.min(d,f.left);b=Math.max(b,f.left+e.width());c=Math.min(c,f.top);a=Math.max(a,f.top+e.width())});return{xmin:d,xmax:b,ymin:c,ymax:a}},fit_canvas_to_nodes:function(){var a=this.bounds_for_all_nodes();var f=this.canvas_container.position();var i=this.canvas_container.parent();var d=fix_delta(a.xmin,100);var h=fix_delta(a.ymin,100);d=Math.max(d,f.left);h=Math.max(h,f.top);var c=f.left-d;var g=f.top-h;var b=round_up(a.xmax+100,100)+d;var j=round_up(a.ymax+100,100)+h;b=Math.max(b,-c+i.width());j=Math.max(j,-g+i.height());this.canvas_container.css({left:c,top:g,width:b,height:j});this.canvas_container.children().each(function(){var k=$(this).position();$(this).css("left",k.left+d);$(this).css("top",k.top+h)})}});function fix_delta(a,b){if(a<b||a>3*b){new_pos=(Math.ceil(((a%b))/b)+1)*b;return(-(a-new
_pos))}return 0}function round_up(a,b){return Math.ceil(a/b)*b}function prebuild_node(l,j,r){var i=$("<div class='toolForm toolFormInCanvas'></div>");var g=new Node(i);g.type=l;if(l=="tool"){g.tool_id=r}var n=$("<div class='toolFormTitle unselectable'>"+j+"</div>");i.append(n);i.css("left",$(window).scrollLeft()+20);i.css("top",$(window).scrollTop()+20);var m=$("<div class='toolFormBody'></div>");var h="<div><img height='16' align='middle' src='../images/loading_small_white_bg.gif'/> loading tool info...</div>";m.append(h);g.form_html=h;i.append(m);var k=$("<div class='buttons' style='float: right;'></div>");k.append($("<img src='../images/delete_icon.png' />").click(function(b){g.destroy()}).hover(function(){$(this).attr("src","../images/delete_icon_dark.png")},function(){$(this).attr("src","../images/delete_icon.png")}));i.appendTo("#canvas-container");var d=$("#canvas-container").position();var c=$("#canvas-container").parent();var a=i.width();var q=i.height();i.css({left
:(-d.left)+(c.width()/2)-(a/2),top:(-d.top)+(c.height()/2)-(q/2)});k.prependTo(n);a+=(k.width()+10);i.css("width",a);$(i).bind("dragstart",function(){workflow.activate_node(g)}).bind("dragend",function(){workflow.node_changed(this);workflow.fit_canvas_to_nodes();canvas_manager.draw_overview()}).bind("dragclickonly",function(){workflow.activate_node(g)}).bind("drag",function(o){var f=$(this).offsetParent().offset(),b=o.offsetX-f.left,p=o.offsetY-f.top;$(this).css({left:b,top:p});$(this).find(".terminal").each(function(){this.terminal.redraw()})});return g}var ext_to_type=null;var type_to_type=null;function issubtype(b,a){b=ext_to_type[b];a=ext_to_type[a];return(type_to_type[b])&&(a in type_to_type[b])}function populate_datatype_info(a){ext_to_type=a.ext_to_class_name;type_to_type=a.class_to_classes}function ScrollPanel(a){this.panel=a}$.extend(ScrollPanel.prototype,{test:function(v,d){clearTimeout(this.timeout);var k=v.pageX,j=v.pageY,l=$(this.panel),c=l.position(),b=l.width(
),i=l.height(),w=l.parent(),s=w.width(),a=w.height(),r=w.offset(),p=r.left,m=r.top,A=p+w.width(),u=m+w.height(),B=-(b-(s/2)),z=-(i-(a/2)),g=(s/2),f=(a/2),h=false,q=5,o=23;if(k-q<p){if(c.left<g){var n=Math.min(o,g-c.left);l.css("left",c.left+n);h=true}}else{if(k+q>A){if(c.left>B){var n=Math.min(o,c.left-B);l.css("left",c.left-n);h=true}}else{if(j-q<m){if(c.top<f){var n=Math.min(o,f-c.top);l.css("top",c.top+n);h=true}}else{if(j+q>u){if(c.top>z){var n=Math.min(o,c.top-B);l.css("top",(c.top-n)+"px");h=true}}}}}if(h){d();var l=this;this.timeout=setTimeout(function(){l.test(v,d)},50)}},stop:function(b,a){clearTimeout(this.timeout)}});function CanvasManager(b,a){this.cv=b;this.cc=this.cv.find("#canvas-container");this.oc=a.find("#overview-canvas");this.ov=a.find("#overview-viewport");this.init_drag()}$.extend(CanvasManager.prototype,{init_drag:function(){var b=this;var a=function(f,g){f=Math.min(f,b.cv.width()/2);f=Math.max(f,-b.cc.width()+b.cv.width()/2);g=Math.min(g,b.cv.height()
/2);g=Math.max(g,-b.cc.height()+b.cv.height()/2);b.cc.css({left:f,top:g});b.update_viewport_overlay()};this.cc.each(function(){this.scroll_panel=new ScrollPanel(this)});var d,c;this.cv.bind("dragstart",function(g){var h=$(this).offset();var f=b.cc.position();c=f.top-h.top;d=f.left-h.left}).bind("drag",function(f){a(f.offsetX+d,f.offsetY+c)}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});this.ov.bind("drag",function(k){var j=b.cc.width(),g=b.cc.height(),f=b.oc.width(),h=b.oc.height(),i=$(this).offsetParent().offset(),m=k.offsetX-i.left,l=k.offsetY-i.top;a(-(m/f*j),-(l/h*g))}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});$("#overview-border").bind("drag",function(g){var i=$(this).offsetParent();var h=i.offset();var f=Math.max(i.width()-(g.offsetX-h.left),i.height()-(g.offsetY-h.top));$(this).css({width:f,height:f});b.draw_overview()});$("#overview-border div").bind("drag",function(f){})},update_viewport_overlay:fun
ction(){var b=this.cc,f=this.cv,a=this.oc,c=this.ov,d=b.width(),j=b.height(),i=a.width(),g=a.height(),h=b.position();c.css({left:-(h.left/d*i),top:-(h.top/j*g),width:(f.width()/d*i)-2,height:(f.height()/j*g)-2})},draw_overview:function(){var j=$("#overview-canvas"),m=j.parent().parent().width(),i=j.get(0).getContext("2d"),d=$("#canvas-container").width(),l=$("#canvas-container").height();var g,a,k,f;var h=this.cv.width();var b=this.cv.height();if(d<h&&l<b){k=d/h*m;f=(m-k)/2;g=l/b*m;a=(m-g)/2}else{if(d<l){a=0;g=m;k=Math.ceil(g*d/l);f=(m-k)/2}else{k=m;f=0;g=Math.ceil(k*l/d);a=(m-g)/2}}j.parent().css({left:f,top:a,width:k,height:g});j.attr("width",k);j.attr("height",g);i.fillStyle="#D2C099";i.strokeStyle="#D8B365";i.lineWidth=1;$.each(workflow.nodes,function(t,q){var s=$(q.element),n=s.position(),c=n.left/d*k,r=n.top/l*g,o=s.width()/d*k,p=s.height()/l*g;i.fillRect(c,r,o,p);i.strokeRect(c,r,o,p)});this.update_viewport_overlay()}});
+function Terminal(a){this.element=a;this.connectors=[]}$.extend(Terminal.prototype,{connect:function(a){this.connectors.push(a);if(this.node){this.node.changed()}},disconnect:function(a){this.connectors.splice($.inArray(a,this.connectors),1);if(this.node){this.node.changed()}},redraw:function(){$.each(this.connectors,function(a,b){b.redraw()})},destroy:function(){$.each(this.connectors.slice(),function(a,b){b.destroy()})}});function OutputTerminal(a,b){Terminal.call(this,a);this.datatypes=b}OutputTerminal.prototype=new Terminal();function InputTerminal(a,b){Terminal.call(this,a);this.datatypes=b}InputTerminal.prototype=new Terminal();$.extend(InputTerminal.prototype,{can_accept:function(a){if(this.connectors.length<1){for(var c in this.datatypes){for(var b in a.datatypes){if(a.datatypes[b]=="input"||issubtype(a.datatypes[b],this.datatypes[c])){return true}}}}return false}});function Connector(b,a){this.canvas=null;this.dragging=false;this.inner_color="#FFFFFF";this.outer_col
or="#D8B365";if(b&&a){this.connect(b,a)}}$.extend(Connector.prototype,{connect:function(b,a){this.handle1=b;this.handle1.connect(this);this.handle2=a;this.handle2.connect(this)},destroy:function(){if(this.handle1){this.handle1.disconnect(this)}if(this.handle2){this.handle2.disconnect(this)}$(this.canvas).remove()},redraw:function(){var d=$("#canvas-container");if(!this.canvas){this.canvas=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(this.canvas)}d.append($(this.canvas));if(this.dragging){this.canvas.style.zIndex="300"}}var n=function(c){return $(c).offset().left-d.offset().left};var i=function(c){return $(c).offset().top-d.offset().top};var h=n(this.handle1.element)+5;var g=i(this.handle1.element)+5;var p=n(this.handle2.element)+5;var m=i(this.handle2.element)+5;var f=100;var k=Math.min(h,p);var a=Math.max(h,p);var j=Math.min(g,m);var t=Math.max(g,m);var b=Math.min(Math.max(Math.abs(t-j)/2,100),300);var o=k-f;var s=j-f;var q=a
-k+2*f;var l=t-j+2*f;this.canvas.style.left=o+"px";this.canvas.style.top=s+"px";this.canvas.setAttribute("width",q);this.canvas.setAttribute("height",l);h-=o;g-=s;p-=o;m-=s;var r=this.canvas.getContext("2d");r.lineCap="round";r.strokeStyle=this.outer_color;r.lineWidth=7;r.beginPath();r.moveTo(h,g);r.bezierCurveTo(h+b,g,p-b,m,p,m);r.stroke();r.strokeStyle=this.inner_color;r.lineWidth=5;r.beginPath();r.moveTo(h,g);r.bezierCurveTo(h+b,g,p-b,m,p,m);r.stroke()}});function Node(a){this.element=a;this.input_terminals={};this.output_terminals={};this.tool_errors={}}$.extend(Node.prototype,{enable_input_terminal:function(d,a,b){var c=this;$(d).each(function(){var f=this.terminal=new InputTerminal(this,b);f.node=c;f.name=a;$(this).bind("dropstart",function(g){g.dragProxy.terminal.connectors[0].inner_color="#BBFFBB"}).bind("dropend",function(g){g.dragProxy.terminal.connectors[0].inner_color="#FFFFFF"}).bind("drop",function(g){(new Connector(g.dragTarget.terminal,g.dropTarget.terminal))
.redraw()}).bind("hover",function(){if(f.connectors.length>0){var g=$("<div class='callout'></div>").css({display:"none"}).appendTo("body").append($("<div class='buttons'></div>").append($("<img/>").attr("src",image_path+"/delete_icon.png").click(function(){$.each(f.connectors,function(i,h){h.destroy()});g.remove()}))).bind("mouseleave",function(){$(this).remove()});g.css({top:$(this).offset().top-2,left:$(this).offset().left-g.width(),"padding-right":$(this).width()}).show()}});c.input_terminals[a]=f})},enable_output_terminal:function(d,a,b){var c=this;$(d).each(function(){var g=this;var f=this.terminal=new OutputTerminal(this,b);f.node=c;f.name=a;$(this).bind("dragstart",function(j){var i=$('<div class="drag-terminal" style="position: absolute;"></div>').appendTo("#canvas-container").get(0);i.terminal=new OutputTerminal(i);var k=new Connector();k.dragging=true;k.connect(this.terminal,i.terminal);$.dropManage({filter:function(h){return this.terminal.can_accept(f)}}).addClas
s("input-terminal-active");return i}).bind("drag",function(i){var h=function(){var k=$(i.dragProxy).offsetParent().offset(),j=i.offsetX-k.left,l=i.offsetY-k.top;$(i.dragProxy).css({left:j,top:l});i.dragProxy.terminal.redraw();canvas_manager.update_viewport_overlay()};h();$("#canvas-container").get(0).scroll_panel.test(i,h)}).bind("dragend",function(h){h.dragProxy.terminal.connectors[0].destroy();$(h.dragProxy).remove();$.dropManage().removeClass("input-terminal-active");$("#canvas-container").get(0).scroll_panel.stop()});c.output_terminals[a]=f})},redraw:function(){$.each(this.input_terminals,function(a,b){b.redraw()});$.each(this.output_terminals,function(a,b){b.redraw()})},destroy:function(){$.each(this.input_terminals,function(a,b){b.destroy()});$.each(this.output_terminals,function(a,b){b.destroy()});workflow.remove_node(this);$(this.element).remove()},make_active:function(){$(this.element).addClass("toolForm-active")},make_inactive:function(){var a=this.element.get(0);(
function(b){b.removeChild(a);b.appendChild(a)})(a.parentNode);$(a).removeClass("toolForm-active")},init_field_data:function(g){var d=this.element;if(g.type){this.type=g.type}this.name=g.name;this.form_html=g.form_html;this.tool_state=g.tool_state;this.tool_errors=g.tool_errors;this.tooltip=g.tooltip?g.tooltip:"";this.annotation=g.annotation;this.post_job_actions=g.post_job_actions;this.workflow_outputs=g.workflow_outputs;if(this.tool_errors){d.addClass("tool-node-error")}else{d.removeClass("tool-node-error")}var c=this;var a=d.find(".toolFormBody");a.find("div").remove();var h=$("<div class='inputs'></div>").appendTo(a);$.each(g.data_inputs,function(j,b){var f=$("<div class='terminal input-terminal'></div>");c.enable_input_terminal(f,b.name,b.extensions);h.append($("<div class='form-row dataRow input-data-row' name='"+b.name+"'>"+b.label+"</div>").prepend(f))});if((g.data_inputs.length>0)&&(g.data_outputs.length>0)){a.append($("<div class='rule'></div>"))}$.each(g.data_outpu
ts,function(k,b){var j=$("<div class='terminal output-terminal'></div>");c.enable_output_terminal(j,b.name,b.extensions);var f=b.name;if(b.extensions.indexOf("input")<0){f=f+" ("+b.extensions+")"}a.append($("<div class='form-row dataRow'>"+f+"</div>").append(j))});workflow.node_changed(this)},update_field_data:function(f){var c=$(this.element),d=this;this.tool_state=f.tool_state;this.form_html=f.form_html;this.tool_errors=f.tool_errors;this.annotation=f.annotation;this.post_job_actions=$.parseJSON(f.post_job_actions);if(this.tool_errors){c.addClass("tool-node-error")}else{c.removeClass("tool-node-error")}var g=c.find("div.inputs");var b=$("<div class='inputs'></div>");var a=g.find("div.input-data-row");$.each(f.data_inputs,function(k,h){var j=$("<div class='terminal input-terminal'></div>");d.enable_input_terminal(j,h.name,h.extensions);g.find("div[name="+h.name+"]").each(function(){$(this).find(".input-terminal").each(function(){var i=this.terminal.connectors[0];if(i){j[0].
terminal.connectors[0]=i;i.handle2=j[0].terminal}});$(this).remove()});b.append($("<div class='form-row dataRow input-data-row' name='"+h.name+"'>"+h.label+"</div>").prepend(j))});g.replaceWith(b);g.find("div.input-data-row > .terminal").each(function(){this.terminal.destroy()});this.changed();this.redraw()},error:function(d){var a=$(this.element).find(".toolFormBody");a.find("div").remove();var c="<div style='color: red; text-style: italic;'>"+d+"</div>";this.form_html=c;a.html(c);workflow.node_changed(this)},changed:function(){workflow.node_changed(this)}});function Workflow(a){this.canvas_container=a;this.id_counter=0;this.nodes={};this.name=null;this.has_changes=false;this.active_form_has_changes=false}$.extend(Workflow.prototype,{add_node:function(a){a.id=this.id_counter;a.element.attr("id","wf-node-step-"+a.id);this.id_counter++;this.nodes[a.id]=a;this.has_changes=true;a.workflow=this},remove_node:function(a){if(this.active_node==a){this.clear_active_node()}delete this
.nodes[a.id];this.has_changes=true},remove_all:function(){wf=this;$.each(this.nodes,function(b,a){a.destroy();wf.remove_node(a)})},to_simple:function(){var a={};$.each(this.nodes,function(c,f){var g={};$.each(f.input_terminals,function(h,i){g[i.name]=null;$.each(i.connectors,function(j,k){g[i.name]={id:k.handle1.node.id,output_name:k.handle1.name}})});var b={};if(f.post_job_actions){$.each(f.post_job_actions,function(j,h){var k={job_id:h.id,action_type:h.action_type,output_name:h.output_name,action_arguments:h.action_arguments};b[h.type+h.output_name]=null;b[h.type+h.output_name]=k})}if(!f.workflow_outputs){f.workflow_outputs=[]}var d={id:f.id,type:f.type,tool_id:f.tool_id,tool_state:f.tool_state,tool_errors:f.tool_errors,input_connections:g,position:$(f.element).position(),annotation:f.annotation,post_job_actions:f.post_job_actions,workflow_outputs:f.workflow_outputs};a[f.id]=d});return{steps:a}},from_simple:function(a){wf=this;var b=0;wf.name=a.name;$.each(a.steps,function
(f,d){var c=prebuild_node("tool",d.name,d.tool_id);c.init_field_data(d);if(d.position){c.element.css({top:d.position.top,left:d.position.left})}c.id=d.id;wf.nodes[c.id]=c;b=Math.max(b,parseInt(f))});wf.id_counter=b+1;$.each(a.steps,function(f,d){var c=wf.nodes[f];$.each(d.input_connections,function(h,g){if(g){var i=wf.nodes[g.id];var j=new Connector();j.connect(i.output_terminals[g.output_name],c.input_terminals[h]);j.redraw()}})})},check_changes_in_active_form:function(){if(this.active_form_has_changes){this.has_changes=true;$("#right-content").find("form").submit();this.active_form_has_changes=false}},clear_active_node:function(){if(this.active_node){this.active_node.make_inactive();this.active_node=null}parent.show_form_for_tool("<div>No node selected</div>")},activate_node:function(a){if(this.active_node!=a){this.check_changes_in_active_form();this.clear_active_node();parent.show_form_for_tool(a.form_html+a.tooltip,a);a.make_active();this.active_node=a}},node_changed:fun
ction(a){this.has_changes=true;if(this.active_node==a){this.check_changes_in_active_form();parent.show_form_for_tool(a.form_html+a.tooltip,a)}},layout:function(){this.check_changes_in_active_form();this.has_changes=true;var i={};var b={};$.each(this.nodes,function(l,k){if(i[l]===undefined){i[l]=0}if(b[l]===undefined){b[l]=[]}});$.each(this.nodes,function(l,k){$.each(k.input_terminals,function(m,n){$.each(n.connectors,function(p,q){var o=q.handle1.node;i[k.id]+=1;b[o.id].push(k.id)})})});node_ids_by_level=[];while(true){level_parents=[];for(var a in i){if(i[a]==0){level_parents.push(a)}}if(level_parents.length==0){break}node_ids_by_level.push(level_parents);for(var f in level_parents){var j=level_parents[f];delete i[j];for(var g in b[j]){i[b[j][g]]-=1}}}if(i.length){return}var d=this.nodes;var h=80;v_pad=30;var c=h;$.each(node_ids_by_level,function(k,l){l.sort(function(p,o){return $(d[p].element).position().top-$(d[o].element).position().top});var m=0;var n=v_pad;$.each(l,fun
ction(o,r){var q=d[r];var p=$(q.element);$(p).css({top:n,left:c});m=Math.max(m,$(p).width());n+=$(p).height()+v_pad});c+=m+h});$.each(d,function(k,l){l.redraw()})},bounds_for_all_nodes:function(){var d=Infinity,b=-Infinity,c=Infinity,a=-Infinity,f;$.each(this.nodes,function(h,g){e=$(g.element);f=e.position();d=Math.min(d,f.left);b=Math.max(b,f.left+e.width());c=Math.min(c,f.top);a=Math.max(a,f.top+e.width())});return{xmin:d,xmax:b,ymin:c,ymax:a}},fit_canvas_to_nodes:function(){var a=this.bounds_for_all_nodes();var f=this.canvas_container.position();var i=this.canvas_container.parent();var d=fix_delta(a.xmin,100);var h=fix_delta(a.ymin,100);d=Math.max(d,f.left);h=Math.max(h,f.top);var c=f.left-d;var g=f.top-h;var b=round_up(a.xmax+100,100)+d;var j=round_up(a.ymax+100,100)+h;b=Math.max(b,-c+i.width());j=Math.max(j,-g+i.height());this.canvas_container.css({left:c,top:g,width:b,height:j});this.canvas_container.children().each(function(){var k=$(this).position();$(this).css("left
",k.left+d);$(this).css("top",k.top+h)})}});function fix_delta(a,b){if(a<b||a>3*b){new_pos=(Math.ceil(((a%b))/b)+1)*b;return(-(a-new_pos))}return 0}function round_up(a,b){return Math.ceil(a/b)*b}function prebuild_node(l,j,r){var i=$("<div class='toolForm toolFormInCanvas'></div>");var g=new Node(i);g.type=l;if(l=="tool"){g.tool_id=r}var n=$("<div class='toolFormTitle unselectable'>"+j+"</div>");i.append(n);i.css("left",$(window).scrollLeft()+20);i.css("top",$(window).scrollTop()+20);var m=$("<div class='toolFormBody'></div>");var h="<div><img height='16' align='middle' src='"+image_path+"/loading_small_white_bg.gif'/> loading tool info...</div>";m.append(h);g.form_html=h;i.append(m);var k=$("<div class='buttons' style='float: right;'></div>");k.append($("<img/>").attr("src",image_path+"/delete_icon.png").click(function(b){g.destroy()}).hover(function(){$(this).attr("src",image_path+"/delete_icon_dark.png")},function(){$(this).attr("src",image_path+"/delete_icon.png")}));i.ap
pendTo("#canvas-container");var d=$("#canvas-container").position();var c=$("#canvas-container").parent();var a=i.width();var q=i.height();i.css({left:(-d.left)+(c.width()/2)-(a/2),top:(-d.top)+(c.height()/2)-(q/2)});k.prependTo(n);a+=(k.width()+10);i.css("width",a);$(i).bind("dragstart",function(){workflow.activate_node(g)}).bind("dragend",function(){workflow.node_changed(this);workflow.fit_canvas_to_nodes();canvas_manager.draw_overview()}).bind("dragclickonly",function(){workflow.activate_node(g)}).bind("drag",function(o){var f=$(this).offsetParent().offset(),b=o.offsetX-f.left,p=o.offsetY-f.top;$(this).css({left:b,top:p});$(this).find(".terminal").each(function(){this.terminal.redraw()})});return g}var ext_to_type=null;var type_to_type=null;function issubtype(b,a){b=ext_to_type[b];a=ext_to_type[a];return(type_to_type[b])&&(a in type_to_type[b])}function populate_datatype_info(a){ext_to_type=a.ext_to_class_name;type_to_type=a.class_to_classes}function ScrollPanel(a){this.p
anel=a}$.extend(ScrollPanel.prototype,{test:function(v,d){clearTimeout(this.timeout);var k=v.pageX,j=v.pageY,l=$(this.panel),c=l.position(),b=l.width(),i=l.height(),w=l.parent(),s=w.width(),a=w.height(),r=w.offset(),p=r.left,m=r.top,A=p+w.width(),u=m+w.height(),B=-(b-(s/2)),z=-(i-(a/2)),g=(s/2),f=(a/2),h=false,q=5,o=23;if(k-q<p){if(c.left<g){var n=Math.min(o,g-c.left);l.css("left",c.left+n);h=true}}else{if(k+q>A){if(c.left>B){var n=Math.min(o,c.left-B);l.css("left",c.left-n);h=true}}else{if(j-q<m){if(c.top<f){var n=Math.min(o,f-c.top);l.css("top",c.top+n);h=true}}else{if(j+q>u){if(c.top>z){var n=Math.min(o,c.top-B);l.css("top",(c.top-n)+"px");h=true}}}}}if(h){d();var l=this;this.timeout=setTimeout(function(){l.test(v,d)},50)}},stop:function(b,a){clearTimeout(this.timeout)}});function CanvasManager(b,a){this.cv=b;this.cc=this.cv.find("#canvas-container");this.oc=a.find("#overview-canvas");this.ov=a.find("#overview-viewport");this.init_drag()}$.extend(CanvasManager.prototype,{
init_drag:function(){var b=this;var a=function(f,g){f=Math.min(f,b.cv.width()/2);f=Math.max(f,-b.cc.width()+b.cv.width()/2);g=Math.min(g,b.cv.height()/2);g=Math.max(g,-b.cc.height()+b.cv.height()/2);b.cc.css({left:f,top:g});b.update_viewport_overlay()};this.cc.each(function(){this.scroll_panel=new ScrollPanel(this)});var d,c;this.cv.bind("dragstart",function(g){var h=$(this).offset();var f=b.cc.position();c=f.top-h.top;d=f.left-h.left}).bind("drag",function(f){a(f.offsetX+d,f.offsetY+c)}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});this.ov.bind("drag",function(k){var j=b.cc.width(),g=b.cc.height(),f=b.oc.width(),h=b.oc.height(),i=$(this).offsetParent().offset(),m=k.offsetX-i.left,l=k.offsetY-i.top;a(-(m/f*j),-(l/h*g))}).bind("dragend",function(){workflow.fit_canvas_to_nodes();b.draw_overview()});$("#overview-border").bind("drag",function(g){var i=$(this).offsetParent();var h=i.offset();var f=Math.max(i.width()-(g.offsetX-h.left),i.height()-(g
.offsetY-h.top));$(this).css({width:f,height:f});b.draw_overview()});$("#overview-border div").bind("drag",function(f){})},update_viewport_overlay:function(){var b=this.cc,f=this.cv,a=this.oc,c=this.ov,d=b.width(),j=b.height(),i=a.width(),g=a.height(),h=b.position();c.css({left:-(h.left/d*i),top:-(h.top/j*g),width:(f.width()/d*i)-2,height:(f.height()/j*g)-2})},draw_overview:function(){var j=$("#overview-canvas"),m=j.parent().parent().width(),i=j.get(0).getContext("2d"),d=$("#canvas-container").width(),l=$("#canvas-container").height();var g,a,k,f;var h=this.cv.width();var b=this.cv.height();if(d<h&&l<b){k=d/h*m;f=(m-k)/2;g=l/b*m;a=(m-g)/2}else{if(d<l){a=0;g=m;k=Math.ceil(g*d/l);f=(m-k)/2}else{k=m;f=0;g=Math.ceil(k*l/d);a=(m-g)/2}}j.parent().css({left:f,top:a,width:k,height:g});j.attr("width",k);j.attr("height",g);i.fillStyle="#D2C099";i.strokeStyle="#D8B365";i.lineWidth=1;$.each(workflow.nodes,function(t,q){var s=$(q.element),n=s.position(),c=n.left/d*k,r=n.top/l*g,o=s.width
()/d*k,p=s.height()/l*g;i.fillRect(c,r,o,p);i.strokeRect(c,r,o,p)});this.update_viewport_overlay()}});
--- a/static/scripts/galaxy.panels.js
+++ b/static/scripts/galaxy.panels.js
@@ -193,7 +193,7 @@ function show_modal( title, body, button
b.hide();
}
if ( body == "progress" ) {
- body = $( "<img src='../images/yui/rel_interstitial_loading.gif')' />" );
+ body = $("<img/>").attr("src", image_path + "/yui/rel_interstitial_loading.gif");
}
$( ".dialog-box" ).find( ".body" ).html( body );
if ( ! $(".dialog-box-container").is( ":visible" ) ) {
--- a/static/scripts/galaxy.workflow_editor.canvas.js
+++ b/static/scripts/galaxy.workflow_editor.canvas.js
@@ -174,7 +174,7 @@ function Node( element ) {
.appendTo( "body" )
.append(
$("<div class='buttons'></div>").append(
- $("<img src='../images/delete_icon.png' />").click( function() {
+ $("<img/>").attr("src", image_path + '/delete_icon.png').click( function() {
$.each( terminal.connectors, function( _, x ) {
x.destroy();
});
@@ -648,18 +648,18 @@ function prebuild_node( type, title_text
f.append( title );
f.css( "left", $(window).scrollLeft() + 20 ); f.css( "top", $(window).scrollTop() + 20 );
var b = $("<div class='toolFormBody'></div>");
- var tmp = "<div><img height='16' align='middle' src='../images/loading_small_white_bg.gif'/> loading tool info...</div>";
+ var tmp = "<div><img height='16' align='middle' src='" +image_path+ "/loading_small_white_bg.gif'/> loading tool info...</div>";
b.append( tmp );
node.form_html = tmp;
f.append( b );
// Fix width to computed width
// Now add floats
var buttons = $("<div class='buttons' style='float: right;'></div>");
- buttons.append( $("<img src='../images/delete_icon.png' />").click( function( e ) {
+ buttons.append( $("<img/>").attr("src", image_path + '/delete_icon.png').click( function( e ) {
node.destroy();
} ).hover(
- function() { $(this).attr( 'src', "../images/delete_icon_dark.png" ); },
- function() { $(this).attr( 'src', "../images/delete_icon.png" ); }
+ function() { $(this).attr( "src", image_path + "/delete_icon_dark.png" ); },
+ function() { $(this).attr( "src", image_path + "/delete_icon.png" ); }
) );
// Place inside container
f.appendTo( "#canvas-container" );
1
0
galaxy-dist commit 121678c8a483: lims: changed sequencing request menu group to sample tracking
by commits-noreply@bitbucket.org 08 Sep '10
by commits-noreply@bitbucket.org 08 Sep '10
08 Sep '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User rc
# Date 1283447523 14400
# Node ID 121678c8a483061c531c37c8d2e398ae1baa315a
# Parent 368956bcef26af16b4f7694fb8f81fb6152cf6de
lims: changed sequencing request menu group to sample tracking
--- a/templates/webapps/galaxy/admin/index.mako
+++ b/templates/webapps/galaxy/admin/index.mako
@@ -110,7 +110,7 @@
</div><div class="toolSectionPad"></div><div class="toolSectionTitle">
- <span>Sequencing Requests</span>
+ <span>Sample Tracking</span></div><div class="toolSectionBody"><div class="toolSectionBg">
1
0
galaxy-dist commit d9e099daa827: Added missing Bowtie color loc file to setup.sh
by commits-noreply@bitbucket.org 08 Sep '10
by commits-noreply@bitbucket.org 08 Sep '10
08 Sep '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Kelly Vincent <kpvincent(a)bx.psu.edu>
# Date 1282317387 14400
# Node ID d9e099daa8279880d5e054680ab28e8fc3064f77
# Parent d8cf43c9a0b99ce386f4d5e701393b0372966f7a
Added missing Bowtie color loc file to setup.sh
--- a/setup.sh
+++ b/setup.sh
@@ -16,6 +16,7 @@ tool-data/bfast_indexes.loc.sample
tool-data/binned_scores.loc.sample
tool-data/blastdb.loc.sample
tool-data/bowtie_indices.loc.sample
+tool-data/bowtie_indices_color.loc.sample
tool-data/encode_datasets.loc.sample
tool-data/liftOver.loc.sample
tool-data/maf_index.loc.sample
1
0
galaxy-dist commit f09915c8da94: Library template improvements and miscellaneous fixes:
by commits-noreply@bitbucket.org 08 Sep '10
by commits-noreply@bitbucket.org 08 Sep '10
08 Sep '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Greg Von Kuster <greg(a)bx.psu.edu>
# Date 1283450357 14400
# Node ID f09915c8da9404b8642b96ee81d89afdccde8414
# Parent 121678c8a483061c531c37c8d2e398ae1baa315a
Library template improvements and miscellaneous fixes:
1. Add support for handling inherited library temnplates that include all supported field types ( AddressField, CheckboxField, SelectField, TextArea, TextField, WorkflowField ) to the upload form for library datasets. New userAddress objects can now be created on the upload forms.
2. Improve the UI for selecting tempaltes for library items - it is now clear that the displayed template is not useable since it is disabled and a message is displayed.
3. Automatically inherit template contents from parent for inherited templates.
4. Fix the AddressField UI to display the required fields for rendered html.
5. Add new test_library_templates.py functional test script.
.
--- /dev/null
+++ b/test/functional/test_library_templates.py
@@ -0,0 +1,219 @@
+from base.twilltestcase import *
+from base.test_db_util import *
+
+class TestLibraryFeatures( TwillTestCase ):
+ def test_000_initiate_users( self ):
+ """Ensuring all required user accounts exist"""
+ self.logout()
+ self.login( email='test1(a)bx.psu.edu', username='regular-user1' )
+ global regular_user1
+ regular_user1 = get_user( 'test1(a)bx.psu.edu' )
+ assert regular_user1 is not None, 'Problem retrieving user with email "test1(a)bx.psu.edu" from the database'
+ global regular_user1_private_role
+ regular_user1_private_role = get_private_role( regular_user1 )
+ self.logout()
+ self.login( email='test2(a)bx.psu.edu', username='regular-user2' )
+ global regular_user2
+ regular_user2 = get_user( 'test2(a)bx.psu.edu' )
+ assert regular_user2 is not None, 'Problem retrieving user with email "test2(a)bx.psu.edu" from the database'
+ global regular_user2_private_role
+ regular_user2_private_role = get_private_role( regular_user2 )
+ self.logout()
+ self.login( email='test3(a)bx.psu.edu', username='regular-user3' )
+ global regular_user3
+ regular_user3 = get_user( 'test3(a)bx.psu.edu' )
+ assert regular_user3 is not None, 'Problem retrieving user with email "test3(a)bx.psu.edu" from the database'
+ global regular_user3_private_role
+ regular_user3_private_role = get_private_role( regular_user3 )
+ self.logout()
+ self.login( email='test(a)bx.psu.edu', username='admin-user' )
+ global admin_user
+ admin_user = get_user( 'test(a)bx.psu.edu' )
+ assert admin_user is not None, 'Problem retrieving user with email "test(a)bx.psu.edu" from the database'
+ global admin_user_private_role
+ admin_user_private_role = get_private_role( admin_user )
+ def test_005_create_library_templates( self ):
+ """Testing creating several LibraryInformationTemplate form definitions"""
+ # Logged in as admin_user
+ for type in [ 'AddressField', 'CheckboxField', 'SelectField', 'TextArea', 'TextField', 'WorkflowField' ]:
+ form_desc = '%s description' % type
+ # Create form for library template
+ self.create_single_field_type_form_definition( name=type,
+ desc=form_desc,
+ formtype=galaxy.model.FormDefinition.types.LIBRARY_INFO_TEMPLATE,
+ field_type=type )
+ # Get all of the new form definitions for later use
+ global AddressField_form
+ AddressField_form = get_form( 'AddressField' )
+ global CheckboxField_form
+ CheckboxField_form = get_form( 'CheckboxField' )
+ global SelectField_form
+ SelectField_form = get_form( 'SelectField' )
+ global TextArea_form
+ TextArea_form = get_form( 'TextArea' )
+ global TextField_form
+ TextField_form = get_form( 'TextField' )
+ global WorkflowField_form
+ WorkflowField_form = get_form( 'WorkflowField' )
+ def test_010_create_libraries( self ):
+ """Testing creating a new library for each template"""
+ # Logged in as admin_user
+ for index, form in enumerate( [ AddressField_form, CheckboxField_form, SelectField_form, TextArea_form, TextField_form, WorkflowField_form ] ):
+ name = 'library%s' % str( index + 1 )
+ description = '%s description' % name
+ synopsis = '%s synopsis' % name
+ self.create_library( name=name, description=description, synopsis=synopsis )
+ # Get the libraries for later use
+ global library1
+ library1 = get_library( 'library1', 'library1 description', 'library1 synopsis' )
+ global library2
+ library2 = get_library( 'library2', 'library2 description', 'library2 synopsis' )
+ global library3
+ library3 = get_library( 'library3', 'library3 description', 'library3 synopsis' )
+ global library4
+ library4 = get_library( 'library4', 'library4 description', 'library4 synopsis' )
+ global library5
+ library5 = get_library( 'library5', 'library5 description', 'library5 synopsis' )
+ global library6
+ library6 = get_library( 'library6', 'library6 description', 'library6 synopsis' )
+ def test_015_add_template_to_library1( self ):
+ """Testing add an inheritable template containing an AddressField to library1"""
+ # Logged in as admin_user
+ # Add a template to library1
+ self.add_library_template( 'library_admin',
+ 'library',
+ self.security.encode_id( library1.id ),
+ self.security.encode_id( AddressField_form.id ),
+ AddressField_form.name )
+ def test_020_add_folder_to_library1( self ):
+ """Testing adding a root folder to library1"""
+ # Logged in as admin_user
+ # Add a root folder to library1
+ folder = library1.root_folder
+ name = "folder"
+ description = "folder description"
+ self.add_folder( 'library_admin',
+ self.security.encode_id( library1.id ),
+ self.security.encode_id( folder.id ),
+ name=name,
+ description=description )
+ global folder1
+ folder1 = get_folder( folder.id, name, description )
+ def test_025_check_library1( self ):
+ """Checking library1 and its root folder"""
+ # Logged in as admin_user
+ self.browse_library( 'library_admin',
+ self.security.encode_id( library1.id ),
+ check_str1=folder1.name,
+ check_str2=folder1.description )
+ # Make sure the template and contents were inherited to folder1
+ self.folder_info( 'library_admin',
+ self.security.encode_id( folder1.id ),
+ self.security.encode_id( library1.id ),
+ check_str1=AddressField_form.name,
+ check_str2='This is an inherited template and is not required to be used with this folder' )
+ def test_030_add_dataset_to_library1_root_folder( self ):
+ """
+ Testing adding a new library dataset to library1's root folder, and adding a new UserAddress
+ on the upload form.
+ """
+ # Logged in as admin_user
+ # The AddressField template should be inherited to the library dataset upload form. Passing
+ # the value 'new' should submit the form via refresh_on_change and allow new UserAddress information
+ # to be posted as part of the upload.
+ self.add_library_dataset( 'library_admin',
+ '1.bed',
+ self.security.encode_id( library1.id ),
+ self.security.encode_id( library1.root_folder.id ),
+ library1.root_folder.name,
+ file_type='bed',
+ dbkey='hg18',
+ root=True,
+ template_refresh_field_name='field_0',
+ template_refresh_field_contents='new',
+ field_0_short_desc='Office',
+ field_0_name='Dick',
+ field_0_institution='PSU',
+ field_0_address='32 O Street',
+ field_0_city='Anywhere',
+ field_0_state='AK',
+ field_0_postal_code='0000000',
+ field_0_country='USA' )
+ global ldda1
+ ldda1 = get_latest_ldda()
+ assert ldda1 is not None, 'Problem retrieving LibraryDatasetDatasetAssociation ldda1 from the database'
+ self.browse_library( 'library_admin',
+ self.security.encode_id( library1.id ),
+ check_str1='1.bed',
+ check_str2=admin_user.email )
+ # Make sure the library template contents were correctly saved
+ self.ldda_edit_info( 'library_admin',
+ self.security.encode_id( library1.id ),
+ self.security.encode_id( library1.root_folder.id ),
+ self.security.encode_id( ldda1.id ),
+ ldda1.name,
+ check_str1='Dick' )
+ def test_035_add_template_to_library2( self ):
+ """ Testing add an inheritable template containing an CheckboxField to library2"""
+ self.add_library_template( 'library_admin',
+ 'library',
+ self.security.encode_id( library2.id ),
+ self.security.encode_id( CheckboxField_form.id ),
+ CheckboxField_form.name )
+ def test_040_add_template_to_library3( self ):
+ """ Testing add an inheritable template containing an SelectField to library3"""
+ self.add_library_template( 'library_admin',
+ 'library',
+ self.security.encode_id( library3.id ),
+ self.security.encode_id( SelectField_form.id ),
+ SelectField_form.name )
+ def test_045_add_template_to_library4( self ):
+ """ Testing add an inheritable template containing an TextArea to library4"""
+ # Add an inheritable template to library4
+ self.add_library_template( 'library_admin',
+ 'library',
+ self.security.encode_id( library4.id ),
+ self.security.encode_id( TextArea_form.id ),
+ TextArea_form.name )
+ def test_050_add_template_to_library5( self ):
+ """ Testing add an inheritable template containing an TextField to library5"""
+ # Add an inheritable template to library5
+ self.add_library_template( 'library_admin',
+ 'library',
+ self.security.encode_id( library5.id ),
+ self.security.encode_id( TextField_form.id ),
+ TextField_form.name )
+ def test_055_add_template_to_library6( self ):
+ """ Testing add an inheritable template containing an WorkflowField to library6"""
+ # Add an inheritable template to library6
+ self.add_library_template( 'library_admin',
+ 'library',
+ self.security.encode_id( library6.id ),
+ self.security.encode_id( WorkflowField_form.id ),
+ WorkflowField_form.name )
+ def test_999_reset_data_for_later_test_runs( self ):
+ """Reseting data to enable later test runs to pass"""
+ # Logged in as admin_user
+ ##################
+ # Delete all form definitions
+ ##################
+ for form in [ AddressField_form, CheckboxField_form, SelectField_form, TextArea_form, TextField_form, WorkflowField_form ]:
+ self.mark_form_deleted( self.security.encode_id( form.form_definition_current.id ) )
+ ##################
+ # Purge all libraries
+ ##################
+ for library in [ library1, library2, library3, library4, library5, library6 ]:
+ self.delete_library_item( 'library_admin',
+ self.security.encode_id( library.id ),
+ self.security.encode_id( library.id ),
+ library.name,
+ item_type='library' )
+ self.purge_library( self.security.encode_id( library.id ), library.name )
+ ##################
+ # Make sure all users are associated only with their private roles
+ ##################
+ for user in [ admin_user, regular_user1, regular_user2, regular_user3 ]:
+ refresh( user )
+ if len( user.roles) != 1:
+ raise AssertionError( '%d UserRoleAssociations are associated with %s ( should be 1 )' % ( len( user.roles ), user.email ) )
+ self.logout()
--- a/lib/galaxy/web/form_builder.py
+++ b/lib/galaxy/web/form_builder.py
@@ -4,12 +4,19 @@ Classes for generating HTML forms
import logging,sys
from cgi import escape
+from galaxy.util import restore_text
+
log = logging.getLogger(__name__)
class BaseField(object):
def get_html( self, prefix="" ):
"""Returns the html widget corresponding to the parameter"""
raise TypeError( "Abstract Method" )
+ def get_disabled_str( self, disabled=False ):
+ if disabled:
+ return 'disabled="disabled"'
+ else:
+ return ''
@staticmethod
def form_field_types():
return ['TextField', 'TextArea', 'SelectField', 'CheckboxField', 'AddressField', 'WorkflowField']
@@ -31,9 +38,9 @@ class TextField(BaseField):
self.name = name
self.size = int( size or 10 )
self.value = value or ""
- def get_html( self, prefix="" ):
- return '<input type="text" name="%s%s" size="%d" value="%s">' \
- % ( prefix, self.name, self.size, escape(str(self.value), quote=True) )
+ def get_html( self, prefix="", disabled=False ):
+ return '<input type="text" name="%s%s" size="%d" value="%s" %s>' \
+ % ( prefix, self.name, self.size, escape( str( self.value ), quote=True ), self.get_disabled_str( disabled ) )
def set_size(self, size):
self.size = int( size )
@@ -52,7 +59,7 @@ class PasswordField(BaseField):
self.value = value or ""
def get_html( self, prefix="" ):
return '<input type="password" name="%s%s" size="%d" value="%s">' \
- % ( prefix, self.name, self.size, escape(str(self.value), quote=True) )
+ % ( prefix, self.name, self.size, escape( str( self.value ), quote=True ) )
def set_size(self, size):
self.size = int( size )
@@ -71,9 +78,9 @@ class TextArea(BaseField):
self.rows = int(self.size[0])
self.cols = int(self.size[-1])
self.value = value or ""
- def get_html( self, prefix="" ):
- return '<textarea name="%s%s" rows="%d" cols="%d">%s</textarea>' \
- % ( prefix, self.name, self.rows, self.cols, escape( str( self.value ), quote=True ) )
+ def get_html( self, prefix="", disabled=False ):
+ return '<textarea name="%s%s" rows="%d" cols="%d" %s>%s</textarea>' \
+ % ( prefix, self.name, self.rows, self.cols, self.get_disabled_str( disabled ), escape( str( self.value ), quote=True ) )
def set_size(self, rows, cols):
self.rows = rows
self.cols = cols
@@ -90,7 +97,7 @@ class CheckboxField(BaseField):
def __init__( self, name, checked=None ):
self.name = name
self.checked = ( checked == True ) or ( isinstance( checked, basestring ) and ( checked.lower() in ( "yes", "true", "on" ) ) )
- def get_html( self, prefix="" ):
+ def get_html( self, prefix="", disabled=False ):
if self.checked:
checked_text = "checked"
else:
@@ -100,8 +107,8 @@ class CheckboxField(BaseField):
# parsing the request, the value 'true' in the hidden field actually means it is NOT checked.
# See the is_checked() method below. The prefix is necessary in each case to ensure functional
# correctness when the param is inside a conditional.
- return '<input type="checkbox" name="%s%s" value="true" %s><input type="hidden" name="%s%s" value="true">' \
- % ( prefix, self.name, checked_text, prefix, self.name )
+ return '<input type="checkbox" name="%s%s" value="true" %s %s><input type="hidden" name="%s%s" value="true" %s>' \
+ % ( prefix, self.name, checked_text, self.get_disabled_str( disabled ), prefix, self.name, self.get_disabled_str( disabled ) )
@staticmethod
def is_checked( value ):
if value == True:
@@ -150,7 +157,7 @@ class HiddenField(BaseField):
self.name = name
self.value = value or ""
def get_html( self, prefix="" ):
- return '<input type="hidden" name="%s%s" value="%s">' % ( prefix, self.name, escape(str(self.value), quote=True) )
+ return '<input type="hidden" name="%s%s" value="%s">' % ( prefix, self.name, escape( str( self.value ), quote=True ) )
class SelectField(BaseField):
"""
@@ -210,14 +217,14 @@ class SelectField(BaseField):
self.refresh_on_change_text = ''
def add_option( self, text, value, selected = False ):
self.options.append( ( text, value, selected ) )
- def get_html( self, prefix="" ):
+ def get_html( self, prefix="", disabled=False ):
if self.display == "checkboxes":
- return self.get_html_checkboxes( prefix )
+ return self.get_html_checkboxes( prefix, disabled )
elif self.display == "radio":
- return self.get_html_radio( prefix )
+ return self.get_html_radio( prefix, disabled )
else:
- return self.get_html_default( prefix )
- def get_html_checkboxes( self, prefix="" ):
+ return self.get_html_default( prefix, disabled )
+ def get_html_checkboxes( self, prefix="", disabled=False ):
rval = []
ctr = 0
if len( self.options ) > 1:
@@ -227,12 +234,14 @@ class SelectField(BaseField):
if len(self.options) > 2 and ctr % 2 == 1:
style = " class=\"odd_row\""
if selected:
- rval.append( '<div%s><input type="checkbox" name="%s%s" value="%s" checked>%s</div>' % ( style, prefix, self.name, escape(str(value), quote=True), text) )
+ rval.append( '<div%s><input type="checkbox" name="%s%s" value="%s" checked %s>%s</div>' % \
+ ( style, prefix, self.name, escape( str( value ), quote=True ), self.get_disabled_str( disabled ), text ) )
else:
- rval.append( '<div%s><input type="checkbox" name="%s%s" value="%s">%s</div>' % ( style, prefix, self.name, escape(str(value), quote=True), text) )
+ rval.append( '<div%s><input type="checkbox" name="%s%s" value="%s" %s>%s</div>' % \
+ ( style, prefix, self.name, escape( str( value ), quote=True ), self.get_disabled_str( disabled ), text ) )
ctr += 1
return "\n".join( rval )
- def get_html_radio( self, prefix="" ):
+ def get_html_radio( self, prefix="", disabled=False ):
rval = []
ctr = 0
for text, value, selected in self.options:
@@ -241,11 +250,20 @@ class SelectField(BaseField):
style = " class=\"odd_row\""
if selected: selected_text = " checked"
else: selected_text = ""
- rval.append( '<div%s><input type="radio" name="%s%s"%s value="%s"%s>%s</div>' % ( style, prefix, self.name, self.refresh_on_change_text, escape(str(value), quote=True), selected_text, text ) )
+ rval.append( '<div%s><input type="radio" name="%s%s"%s value="%s"%s %s>%s</div>' % \
+ ( style,
+ prefix,
+ self.name,
+ self.refresh_on_change_text,
+ escape( str( value ), quote=True ),
+ selected_text,
+ self.get_disabled_str( disabled ),
+ text ) )
ctr += 1
return "\n".join( rval )
- def get_html_default( self, prefix="" ):
- if self.multiple: multiple = " multiple"
+ def get_html_default( self, prefix="", disabled=False ):
+ if self.multiple:
+ multiple = " multiple"
else: multiple = ""
rval = []
last_selected_value = ""
@@ -253,11 +271,13 @@ class SelectField(BaseField):
if selected:
selected_text = " selected"
last_selected_value = value
- else: selected_text = ""
- rval.append( '<option value="%s"%s>%s</option>' % ( escape(str(value), quote=True), selected_text, text ) )
+ else:
+ selected_text = ""
+ rval.append( '<option value="%s"%s>%s</option>' % ( escape( str( value ), quote=True ), selected_text, text ) )
if last_selected_value:
- last_selected_value = ' last_selected_value="%s"' % escape(str(last_selected_value), quote=True)
- rval.insert( 0, '<select name="%s%s"%s%s%s>' % ( prefix, self.name, multiple, self.refresh_on_change_text, last_selected_value ) )
+ last_selected_value = ' last_selected_value="%s"' % escape( str( last_selected_value ), quote=True )
+ rval.insert( 0, '<select name="%s%s"%s%s%s %s>' % \
+ ( prefix, self.name, multiple, self.refresh_on_change_text, last_selected_value, self.get_disabled_str( disabled ), ) )
rval.append( '</select>' )
return "\n".join( rval )
def get_selected(self):
@@ -381,61 +401,71 @@ class DrillDownField( BaseField ):
class AddressField(BaseField):
@staticmethod
def fields():
- return [ ( "short_desc", "Short address description"),
- ( "name", "Name" ),
- ( "institution", "Institution" ),
- ( "address", "Address" ),
- ( "city", "City" ),
- ( "state", "State/Province/Region" ),
- ( "postal_code", "Postal Code" ),
- ( "country", "Country" ),
- ( "phone", "Phone" ) ]
+ return [ ( "short_desc", "Short address description", "Required" ),
+ ( "name", "Name", "Required" ),
+ ( "institution", "Institution", "Required" ),
+ ( "address", "Address", "Required" ),
+ ( "city", "City", "Required" ),
+ ( "state", "State/Province/Region", "Required" ),
+ ( "postal_code", "Postal Code", "Required" ),
+ ( "country", "Country", "Required" ),
+ ( "phone", "Phone", "" ) ]
def __init__(self, name, user=None, value=None, params=None):
self.name = name
self.user = user
self.value = value
self.select_address = None
self.params = params
- def get_html(self):
- from galaxy import util
+ def get_html( self, disabled=False ):
address_html = ''
add_ids = ['none']
if self.user:
for a in self.user.addresses:
- add_ids.append(str(a.id))
- add_ids.append('new')
- self.select_address = SelectField(self.name,
- refresh_on_change=True,
- refresh_on_change_values=add_ids)
+ add_ids.append( str( a.id ) )
+ add_ids.append( 'new' )
+ self.select_address = SelectField( self.name,
+ refresh_on_change=True,
+ refresh_on_change_values=add_ids )
if self.value == 'none':
- self.select_address.add_option('Select one', 'none', selected=True)
+ self.select_address.add_option( 'Select one', 'none', selected=True )
else:
- self.select_address.add_option('Select one', 'none')
+ self.select_address.add_option( 'Select one', 'none' )
if self.user:
for a in self.user.addresses:
if not a.deleted:
- if self.value == str(a.id):
- self.select_address.add_option(a.desc, str(a.id), selected=True)
- # display this address
- address_html = '''<div class="form-row">
- %s
- </div>''' % a.get_html()
+ if self.value == str( a.id ):
+ self.select_address.add_option( a.desc, str( a.id ), selected=True )
+ # Display this address
+ address_html += '''
+ <div class="form-row">
+ %s
+ </div>
+ ''' % a.get_html()
else:
- self.select_address.add_option(a.desc, str(a.id))
+ self.select_address.add_option( a.desc, str( a.id ) )
if self.value == 'new':
- self.select_address.add_option('Add a new address', 'new', selected=True)
- for field_name, label in self.fields():
- add_field = TextField(self.name+'_'+field_name,
+ self.select_address.add_option( 'Add a new address', 'new', selected=True )
+ for field_name, label, help_text in self.fields():
+ add_field = TextField( self.name + '_' + field_name,
40,
- util.restore_text( self.params.get( self.name+'_'+field_name, '' ) ))
- address_html += ''' <div class="form-row">
- <label>%s</label>
+ restore_text( self.params.get( self.name + '_' + field_name, '' ) ) )
+ address_html += '''
+ <div class="form-row">
+ <label>%s</label>
+ %s
+ ''' % ( label, add_field.get_html( disabled=disabled ) )
+ if help_text:
+ address_html += '''
+ <div class="toolParamHelp" style="clear: both;">
%s
</div>
- ''' % (label, add_field.get_html())
+ ''' % help_text
+ address_html += '''
+ </div>
+ '''
else:
- self.select_address.add_option('Add a new address', 'new')
- return self.select_address.get_html()+address_html
+ self.select_address.add_option( 'Add a new address', 'new' )
+ return self.select_address.get_html( disabled=disabled ) + address_html
class WorkflowField(BaseField):
def __init__(self, name, user=None, value=None, params=None):
@@ -444,21 +474,20 @@ class WorkflowField(BaseField):
self.value = value
self.select_workflow = None
self.params = params
- def get_html(self):
- self.select_workflow = SelectField(self.name)
+ def get_html( self, disabled=False ):
+ self.select_workflow = SelectField( self.name )
if self.value == 'none':
- self.select_workflow.add_option('Select one', 'none', selected=True)
+ self.select_workflow.add_option( 'Select one', 'none', selected=True )
else:
- self.select_workflow.add_option('Select one', 'none')
+ self.select_workflow.add_option( 'Select one', 'none' )
if self.user:
for a in self.user.stored_workflows:
if not a.deleted:
- if str(self.value) == str(a.id):
- self.select_workflow.add_option(a.name, str(a.id), selected=True)
+ if str( self.value ) == str( a.id ):
+ self.select_workflow.add_option( a.name, str( a.id ), selected=True )
else:
- self.select_workflow.add_option(a.name, str(a.id))
- return self.select_workflow.get_html()
-
+ self.select_workflow.add_option( a.name, str( a.id ) )
+ return self.select_workflow.get_html( disabled=disabled )
def get_suite():
"""Get unittest suite for this module"""
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -313,9 +313,9 @@ class UsesFormDefinitionWidgets:
return True
if isinstance( field[ 'widget' ], CheckboxField ) and field[ 'widget' ].checked:
return True
- if isinstance( field[ 'widget' ], WorkflowField ) and field[ 'widget' ].value not in [ 'none', 'None', None ]:
+ if isinstance( field[ 'widget' ], WorkflowField ) and str( field[ 'widget' ].value ).lower() not in [ 'none' ]:
return True
- if isinstance( field[ 'widget' ], AddressField ) and field[ 'widget' ].value not in [ 'none', 'None', None ]:
+ if isinstance( field[ 'widget' ], AddressField ) and str( field[ 'widget' ].value ).lower() not in [ 'none' ]:
return True
return False
def clean_field_contents( self, widgets, **kwd ):
@@ -332,9 +332,24 @@ class UsesFormDefinitionWidgets:
field_value = widget.value
field_contents.append( util.restore_text( field_value ) )
return field_contents
+ def field_param_values_ok( self, index, widget_type, **kwd ):
+ # Make sure required fields have contents, etc
+ # TODO: Add support for other field types ( e.g., WorkflowField, etc )
+ params = util.Params( kwd )
+ if widget_type == 'AddressField':
+ if not util.restore_text( params.get( 'field_%i_short_desc' % index, '' ) ) \
+ or not util.restore_text( params.get( 'field_%i_name' % index, '' ) ) \
+ or not util.restore_text( params.get( 'field_%i_institution' % index, '' ) ) \
+ or not util.restore_text( params.get( 'field_%i_address' % index, '' ) ) \
+ or not util.restore_text( params.get( 'field_%i_city' % index, '' ) ) \
+ or not util.restore_text( params.get( 'field_%i_state' % index, '' ) ) \
+ or not util.restore_text( params.get( 'field_%i_postal_code' % index, '' ) ) \
+ or not util.restore_text( params.get( 'field_%i_country' % index, '' ) ):
+ return False
+ return True
def save_widget_field( self, trans, field_obj, index, **kwd ):
# Save a form_builder field object
- # TODO: Add support for other field types ( e.g., WorkflowField )
+ # TODO: Add support for other field types ( e.g., WorkflowField, etc )
params = util.Params( kwd )
if isinstance( field_obj, trans.model.UserAddress ):
field_obj.desc = util.restore_text( params.get( 'field_%i_short_desc' % index, '' ) )
@@ -1227,6 +1242,7 @@ class Admin( object ):
# - Dataset where HistoryDatasetAssociation.dataset_id = Dataset.id
# - UserGroupAssociation where user_id == User.id
# - UserRoleAssociation where user_id == User.id EXCEPT FOR THE PRIVATE ROLE
+ # - UserAddress where user_id == User.id
# Purging Histories and Datasets must be handled via the cleanup_datasets.py script
webapp = kwd.get( 'webapp', 'galaxy' )
id = kwd.get( 'id', None )
@@ -1271,6 +1287,9 @@ class Admin( object ):
for ura in user.roles:
if ura.role_id != private_role.id:
trans.sa_session.delete( ura )
+ # Delete UserAddresses
+ for address in user.addresses:
+ trans.sa_session.delete( address )
# Purge the user
user.purged = True
trans.sa_session.add( user )
--- a/templates/library/common/upload.mako
+++ b/templates/library/common/upload.mako
@@ -12,8 +12,32 @@
%><%def name="javascripts()">
+ ${h.js("jquery.autocomplete", "autocomplete_tagging" )}
${parent.javascripts()}
- ${h.js("jquery.autocomplete", "autocomplete_tagging" )}
+ <script type="text/javascript">
+ $( function() {
+ $( "select[refresh_on_change='true']").change( function() {
+ var refresh = false;
+ var refresh_on_change_values = $( this )[0].attributes.getNamedItem( 'refresh_on_change_values' )
+ if ( refresh_on_change_values ) {
+ refresh_on_change_values = refresh_on_change_values.value.split( ',' );
+ var last_selected_value = $( this )[0].attributes.getNamedItem( 'last_selected_value' );
+ for( i= 0; i < refresh_on_change_values.length; i++ ) {
+ if ( $( this )[0].value == refresh_on_change_values[i] || ( last_selected_value && last_selected_value.value == refresh_on_change_values[i] ) ){
+ refresh = true;
+ break;
+ }
+ }
+ }
+ else {
+ refresh = true;
+ }
+ if ( refresh ){
+ $( "#upload_library_dataset" ).submit();
+ }
+ });
+ });
+ </script></%def><%def name="stylesheets()">
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -862,7 +862,8 @@ class Library( object ):
# inherited is not applicable at the library level. The get_contents
# param is passed by callers that are inheriting a template - these
# are usually new library datsets for which we want to include template
- # fields on the upload form, but not the contents of the inherited template.
+ # fields on the upload form, but not necessarily the contents of the
+ # inherited template saved for the parent.
info_association, inherited = self.get_info_association()
if info_association:
template = info_association.template
@@ -939,7 +940,8 @@ class LibraryFolder( object ):
# See if we have any associated templates. The get_contents
# param is passed by callers that are inheriting a template - these
# are usually new library datsets for which we want to include template
- # fields on the upload form.
+ # fields on the upload form, but not necessarily the contents of the
+ # inherited template saved for the parent.
info_association, inherited = self.get_info_association()
if info_association:
if inherited:
@@ -948,7 +950,12 @@ class LibraryFolder( object ):
template = info_association.template
# See if we have any field contents, but only if the info_association was
# not inherited ( we do not want to display the inherited contents ).
- if not inherited and get_contents:
+ # (gvk: 8/30/10) Based on conversations with Dan, we agreed to ALWAYS inherit
+ # contents. We'll use this behavior until we hear from the community that
+ # contents should not be inherited. If we don't hear anything for a while,
+ # eliminate the old commented out behavior.
+ #if not inherited and get_contents:
+ if get_contents:
info = info_association.info
if info:
return template.get_widgets( trans.user, info.content )
@@ -1160,7 +1167,8 @@ class LibraryDatasetDatasetAssociation(
# See if we have any associated templatesThe get_contents
# param is passed by callers that are inheriting a template - these
# are usually new library datsets for which we want to include template
- # fields on the upload form.
+ # fields on the upload form, but not necessarily the contents of the
+ # inherited template saved for the parent.
info_association, inherited = self.get_info_association()
if info_association:
if inherited:
@@ -1169,7 +1177,12 @@ class LibraryDatasetDatasetAssociation(
template = info_association.template
# See if we have any field contents, but only if the info_association was
# not inherited ( we do not want to display the inherited contents ).
- if not inherited and get_contents:
+ # (gvk: 8/30/10) Based on conversations with Dan, we agreed to ALWAYS inherit
+ # contents. We'll use this behavior until we hear from the community that
+ # contents should not be inherited. If we don't hear anything for a while,
+ # eliminate the old commented out behavior.
+ #if not inherited and get_contents:
+ if get_contents:
info = info_association.info
if info:
return template.get_widgets( trans.user, info.content )
--- a/test/functional/test_user_info.py
+++ b/test/functional/test_user_info.py
@@ -126,7 +126,7 @@ class TestUserInfo( TwillTestCase ):
self.check_page_for_string( "Manage User Information" )
self.check_page_for_string( user_info_values[0] )
self.check_page_for_string( user_info_values[1] )
- self.check_page_for_string( '<input type="checkbox" name="field_2" value="true" checked>' )
+ self.check_page_for_string( '<input type="checkbox" name="field_2" value="true" checked >' )
def test_015_user_reqistration_single_user_info_forms( self ):
''' Testing user registration with a single user info form '''
# Logged in as regular_user_11
@@ -155,7 +155,7 @@ class TestUserInfo( TwillTestCase ):
self.check_page_for_string( "Manage User Information" )
self.check_page_for_string( user_info_values[0] )
self.check_page_for_string( user_info_values[1] )
- self.check_page_for_string( '<input type="checkbox" name="field_2" value="true" checked>' )
+ self.check_page_for_string( '<input type="checkbox" name="field_2" value="true" checked >' )
def test_020_edit_user_info( self ):
"""Testing editing user info as a regular user"""
# Logged in as regular_user_12
@@ -179,32 +179,23 @@ class TestUserInfo( TwillTestCase ):
# Test editing the user info
self.edit_user_info( ['Research', 'PSU'] )
def test_999_reset_data_for_later_test_runs( self ):
+ """Reseting data to enable later test runs to pass"""
# Logged in as regular_user_12
self.logout()
self.login( email=admin_user.email )
+ ##################
+ # Mark all forms deleted
+ ##################
+ for form_name in [ form_one_name ]:
+ form = get_form( form_name )
+ mark_form_deleted( form )
###############
- # Mark form_one as deleted ( form_two was marked deleted earlier )
+ # Purge appropriate users
###############
- form_latest = get_form( form_one_name )
- mark_form_deleted( form_latest )
- ###############
- # Manually delete the test_user11
- ###############
- self.mark_user_deleted( user_id=self.security.encode_id( regular_user11.id ), email=regular_user11.email )
- refresh( regular_user11 )
- self.purge_user( self.security.encode_id( regular_user11.id ), regular_user11.email )
- refresh( regular_user11 )
- # We should now only the the user and his private role
- delete_user_roles( regular_user11 )
- delete_obj( regular_user11 )
- ###############
- # Manually delete the test_user12
- ###############
- refresh( regular_user12 )
- self.mark_user_deleted( user_id=self.security.encode_id( regular_user12.id ), email=regular_user12.email )
- refresh( regular_user12 )
- self.purge_user( self.security.encode_id( regular_user12.id ), regular_user12.email )
- refresh( regular_user12 )
- # We should now only the the user and his private role
- delete_user_roles( regular_user12 )
- delete_obj( regular_user12 )
+ for user in [ regular_user11, regular_user12 ]:
+ self.mark_user_deleted( user_id=self.security.encode_id( user.id ), email=user.email )
+ refresh( user )
+ self.purge_user( self.security.encode_id( user.id ), user.email )
+ refresh( user )
+ delete_user_roles( user )
+ delete_obj( user )
--- a/templates/library/common/select_template.mako
+++ b/templates/library/common/select_template.mako
@@ -66,13 +66,18 @@
<input type="submit" name="add_template_button" value="Add template to ${item_desc}"/></div></form>
- %if template_select_list.get_selected() != ('Select one', 'none'):
- <div style="clear: both"></div>
+ </div>
+</div>
+<p/>
+%if template_select_list.get_selected() != ('Select one', 'none'):
+ <div class="toolForm">
+ <div class="toolFormTitle">Layout of selected template</div>
+ <div class="toolFormBody"><div class="form-row">
%for i, field in enumerate( widgets ):
<div class="form-row"><label>${field[ 'label' ]}</label>
- ${field[ 'widget' ].get_html()}
+ ${field[ 'widget' ].get_html( disabled=True )}
<div class="toolParamHelp" style="clear: both;">
${field[ 'helptext' ]}
</div>
@@ -80,6 +85,6 @@
</div>
%endfor
</div>
- %endif
+ </div></div>
-</div>
+%endif
--- a/test/base/twilltestcase.py
+++ b/test/base/twilltestcase.py
@@ -1406,6 +1406,45 @@ class TwillTestCase( unittest.TestCase )
self.check_page_for_string( desc )
self.check_page_for_string( formtype )
self.home()
+ # Form stuff
+ def create_single_field_type_form_definition( self, name, desc, formtype, field_type ):
+ """
+ Create a new form definition containing 1 field of a specified type ( AddressField, CheckboxField, SelectField,
+ TextArea, TextField, WorkflowField ). The form_type param value should not be 'Sequencing Sample Form,' use
+ create_form() above for that.
+ """
+ self.home()
+ # Create a new form definition
+ self.visit_url( "%s/forms/new" % self.url )
+ self.check_page_for_string( 'Create a new form definition' )
+ tc.fv( "1", "name", name )
+ tc.fv( "1", "description", desc )
+ tc.fv( "1", "form_type_selectbox", formtype )
+ tc.submit( "create_form_button" )
+ # Add 1 AddressField to the new form definition
+ field_name = 'field_name_0'
+ field_contents = field_type
+ field_help_name = 'field_helptext_0'
+ field_help_contents = '%s help' % field_type
+ field_default = 'field_default_0'
+ field_default_contents = '%s default contents' % field_type
+ tc.fv( "1", field_name, field_contents )
+ tc.fv( "1", field_help_name, field_help_contents )
+ self.refresh_form( 'field_type_0', field_type )
+ if field_type == 'SelectField':
+ # Add 2 options so our select list is functional
+ tc.submit( "addoption_0" )
+ tc.fv( "1", "field_0_option_0", "One" )
+ tc.submit( "addoption_0" )
+ tc.fv( "1", "field_0_option_1", "Two" )
+ tc.fv( "1", field_default, field_default_contents )
+ tc.submit( "save_changes_button" )
+ self.home()
+ self.visit_url( "%s/forms/manage" % self.url )
+ self.check_page_for_string( name )
+ self.check_page_for_string( desc )
+ self.check_page_for_string( formtype )
+ self.home()
def edit_form( self, form_current_id, form_name, new_form_name="Form One's Name (Renamed)", new_form_desc="This is Form One's description (Re-described)"):
"""
Edit form details; name & description
@@ -1459,6 +1498,15 @@ class TwillTestCase( unittest.TestCase )
check_str = "The form '%s' has been updated with the changes." % form_name
self.check_page_for_string( check_str )
self.home()
+ def mark_form_deleted( self, form_id ):
+ """Mark a form_definition as deleted"""
+ self.home()
+ url = "%s/forms/manage?operation=delete&id=%s" % ( self.url, form_id )
+ self.visit_url( url )
+ check_str = "1 form(s) is deleted."
+ self.check_page_for_string( check_str )
+ self.home()
+
# Requests stuff
def check_request_grid(self, state, request_name, deleted=False):
self.home()
@@ -1603,7 +1651,11 @@ class TwillTestCase( unittest.TestCase )
# Library stuff
def add_library_template( self, cntrller, item_type, library_id, form_id, form_name, folder_id=None, ldda_id=None ):
- """Add a new info template to a library item"""
+ """
+ Add a new info template to a library item - the template will ALWAYS BE SET TO INHERITABLE here. If you want to
+ dis-inherit your template, call the manage_library_template_inheritance() below immediately after you call this
+ method in your test code.
+ """
self.home()
if item_type == 'library':
url = "%s/library_common/add_template?cntrller=%s&item_type=%s&library_id=%s" % \
@@ -1616,11 +1668,31 @@ class TwillTestCase( unittest.TestCase )
( self.url, cntrller, item_type, library_id, folder_id, ldda_id )
self.visit_url( url )
self.check_page_for_string ( "Select a template for the" )
- tc.fv( '1', 'form_id', form_id )
- tc.fv( '1', 'inherit', '1' )
- tc.submit( 'add_template_button' )
+ self.refresh_form( "form_id", form_id )
+ # For some unknown reason, twill barfs if the form number ( 1 ) is used in the following
+ # rather than the form anme ( select_template ), so we have to use the form name.
+ tc.fv( "select_template", "inheritable", '1' )
+ tc.submit( "add_template_button" )
self.check_page_for_string = 'A template based on the form "%s" has been added to this' % form_name
self.home()
+ def manage_library_template_inheritance( self, cntrller, item_type, library_id, folder_id=None, ldda_id=None, inheritable=True ):
+ # If inheritable is True, the item is currently inheritable.
+ self.home()
+ if item_type == 'library':
+ url = "%s/library_common/manage_template_inheritance?cntrller=%s&item_type=%s&library_id=%s" % \
+ ( self.url, cntrller, item_type, library_id )
+ elif item_type == 'folder':
+ url = "%s/library_common/manage_template_inheritance?cntrller=%s&item_type=%s&library_id=%s&folder_id=%s" % \
+ ( self.url, cntrller, item_type, library_id, folder_id )
+ elif item_type == 'ldda':
+ url = "%s/library_common/manage_template_inheritance?cntrller=%s&item_type=%s&library_id=%s&folder_id=%s&ldda_id=%s" % \
+ ( self.url, cntrller, item_type, library_id, folder_id, ldda_id )
+ self.visit_url( url )
+ if inheritable:
+ self.check_page_for_string = 'will no longer be inherited to contained folders and datasets'
+ else:
+ self.check_page_for_string = 'will now be inherited to contained folders and datasets'
+ self.home()
def browse_libraries_admin( self, deleted=False, check_str1='', check_str2='', not_displayed1='' ):
self.visit_url( '%s/library_admin/browse_libraries?sort=name&f-description=All&f-name=All&f-deleted=%s' % ( self.url, str( deleted ) ) )
if check_str1:
@@ -1718,13 +1790,14 @@ class TwillTestCase( unittest.TestCase )
self.home()
# Library folder stuff
- def add_folder( self, controller, library_id, folder_id, name='Folder One', description='This is Folder One' ):
+ def add_folder( self, cntrller, library_id, folder_id, name='Folder One', description='This is Folder One' ):
"""Create a new folder"""
self.home()
- self.visit_url( "%s/library_common/create_folder?cntrller=%s&library_id=%s&parent_id=%s" % ( self.url, controller, library_id, folder_id ) )
+ url = "%s/library_common/create_folder?cntrller=%s&library_id=%s&parent_id=%s" % ( self.url, cntrller, library_id, folder_id )
+ self.visit_url( url )
self.check_page_for_string( 'Create a new folder' )
- tc.fv( "1", "name", name ) # form field 1 is the field named name...
- tc.fv( "1", "description", description ) # form field 2 is the field named description...
+ tc.fv( "1", "name", name )
+ tc.fv( "1", "description", description )
tc.submit( "new_folder_button" )
check_str = "The new folder named '%s' has been added to the data library." % name
self.check_page_for_string( check_str )
@@ -1765,14 +1838,32 @@ class TwillTestCase( unittest.TestCase )
# Library dataset stuff
def add_library_dataset( self, cntrller, filename, library_id, folder_id, folder_name,
file_type='auto', dbkey='hg18', roles=[], message='', root=False,
- template_field_name1='', template_field_contents1='', show_deleted='False',
- upload_option='upload_file' ):
+ template_field_name1='', template_field_contents1='',
+ template_refresh_field_name='', template_refresh_field_contents='',
+ field_0_short_desc='', field_0_name='', field_0_institution='',
+ field_0_address='', field_0_city='', field_0_state='', field_0_postal_code='',
+ field_0_country='', show_deleted='False', upload_option='upload_file' ):
"""Add a dataset to a folder"""
filename = self.get_filename( filename )
self.home()
self.visit_url( "%s/library_common/upload_library_dataset?cntrller=%s&library_id=%s&folder_id=%s&upload_option=%s&message=%s" % \
( self.url, cntrller, library_id, folder_id, upload_option, message.replace( ' ', '+' ) ) )
self.check_page_for_string( 'Upload files' )
+ # A template containing an AddressField may be displayed on the upload form.
+ # If this is the case, we need to refresh the form with the passeed tmplate_field_name1.
+ if template_refresh_field_name and template_refresh_field_contents:
+ self.refresh_form( template_refresh_field_name, template_refresh_field_contents )
+ tc.fv( "1", "field_0_short_desc", field_0_short_desc )
+ tc.fv( "1", "field_0_name", field_0_name )
+ tc.fv( "1", "field_0_institution", field_0_institution )
+ tc.fv( "1", "field_0_address", field_0_address )
+ tc.fv( "1", "field_0_city", field_0_city )
+ tc.fv( "1", "field_0_state", field_0_state )
+ tc.fv( "1", "field_0_postal_code", field_0_postal_code )
+ tc.fv( "1", "field_0_country", field_0_country )
+ # Add template field contents, if any...
+ if template_field_name1:
+ tc.fv( "1", template_field_name1, template_field_contents1 )
tc.fv( "1", "library_id", library_id )
tc.fv( "1", "folder_id", folder_id )
tc.fv( "1", "show_deleted", show_deleted )
@@ -1782,9 +1873,6 @@ class TwillTestCase( unittest.TestCase )
tc.fv( "1", "message", message.replace( '+', ' ' ) )
for role_id in roles:
tc.fv( "1", "roles", role_id )
- # Add template field contents, if any...
- if template_field_name1:
- tc.fv( "1", template_field_name1, template_field_contents1 )
tc.submit( "runtool_btn" )
if root:
check_str = "Added 1 datasets to the library '%s' (each is selected)." % folder_name
--- a/templates/library/common/common.mako
+++ b/templates/library/common/common.mako
@@ -22,7 +22,7 @@
has_contents = True
label = field[ 'label' ]
value = 'checked'
- elif isinstance( field[ 'widget' ], WorkflowField ) and field[ 'widget' ].value not in [ 'none', 'None', None ]:
+ elif isinstance( field[ 'widget' ], WorkflowField ) and str( field[ 'widget' ].value ).lower() not in [ 'none' ]:
has_contents = True
label = field[ 'label' ]
widget = field[ 'widget' ]
@@ -35,7 +35,7 @@
else:
# If we didn't find the selected workflow option above, we'll just print the value
value = field[ 'widget' ].value
- elif isinstance( field[ 'widget' ], AddressField ) and field[ 'widget' ].value not in [ 'none', 'None', None ]:
+ elif isinstance( field[ 'widget' ], AddressField ) and str( field[ 'widget' ].value ).lower() not in [ 'none' ]:
has_contents = True
widget = field[ 'widget' ]
address = trans.sa_session.query( trans.model.UserAddress ).get( int( widget.value ) )
@@ -69,71 +69,77 @@
else:
can_modify = False
%>
- %if widgets:
- %if editable and can_modify:
- <p/>
- <div class="toolForm">
- <div class="toolFormTitle">
- %if inherited:
- Other information <i>- this is an inherited template and is not required to be used with this ${item_type}</i>
- %else:
- Other information
- %endif
- %if info_association and not inherited and can_modify:
+ %if editable and can_modify:
+ <p/>
+ <div class="toolForm">
+ <div class="toolFormTitle">Other information
+ <a id="item-${item.id}-popup" class="popup-arrow" style="display: none;">▼</a>
+ <div popupmenu="item-${item.id}-popup">
+ %if info_association and inherited and can_modify:
## "inherited" will be true only if the info_association is not associated with the current item,
- ## in which case we do not want to render the following popup menu.
- <a id="item-${item.id}-popup" class="popup-arrow" style="display: none;">▼</a>
- <div popupmenu="item-${item.id}-popup">
- <a class="action-button" href="${h.url_for( controller='library_common', action='edit_template', cntrller=cntrller, item_type=item_type, library_id=library_id, folder_id=folder_id, ldda_id=ldda_id, show_deleted=show_deleted )}">Edit template</a>
- <a class="action-button" href="${h.url_for( controller='library_common', action='delete_template', cntrller=cntrller, item_type=item_type, library_id=library_id, folder_id=folder_id, ldda_id=ldda_id, show_deleted=show_deleted )}">Delete template</a>
- %if item_type not in [ 'ldda', 'library_dataset' ]:
- %if info_association.inheritable:
- <a class="action-button" href="${h.url_for( controller='library_common', action='manage_template_inheritance', cntrller=cntrller, item_type=item_type, library_id=library_id, folder_id=folder_id, ldda_id=ldda_id, show_deleted=show_deleted )}">Dis-inherit template</a>
- %else:
- <a class="action-button" href="${h.url_for( controller='library_common', action='manage_template_inheritance', cntrller=cntrller, item_type=item_type, library_id=library_id, folder_id=folder_id, ldda_id=ldda_id, show_deleted=show_deleted )}">Inherit template</a>
- %endif
+ ## which means that the currently display template has not yet been saved for the current item.
+ <a class="action-button" href="${h.url_for( controller='library_common', action='add_template', cntrller=cntrller, item_type=item_type, library_id=library_id, folder_id=folder_id, ldda_id=ldda_id, show_deleted=show_deleted )}">Select a different template</a>
+ %elif info_association and not inherited and can_modify:
+ <a class="action-button" href="${h.url_for( controller='library_common', action='edit_template', cntrller=cntrller, item_type=item_type, library_id=library_id, folder_id=folder_id, ldda_id=ldda_id, show_deleted=show_deleted )}">Edit template</a>
+ <a class="action-button" href="${h.url_for( controller='library_common', action='delete_template', cntrller=cntrller, item_type=item_type, library_id=library_id, folder_id=folder_id, ldda_id=ldda_id, show_deleted=show_deleted )}">Delete template</a>
+ %if item_type not in [ 'ldda', 'library_dataset' ]:
+ %if info_association.inheritable:
+ <a class="action-button" href="${h.url_for( controller='library_common', action='manage_template_inheritance', cntrller=cntrller, item_type=item_type, library_id=library_id, folder_id=folder_id, ldda_id=ldda_id, show_deleted=show_deleted )}">Dis-inherit template</a>
+ %else:
+ <a class="action-button" href="${h.url_for( controller='library_common', action='manage_template_inheritance', cntrller=cntrller, item_type=item_type, library_id=library_id, folder_id=folder_id, ldda_id=ldda_id, show_deleted=show_deleted )}">Inherit template</a>
%endif
- </div>
+ %endif
%endif
</div>
- <div class="toolFormBody">
- <form name="edit_info" id="edit_info" action="${h.url_for( controller='library_common', action='edit_template_info', cntrller=cntrller, item_type=item_type, library_id=library_id, folder_id=folder_id, ldda_id=ldda_id, show_deleted=show_deleted )}" method="post">
- %for i, field in enumerate( widgets ):
- <div class="form-row">
- <label>${field[ 'label' ]}</label>
- ${field[ 'widget' ].get_html()}
- <div class="toolParamHelp" style="clear: both;">
- ${field[ 'helptext' ]}
- </div>
- <div style="clear: both"></div>
+ </div>
+ <div class="toolFormBody">
+ %if inherited:
+ <div class="form-row">
+ <font color="red">
+ <b>
+ This is an inherited template and is not required to be used with this ${item_type}. You can
+ <a href="${h.url_for( controller='library_common', action='add_template', cntrller=cntrller, item_type=item_type, library_id=library_id, folder_id=folder_id, ldda_id=ldda_id, show_deleted=show_deleted )}"><font color="red">select a different template</font></a>
+ or fill in the desired fields and save this one. This template will not be assocaiated with this ${item_type} until you click the Save button.
+ </b>
+ </font>
+ </div>
+ %endif
+ <form name="edit_info" id="edit_info" action="${h.url_for( controller='library_common', action='edit_template_info', cntrller=cntrller, item_type=item_type, library_id=library_id, folder_id=folder_id, ldda_id=ldda_id, show_deleted=show_deleted )}" method="post">
+ %for i, field in enumerate( widgets ):
+ <div class="form-row">
+ <label>${field[ 'label' ]}</label>
+ ${field[ 'widget' ].get_html()}
+ <div class="toolParamHelp" style="clear: both;">
+ ${field[ 'helptext' ]}
</div>
- %endfor
- <div class="form-row">
- <input type="submit" name="edit_info_button" value="Save"/>
+ <div style="clear: both"></div></div>
- </form>
- </div>
+ %endfor
+ <div class="form-row">
+ <input type="submit" name="edit_info_button" value="Save"/>
+ </div>
+ </form></div>
- <p/>
- %elif widget_fields_have_contents:
- <p/>
- <div class="toolForm">
- <div class="toolFormTitle">Other information about ${item.name}</div>
- <div class="toolFormBody">
- %for i, field in enumerate( widgets ):
- ${render_template_field( field )}
- %endfor
- </div>
+ </div>
+ <p/>
+ %elif widget_fields_have_contents:
+ <p/>
+ <div class="toolForm">
+ <div class="toolFormTitle">Other information about ${item.name}</div>
+ <div class="toolFormBody">
+ %for i, field in enumerate( widgets ):
+ ${render_template_field( field )}
+ %endfor
</div>
- <p/>
- %endif
+ </div>
+ <p/>
%endif
</%def><%def name="render_upload_form( cntrller, upload_option, action, library_id, folder_id, replace_dataset, file_formats, dbkeys, widgets, roles, history, show_deleted )"><% import os, os.path %>
%if upload_option in [ 'upload_file', 'upload_directory', 'upload_paths' ]:
- <div class="toolForm" id="upload_library_dataset">
+ <div class="toolForm" id="upload_library_dataset_tool_form">
%if upload_option == 'upload_directory':
<div class="toolFormTitle">Upload a directory of files</div>
%elif upload_option == 'upload_paths':
@@ -142,7 +148,7 @@
<div class="toolFormTitle">Upload files</div>
%endif
<div class="toolFormBody">
- <form name="upload_library_dataset" action="${action}" enctype="multipart/form-data" method="post">
+ <form name="upload_library_dataset" id="upload_library_dataset" action="${action}" enctype="multipart/form-data" method="post"><input type="hidden" name="tool_id" value="upload1"/><input type="hidden" name="tool_state" value="None"/><input type="hidden" name="cntrller" value="${cntrller}"/>
--- a/lib/galaxy/web/controllers/library_common.py
+++ b/lib/galaxy/web/controllers/library_common.py
@@ -7,6 +7,7 @@ from galaxy.util.json import to_json_str
from galaxy.tools.actions import upload_common
from galaxy.model.orm import *
from galaxy.util.streamball import StreamBall
+from galaxy.web.form_builder import AddressField, CheckboxField, SelectField, TextArea, TextField, WorkflowField
import logging, tempfile, zipfile, tarfile, os, sys
if sys.version_info[:2] < ( 2, 6 ):
@@ -943,7 +944,7 @@ class LibraryCommon( BaseController, Use
# Check to see if the user selected roles to associate with the DATASET_ACCESS permission
# on the dataset that would cause accessibility issues.
roles = params.get( 'roles', False )
- error = None
+ error = False
if upload_option == 'upload_paths' and not trans.app.config.allow_library_path_paste:
error = True
message = '"allow_library_path_paste" is not defined in the Galaxy configuration file'
@@ -966,11 +967,41 @@ class LibraryCommon( BaseController, Use
status='error' ) )
else:
- # See if we have any inherited templates, but do not inherit contents.
+ # See if we have any inherited templates.
info_association, inherited = folder.get_info_association( inherited=True )
if info_association and info_association.inheritable:
template_id = str( info_association.template.id )
- widgets = folder.get_template_widgets( trans, get_contents=False )
+ widgets = folder.get_template_widgets( trans, get_contents=True )
+ processed_widgets = []
+ # The list of widgets may include an AddressField which we need to save if it is new
+ for index, widget_dict in enumerate( widgets ):
+ widget = widget_dict[ 'widget' ]
+ if isinstance( widget, AddressField ):
+ value = util.restore_text( params.get( 'field_%i' % index, '' ) )
+ if value == 'new':
+ if self.field_param_values_ok( index, 'AddressField', **kwd ):
+ # Save the new address
+ address = trans.app.model.UserAddress( user=trans.user )
+ self.save_widget_field( trans, address, index, **kwd )
+ widget.value = str( address.id )
+ widget_dict[ 'widget' ] = widget
+ processed_widgets.append( widget_dict )
+ # FIXME: ( hack ) It is now critical to update the value of 'field_%i', replacing the string
+ # 'new' with the new address id. This is necessary because the upload_dataset()
+ # method below calls the handle_library_params() method, which does not parse the
+ # widget fields, it instead pulls form values from kwd. See the FIXME comments in the
+ # handle_library_params() method...
+ kwd[ 'field_%i' % index ] = str( address.id )
+ else:
+ # The invalid address won't be saved, but we cannot dispaly error
+ # messages on the upload form due to the ajax upload already occurring.
+ # When we re-engineer the upload process ( currently under way ), we
+ # will be able to check the form values before the ajax upload occurs
+ # in the background. For now, we'll do nothing...
+ pass
+ else:
+ processed_widgets.append( widget_dict )
+ widgets = processed_widgets
else:
template_id = 'None'
widgets = []
@@ -1039,10 +1070,34 @@ class LibraryCommon( BaseController, Use
show_deleted=show_deleted,
message=util.sanitize_text( message ),
status=status ) )
- # See if we have any inherited templates, but do not inherit contents.
+ # Note: if the upload form was submitted due to refresh_on_demand for a form field, we cannot re-populate
+ # the field for the selected file ( files_0|file_data ) if the user selected one. This is because the value
+ # attribute of the html input file type field is typically ignored by browsers as a security precaution.
+
+ # See if we have any inherited templates.
info_association, inherited = folder.get_info_association( inherited=True )
if info_association and info_association.inheritable:
- widgets = folder.get_template_widgets( trans, get_contents=False )
+ widgets = folder.get_template_widgets( trans, get_contents=True )
+ # Handle form submission via refresh_on_change by keeping the contents of widget fields
+ populated_widgets = []
+ for index, widget_dict in enumerate( widgets ):
+ widget = widget_dict[ 'widget' ]
+ if isinstance( widget, AddressField ):
+ value = util.restore_text( params.get( 'field_%i' % index, '' ) )
+ if value:
+ if value == 'new':
+ # Adding a new address
+ widget.value = value
+ widget_dict[ 'widget' ] = widget
+ elif value == 'none':
+ widget.value = ''
+ widget_dict[ 'widget' ] = widget
+ else:
+ # An existing address object was selected
+ address_obj = trans.sa_session.query( trans.app.model.UserAddress ).get( int( value ) )
+ widget_dict[ 'widget' ] = address_obj
+ populated_widgets.append( widget_dict )
+ widgets = populated_widgets
else:
widgets = []
upload_option = params.get( 'upload_option', 'upload_file' )
@@ -1132,6 +1187,8 @@ class LibraryCommon( BaseController, Use
message = '"allow_library_path_paste" is not defined in the Galaxy configuration file'
# Some error handling should be added to this method.
try:
+ # FIXME: instead of passing params here ( chiech have been process by util.Params(), the original kwd
+ # should be passed so that complex objects that may have been included in the initial request remain.
library_bunch = upload_common.handle_library_params( trans, params, folder_id, replace_dataset )
except:
response_code = 500
@@ -2174,10 +2231,23 @@ class LibraryCommon( BaseController, Use
value = util.restore_text( params.get( 'field_%i' % index, '' ) )
if value == 'new':
if params.get( 'edit_info_button', False ):
- # Save the new address
- address = trans.app.model.UserAddress( user=trans.user )
- self.save_widget_field( trans, address, index, **kwd )
- widget.value = str( address.id )
+ if self.field_param_values_ok( index, 'AddressField', **kwd ):
+ # Save the new address
+ address = trans.app.model.UserAddress( user=trans.user )
+ self.save_widget_field( trans, address, index, **kwd )
+ widget.value = str( address.id )
+ else:
+ message = 'Required fields are missing contents.'
+ return trans.response.send_redirect( web.url_for( controller='library_common',
+ action=action,
+ cntrller=cntrller,
+ use_panels=use_panels,
+ library_id=library_id,
+ folder_id=folder_id,
+ id=id,
+ show_deleted=show_deleted,
+ message=util.sanitize_text( message ),
+ status='error' ) )
else:
# Form was submitted via refresh_on_change
widget.value = 'new'
--- a/templates/library/common/library_dataset_info.mako
+++ b/templates/library/common/library_dataset_info.mako
@@ -90,6 +90,5 @@
%endif
%if widgets:
- ## Templates are not currently supported for library_datasets, only the associated ldda.
${render_template_fields( cntrller, 'library_dataset', library_id, widgets, widget_fields_have_contents, info_association=None, inherited=False, editable=False )}
%endif
--- a/lib/galaxy/tools/actions/upload_common.py
+++ b/lib/galaxy/tools/actions/upload_common.py
@@ -35,6 +35,9 @@ def persist_uploads( params ):
params['files'] = new_files
return params
def handle_library_params( trans, params, folder_id, replace_dataset=None ):
+ # FIXME: the received params has already been parsed by util.Params() by the time it reaches here,
+ # so no complex objects remain. This is not good because it does not allow for those objects to be
+ # manipulated here. The receivd params should be the original kwd from the initial request.
library_bunch = util.bunch.Bunch()
library_bunch.replace_dataset = replace_dataset
library_bunch.message = params.get( 'message', '' )
@@ -42,9 +45,8 @@ def handle_library_params( trans, params
library_bunch.template_field_contents = []
template_id = params.get( 'template_id', None )
library_bunch.folder = trans.sa_session.query( trans.app.model.LibraryFolder ).get( trans.security.decode_id( folder_id ) )
- # We are inheriting the folder's info_association, so we did not
- # receive any inherited contents, but we may have redirected here
- # after the user entered template contents ( due to errors ).
+ # We are inheriting the folder's info_association, so we may have received inherited contents or we may have redirected
+ # here after the user entered template contents ( due to errors ).
if template_id not in [ None, 'None' ]:
library_bunch.template = trans.sa_session.query( trans.app.model.FormDefinition ).get( template_id )
for field_index in range( len( library_bunch.template.fields ) ):
--- a/lib/galaxy/web/controllers/tool_runner.py
+++ b/lib/galaxy/web/controllers/tool_runner.py
@@ -179,6 +179,8 @@ class ToolRunner( BaseController ):
replace_dataset = trans.sa_session.query( trans.app.model.LibraryDataset ).get( trans.security.decode_id( replace_id ) )
else:
replace_dataset = None
+ # FIXME: instead of passing params here ( chiech have been process by util.Params(), the original kwd
+ # should be passed so that complex objects that may have been included in the initial request remain.
library_bunch = upload_common.handle_library_params( trans, nonfile_params, nonfile_params.folder_id, replace_dataset )
else:
library_bunch = None
1
0
galaxy-dist commit 368956bcef26: Standardize mouseover behavior for UI tabs.
by commits-noreply@bitbucket.org 08 Sep '10
by commits-noreply@bitbucket.org 08 Sep '10
08 Sep '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User jeremy goecks <jeremy.goecks(a)emory.edu>
# Date 1283444597 14400
# Node ID 368956bcef26af16b4f7694fb8f81fb6152cf6de
# Parent 833cfa90b33735f4f30f10d0d7e39cbf1a64d6d9
Standardize mouseover behavior for UI tabs.
--- a/templates/webapps/galaxy/base_panels.mako
+++ b/templates/webapps/galaxy/base_panels.mako
@@ -30,7 +30,7 @@
%if href:
<a target="${target}" href="${href}">${display}</a>
%else:
- ${display}
+ <a>${display}</a>
%endif
%if menu_options:
<div class="submenu">
1
0