galaxy-commits
Threads by month
- ----- 2026 -----
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 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
- 15302 discussions
commit/galaxy-central: guerler: Grids: Reduce mako templating to json generation, introduce GridsView, bug fixes
by commits-noreply@bitbucket.org 17 Nov '13
by commits-noreply@bitbucket.org 17 Nov '13
17 Nov '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/f1cef709a9e5/
Changeset: f1cef709a9e5
User: guerler
Date: 2013-11-17 11:08:25
Summary: Grids: Reduce mako templating to json generation, introduce GridsView, bug fixes
iG: changed templates/webapps/galaxy/tracks/history_select_grid.mako
Affected #: 14 files
diff -r 5e534cc8da856ad598d63b8b9f03fe20629df05f -r f1cef709a9e5631cae2126ffff71dbba64611f87 lib/galaxy/web/framework/helpers/grids.py
--- a/lib/galaxy/web/framework/helpers/grids.py
+++ b/lib/galaxy/web/framework/helpers/grids.py
@@ -321,7 +321,7 @@
class GridColumn( object ):
def __init__( self, label, key=None, model_class=None, method=None, format=None, \
- link=None, attach_popup=False, visible=True, ncells=1, nowrap=False, \
+ link=None, attach_popup=False, visible=True, nowrap=False, \
# Valid values for filterable are ['standard', 'advanced', None]
filterable=None, sortable=True, label_id_prefix=None ):
"""Create a grid column."""
@@ -334,7 +334,6 @@
self.nowrap = nowrap
self.attach_popup = attach_popup
self.visible = visible
- self.ncells = ncells
self.filterable = filterable
# Column must have a key to be sortable.
self.sortable = ( self.key is not None and sortable )
diff -r 5e534cc8da856ad598d63b8b9f03fe20629df05f -r f1cef709a9e5631cae2126ffff71dbba64611f87 lib/galaxy/webapps/galaxy/controllers/dataset.py
--- a/lib/galaxy/webapps/galaxy/controllers/dataset.py
+++ b/lib/galaxy/webapps/galaxy/controllers/dataset.py
@@ -100,7 +100,7 @@
grids.TextColumn( "Name", key="name",
# Link name to dataset's history.
link=( lambda item: iff( item.history.deleted, None, dict( operation="switch", id=item.id ) ) ), filterable="advanced", attach_popup=True ),
- HistoryColumn( "History", key="history",
+ HistoryColumn( "History", key="history", sortable=False,
link=( lambda item: iff( item.history.deleted, None, dict( operation="switch_history", id=item.id ) ) ) ),
grids.IndividualTagsColumn( "Tags", key="tags", model_tag_association_class=model.HistoryDatasetAssociationTagAssociation, filterable="advanced", grid_name="HistoryDatasetAssocationListGrid" ),
StatusColumn( "Status", key="deleted", attach_popup=False ),
@@ -113,11 +113,12 @@
key="free-text-search", visible=False, filterable="standard" )
)
operations = [
- grids.GridOperation( "Copy to current history", condition=( lambda item: not item.deleted ), async_compatible=False ),
+ grids.GridOperation( "Copy to current history", condition=( lambda item: not item.deleted ), async_compatible=True ),
]
standard_filters = []
default_filter = dict( name="All", deleted="False", tags="All" )
preserve_state = False
+ use_async = True
use_paging = True
num_rows_per_page = 50
def build_initial_query( self, trans, **kwargs ):
diff -r 5e534cc8da856ad598d63b8b9f03fe20629df05f -r f1cef709a9e5631cae2126ffff71dbba64611f87 lib/galaxy/webapps/galaxy/controllers/history.py
--- a/lib/galaxy/webapps/galaxy/controllers/history.py
+++ b/lib/galaxy/webapps/galaxy/controllers/history.py
@@ -30,16 +30,13 @@
def get_value( self, trans, grid, history ):
state_count_dict = self.get_hda_state_counts( trans, history )
- rval = []
+ rval = ''
for state in ( 'ok', 'running', 'queued', 'error' ):
count = state_count_dict.get( state, 0 )
if count:
- rval.append( '<div class="count-box state-color-%s">%s</div>' % ( state, count ) )
- else:
- rval.append( '' )
+ rval += '<div class="count-box state-color-%s">%s</div>' % (state, count)
return rval
-
class HistoryListNameColumn( NameColumn ):
def get_link( self, trans, grid, history ):
link = None
@@ -72,7 +69,7 @@
default_sort_key = "-update_time"
columns = [
HistoryListNameColumn( "Name", key="name", attach_popup=True, filterable="advanced" ),
- DatasetsByStateColumn( "Datasets", key="datasets_by_state", ncells=4, sortable=False ),
+ DatasetsByStateColumn( "Datasets", key="datasets_by_state", sortable=False ),
grids.IndividualTagsColumn( "Tags", key="tags", model_tag_association_class=model.HistoryTagAssociation, \
filterable="advanced", grid_name="HistoryListGrid" ),
grids.SharingStatusColumn( "Sharing", key="sharing", filterable="advanced", sortable=False ),
@@ -118,13 +115,11 @@
# Custom column types
class DatasetsByStateColumn( grids.GridColumn ):
def get_value( self, trans, grid, history ):
- rval = []
+ rval = ''
for state in ( 'ok', 'running', 'queued', 'error' ):
total = sum( 1 for d in history.active_datasets if d.state == state )
if total:
- rval.append( '<div class="count-box state-color-%s">%s</div>' % ( state, total ) )
- else:
- rval.append( '' )
+ rval += '<div class="count-box state-color-%s">%s</div>' % ( state, total )
return rval
class SharedByColumn( grids.GridColumn ):
@@ -138,7 +133,7 @@
default_filter = {}
columns = [
grids.GridColumn( "Name", key="name", attach_popup=True ), # link=( lambda item: dict( operation="View", id=item.id ) ), attach_popup=True ),
- DatasetsByStateColumn( "Datasets", ncells=4, sortable=False ),
+ DatasetsByStateColumn( "Datasets", sortable=False ),
grids.GridColumn( "Created", key="create_time", format=time_ago ),
grids.GridColumn( "Last Updated", key="update_time", format=time_ago ),
SharedByColumn( "Shared by", key="user_id" )
diff -r 5e534cc8da856ad598d63b8b9f03fe20629df05f -r f1cef709a9e5631cae2126ffff71dbba64611f87 lib/galaxy/webapps/galaxy/controllers/visualization.py
--- a/lib/galaxy/webapps/galaxy/controllers/visualization.py
+++ b/lib/galaxy/webapps/galaxy/controllers/visualization.py
@@ -147,11 +147,11 @@
# Grid definition.
title = "Insert into visualization"
template = "/tracks/add_to_viz.mako"
- async_template = "/page/select_items_grid_async.mako"
model_class = model.Visualization
default_sort_key = "-update_time"
use_async = True
use_paging = False
+ show_item_checkboxes = True
columns = [
grids.TextColumn( "Title", key="title", model_class=model.Visualization, filterable="standard" ),
grids.TextColumn( "Dbkey", key="dbkey", model_class=model.Visualization ),
diff -r 5e534cc8da856ad598d63b8b9f03fe20629df05f -r f1cef709a9e5631cae2126ffff71dbba64611f87 static/scripts/galaxy.grids.js
--- a/static/scripts/galaxy.grids.js
+++ b/static/scripts/galaxy.grids.js
@@ -119,433 +119,456 @@
}
// Add filter arguments to data, placing "f-" in front of all arguments.
- // FIXME: when underscore updated, use pairs function().
var self = this;
- _.each(_.keys(self.attributes.filters), function(k) {
- url_data['f-' + k] = self.attributes.filters[k];
+ _.each(_.pairs(self.attributes.filters), function(k) {
+ url_data['f-' + k[0]] = k[1];
});
return url_data;
}
});
-//
-// Code to handle grid operations: filtering, sorting, paging, and operations.
-//
+// grid view
+var GridView = Backbone.View.extend({
-// Initialize grid controls
-function init_grid_controls() {
- // Initialize submit image elements.
- $('.submit-image').each( function() {
- // On mousedown, add class to simulate click.
- $(this).mousedown( function() {
- $(this).addClass('gray-background');
+ // model
+ grid: null,
+
+ // Initialize
+ initialize: function(grid)
+ {
+ this.grid = grid;
+ this.init_grid_elements();
+ this.init_grid_controls();
+
+ // Initialize text filters to select text on click and use normal font when user is typing.
+ $('input[type=text]').each(function() {
+ $(this).click(function() { $(this).select(); } )
+ .keyup(function () { $(this).css("font-style", "normal"); });
+ });
+ },
+
+ // Initialize grid controls
+ init_grid_controls: function() {
+ // Initialize submit image elements.
+ $('.submit-image').each( function() {
+ // On mousedown, add class to simulate click.
+ $(this).mousedown( function() {
+ $(this).addClass('gray-background');
+ });
+
+ // On mouseup, add class to simulate click.
+ $(this).mouseup( function() {
+ $(this).removeClass('gray-background');
+ });
});
- // On mouseup, add class to simulate click.
- $(this).mouseup( function() {
- $(this).removeClass('gray-background');
+ // link
+ var self = this;
+
+ // Initialize sort links.
+ $('.sort-link').each( function() {
+ $(this).click( function() {
+ self.set_sort_condition( $(this).attr('sort_key') );
+ return false;
+ });
});
- });
+
+ // Initialize page links.
+ $('.page-link > a').each( function() {
+ $(this).click( function() {
+ self.set_page( $(this).attr('page_num') );
+ return false;
+ });
+ });
+
+ // Initialize categorical filters.
+ $('.categorical-filter > a').each( function() {
+ $(this).click( function() {
+ self.set_categorical_filter( $(this).attr('filter_key'), $(this).attr('filter_val') );
+ return false;
+ });
+ });
+
+ // Initialize text filters.
+ $('.text-filter-form').each( function() {
+ $(this).submit( function() {
+ var column_key = $(this).attr('column_key');
+ var text_input_obj = $('#input-' + column_key + '-filter');
+ var text_input = text_input_obj.val();
+ text_input_obj.val('');
+ self.add_filter_condition(column_key, text_input, true);
+ return false;
+ });
+ });
+
+ // Initialize autocomplete for text inputs in search UI.
+ var t = $("#input-tags-filter");
+ if (t.length) {
+ t.autocomplete(this.grid.history_tag_autocomplete_url,
+ { selectFirst: false, autoFill: false, highlight: false, mustMatch: false });
+ }
+
+ var t2 = $("#input-name-filter");
+ if (t2.length) {
+ t2.autocomplete(this.grid.history_name_autocomplete_url,
+ { selectFirst: false, autoFill: false, highlight: false, mustMatch: false });
+ }
+
+ // Initialize standard, advanced search toggles.
+ $('.advanced-search-toggle').each( function() {
+ $(this).click( function() {
+ $("#standard-search").slideToggle('fast');
+ $('#advanced-search').slideToggle('fast');
+ return false;
+ });
+ });
+ },
+
+ // Initialize grid elements.
+ init_grid_elements : function() {
- // Initialize sort links.
- $('.sort-link').each( function() {
- $(this).click( function() {
- set_sort_condition( $(this).attr('sort_key') );
- return false;
+ // Initialize grid selection checkboxes.
+ $(".grid").each( function() {
+ var checkboxes = $(this).find("input.grid-row-select-checkbox");
+ var check_count = $(this).find("span.grid-selected-count");
+ var update_checked = function() {
+ check_count.text( $(checkboxes).filter(":checked").length );
+ };
+
+ $(checkboxes).each( function() {
+ $(this).change(update_checked);
+ });
+ update_checked();
});
- });
-
- // Initialize page links.
- $('.page-link > a').each( function() {
- $(this).click( function() {
- set_page( $(this).attr('page_num') );
- return false;
+
+ // Initialize item labels.
+ var self = this;
+ $(".label").each( function() {
+ // If href has an operation in it, do operation when clicked. Otherwise do nothing.
+ var href = $(this).attr('href');
+ if ( href !== undefined && href.indexOf('operation=') != -1 ) {
+ $(this).click( function() {
+ self.do_operation_from_href( $(this).attr('href') );
+ return false;
+ });
+ }
});
- });
+
+ // Initialize ratings.
+ if ($('.community_rating_star').length !== 0)
+ $('.community_rating_star').rating({});
+
+ // Initialize item menu operations.
+ make_popup_menus();
+ },
- // Initialize categorical filters.
- $('.categorical-filter > a').each( function() {
- $(this).click( function() {
- set_categorical_filter( $(this).attr('filter_key'), $(this).attr('filter_val') );
+ // Go back to page one; this is useful when a filter is applied.
+ go_page_one: function () {
+ // Need to go back to page 1 if not showing all.
+ var cur_page = this.grid.get('cur_page');
+ if (cur_page !== null && cur_page !== undefined && cur_page !== 'all') {
+ this.grid.set('cur_page', 1);
+ }
+ },
+
+ // Add a condition to the grid filter; this adds the condition and refreshes the grid.
+ add_filter_condition: function (name, value, append) {
+ // Do nothing is value is empty.
+ if (value === "") {
return false;
+ }
+
+ // Add condition to grid.
+ this.grid.add_filter(name, value, append);
+
+ // Add button that displays filter and provides a button to delete it.
+ var t = $("<span>" + value + "<a href='javascript:void(0);'><span class='delete-search-icon' /></a></span>");
+ t.addClass('text-filter-val');
+ var self = this;
+ t.click(function() {
+ // Remove filter condition.
+ self.grid.remove_filter(name, value);
+
+ // Remove visible element.
+ $(this).remove();
+
+ self.go_page_one();
+ self.update_grid();
});
- });
-
- // Initialize text filters.
- $('.text-filter-form').each( function() {
- $(this).submit( function() {
- var column_key = $(this).attr('column_key');
- var text_input_obj = $('#input-' + column_key + '-filter');
- var text_input = text_input_obj.val();
- text_input_obj.val('');
- add_filter_condition(column_key, text_input, true);
+
+ var container = $('#' + name + "-filtering-criteria");
+ container.append(t);
+
+ this.go_page_one();
+ this.update_grid();
+ },
+
+ // Set sort condition for grid.
+ set_sort_condition: function (col_key) {
+ // Set new sort condition. New sort is col_key if sorting new column; if reversing sort on
+ // currently sorted column, sort is reversed.
+ var cur_sort = this.grid.get('sort_key');
+ var new_sort = col_key;
+ if (cur_sort.indexOf(col_key) !== -1) {
+ // Reverse sort.
+ if (cur_sort.substring(0,1) !== '-') {
+ new_sort = '-' + col_key;
+ } else {
+ // Sort reversed by using just col_key.
+ }
+ }
+
+ // Remove sort arrows elements.
+ $('.sort-arrow').remove();
+
+ // Add sort arrow element to new sort column.
+ var sort_arrow = (new_sort.substring(0,1) == '-') ? "↑" : "↓";
+ var t = $("<span>" + sort_arrow + "</span>").addClass('sort-arrow');
+ var th = $("#" + col_key + '-header');
+ th.append(t);
+
+ // Update grid.
+ this.grid.set('sort_key', new_sort);
+ this.go_page_one();
+ this.update_grid();
+ },
+
+ // Set new value for categorical filter.
+ set_categorical_filter: function (name, new_value) {
+ // Update filter hyperlinks to reflect new filter value.
+ var category_filter = this.grid.get('categorical_filters')[name],
+ cur_value = this.grid.get('filters')[name];
+ var self = this;
+ $("." + name + "-filter").each( function() {
+ var text = $.trim( $(this).text() );
+ var filter = category_filter[text];
+ var filter_value = filter[name];
+ if (filter_value == new_value) {
+ // Remove filter link since grid will be using this filter. It is assumed that
+ // this element has a single child, a hyperlink/anchor with text.
+ $(this).empty();
+ $(this).addClass("current-filter");
+ $(this).append(text);
+ } else if (filter_value == cur_value) {
+ // Add hyperlink for this filter since grid will no longer be using this filter. It is assumed that
+ // this element has a single child, a hyperlink/anchor.
+ $(this).empty();
+ var t = $("<a href='#'>" + text + "</a>");
+ t.click(function() {
+ self.set_categorical_filter( name, filter_value );
+ });
+ $(this).removeClass("current-filter");
+ $(this).append(t);
+ }
+ });
+
+ // Update grid.
+ this.grid.add_filter(name, new_value);
+ this.go_page_one();
+ this.update_grid();
+ },
+
+ // Set page to view.
+ set_page: function (new_page) {
+ // Update page hyperlink to reflect new page.
+ var self = this;
+ $(".page-link").each( function() {
+ var id = $(this).attr('id'),
+ page_num = parseInt( id.split("-")[2], 10 ), // Id has form 'page-link-<page_num>
+ cur_page = self.grid.get('cur_page'),
+ text;
+ if (page_num === new_page) {
+ // Remove link to page since grid will be on this page. It is assumed that
+ // this element has a single child, a hyperlink/anchor with text.
+ text = $(this).children().text();
+ $(this).empty();
+ $(this).addClass("inactive-link");
+ $(this).text(text);
+ }
+ else if (page_num === cur_page) {
+ // Add hyperlink to this page since grid will no longer be on this page. It is assumed that
+ // this element has a single child, a hyperlink/anchor.
+ text = $(this).text();
+ $(this).empty();
+ $(this).removeClass("inactive-link");
+ var t = $("<a href='#'>" + text + "</a>");
+ t.click(function() {
+ set_page(page_num);
+ });
+ $(this).append(t);
+ }
+ });
+
+ var maintain_page_links = true;
+ if (new_page === "all") {
+ this.grid.set('cur_page', new_page);
+ maintain_page_links = false;
+ } else {
+ this.grid.set('cur_page', parseInt(new_page, 10));
+ }
+ this.update_grid(maintain_page_links);
+ },
+
+ // Perform a grid operation.
+ do_operation: function (operation, item_ids) {
+ operation = operation.toLowerCase();
+
+ // Update grid.
+ this.grid.set({
+ operation: operation,
+ item_ids: item_ids
+ });
+
+ // Do operation. If operation cannot be performed asynchronously, redirect to location.
+ if (this.grid.can_async_op(operation)) {
+ this.update_grid(true);
+ }
+ else {
+ this.go_to_URL();
+ }
+ },
+
+ // Perform a hyperlink click that initiates an operation. If there is no operation, ignore click.
+ do_operation_from_href: function (href) {
+ // Get operation, id in hyperlink's href.
+ var href_parts = href.split("?");
+ if (href_parts.length > 1) {
+ var href_parms_str = href_parts[1];
+ var href_parms = href_parms_str.split("&");
+ var operation = null;
+ var id = -1;
+ for (var index = 0; index < href_parms.length; index++) {
+ if (href_parms[index].indexOf('operation') != -1) {
+ // Found operation parm; get operation value.
+ operation = href_parms[index].split('=')[1];
+ } else if (href_parms[index].indexOf('id') != -1) {
+ // Found id parm; get id value.
+ id = href_parms[index].split('=')[1];
+ }
+ }
+ // Do operation.
+ this.do_operation(operation, id);
return false;
+ }
+ },
+
+ // Navigate window to the URL defined by url_args. This method can be used to short-circuit grid AJAXing.
+ go_to_URL: function () {
+ // Not async request.
+ this.grid.set('async', false);
+
+ // Go.
+ window.location = this.grid.get('url_base') + "?" + $.param(this.grid.get_url_data());
+
+ // Clear grid of transient request attributes.
+ this.grid.set({
+ operation: undefined,
+ item_ids: undefined
});
- });
-
- // Initialize autocomplete for text inputs in search UI.
- var t = $("#input-tags-filter");
- if (t.length) {
- t.autocomplete(history_tag_autocomplete_url,
- { selectFirst: false, autoFill: false, highlight: false, mustMatch: false });
- }
-
- var t2 = $("#input-name-filter");
- if (t2.length) {
- t2.autocomplete(history_name_autocomplete_url,
- { selectFirst: false, autoFill: false, highlight: false, mustMatch: false });
- }
-
- // Initialize standard, advanced search toggles.
- $('.advanced-search-toggle').each( function() {
- $(this).click( function() {
- $("#standard-search").slideToggle('fast');
- $('#advanced-search').slideToggle('fast');
- return false;
- });
- });
-}
-
-// Initialize grid elements.
-function init_grid_elements() {
- // Initialize grid selection checkboxes.
- $(".grid").each( function() {
- var checkboxes = $(this).find("input.grid-row-select-checkbox");
- var check_count = $(this).find("span.grid-selected-count");
- var update_checked = function() {
- check_count.text( $(checkboxes).filter(":checked").length );
- };
-
- $(checkboxes).each( function() {
- $(this).change(update_checked);
- });
- update_checked();
- });
-
- // Initialize item labels.
- $(".label").each( function() {
- // If href has an operation in it, do operation when clicked. Otherwise do nothing.
- var href = $(this).attr('href');
- if ( href !== undefined && href.indexOf('operation=') != -1 ) {
- $(this).click( function() {
- do_operation_from_href( $(this).attr('href') );
- return false;
- });
- }
- });
-
- // Initialize ratings.
- if ($('.community_rating_star').length !== 0)
- $('.community_rating_star').rating({});
-
- // Initialize item menu operations.
- make_popup_menus();
-}
-
-// Go back to page one; this is useful when a filter is applied.
-function go_page_one() {
- // Need to go back to page 1 if not showing all.
- var cur_page = grid.get('cur_page');
- if (cur_page !== null && cur_page !== undefined && cur_page !== 'all') {
- grid.set('cur_page', 1);
- }
-}
-
-// Add a condition to the grid filter; this adds the condition and refreshes the grid.
-function add_filter_condition(name, value, append) {
- // Do nothing is value is empty.
- if (value === "") {
- return false;
- }
-
- // Add condition to grid.
- grid.add_filter(name, value, append);
-
- // Add button that displays filter and provides a button to delete it.
- var t = $("<span>" + value + "<a href='javascript:void(0);'><span class='delete-search-icon' /></a></span>");
- t.addClass('text-filter-val');
- t.click(function() {
- // Remove filter condition.
- grid.remove_filter(name, value);
-
- // Remove visible element.
- $(this).remove();
-
- go_page_one();
- update_grid();
- });
-
- var container = $('#' + name + "-filtering-criteria");
- container.append(t);
-
- go_page_one();
- update_grid();
-}
-
-// Add tag to grid filter.
-function add_tag_to_grid_filter(tag_name, tag_value) {
- // Put tag name and value together.
- var tag = tag_name + (tag_value !== undefined && tag_value !== "" ? ":" + tag_value : "");
- $('#advanced-search').show('fast');
- add_filter_condition("tags", tag, true);
-}
-
-// Set sort condition for grid.
-function set_sort_condition(col_key) {
- // Set new sort condition. New sort is col_key if sorting new column; if reversing sort on
- // currently sorted column, sort is reversed.
- var cur_sort = grid.get('sort_key');
- var new_sort = col_key;
- if (cur_sort.indexOf(col_key) !== -1) {
- // Reverse sort.
- if (cur_sort.substring(0,1) !== '-') {
- new_sort = '-' + col_key;
- } else {
- // Sort reversed by using just col_key.
- }
- }
-
- // Remove sort arrows elements.
- $('.sort-arrow').remove();
-
- // Add sort arrow element to new sort column.
- var sort_arrow = (new_sort.substring(0,1) == '-') ? "↑" : "↓";
- var t = $("<span>" + sort_arrow + "</span>").addClass('sort-arrow');
- var th = $("#" + col_key + '-header');
- th.append(t);
-
- // Update grid.
- grid.set('sort_key', new_sort);
- go_page_one();
- update_grid();
-}
-
-// Set new value for categorical filter.
-function set_categorical_filter(name, new_value) {
- // Update filter hyperlinks to reflect new filter value.
- var category_filter = grid.get('categorical_filters')[name],
- cur_value = grid.get('filters')[name];
- $("." + name + "-filter").each( function() {
- var text = $.trim( $(this).text() );
- var filter = category_filter[text];
- var filter_value = filter[name];
- if (filter_value == new_value) {
- // Remove filter link since grid will be using this filter. It is assumed that
- // this element has a single child, a hyperlink/anchor with text.
- $(this).empty();
- $(this).addClass("current-filter");
- $(this).append(text);
- } else if (filter_value == cur_value) {
- // Add hyperlink for this filter since grid will no longer be using this filter. It is assumed that
- // this element has a single child, a hyperlink/anchor.
- $(this).empty();
- var t = $("<a href='#'>" + text + "</a>");
- t.click(function() {
- set_categorical_filter( name, filter_value );
- });
- $(this).removeClass("current-filter");
- $(this).append(t);
- }
- });
-
- // Update grid.
- grid.add_filter(name, new_value);
- go_page_one();
- update_grid();
-}
-
-// Set page to view.
-function set_page(new_page) {
- // Update page hyperlink to reflect new page.
- $(".page-link").each( function() {
- var id = $(this).attr('id'),
- page_num = parseInt( id.split("-")[2], 10 ), // Id has form 'page-link-<page_num>
- cur_page = grid.get('cur_page'),
- text;
- if (page_num === new_page) {
- // Remove link to page since grid will be on this page. It is assumed that
- // this element has a single child, a hyperlink/anchor with text.
- text = $(this).children().text();
- $(this).empty();
- $(this).addClass("inactive-link");
- $(this).text(text);
- }
- else if (page_num === cur_page) {
- // Add hyperlink to this page since grid will no longer be on this page. It is assumed that
- // this element has a single child, a hyperlink/anchor.
- text = $(this).text();
- $(this).empty();
- $(this).removeClass("inactive-link");
- var t = $("<a href='#'>" + text + "</a>");
- t.click(function() {
- set_page(page_num);
- });
- $(this).append(t);
- }
- });
-
- var maintain_page_links = true;
- if (new_page === "all") {
- grid.set('cur_page', new_page);
- maintain_page_links = false;
- } else {
- grid.set('cur_page', parseInt(new_page, 10));
- }
- update_grid(maintain_page_links);
-}
-
-// Perform a grid operation.
-function do_operation(operation, item_ids) {
- operation = operation.toLowerCase();
+ },
// Update grid.
- grid.set({
- operation: operation,
- item_ids: item_ids
- });
-
- // Do operation. If operation cannot be performed asynchronously, redirect to location.
- if (grid.can_async_op(operation)) {
- update_grid(true);
- }
- else {
- go_to_URL();
- }
-}
+ update_grid: function (maintain_page_links) {
+ // If grid is not using async, then go to URL.
+ if (!this.grid.get('async')) {
+ this.go_to_URL();
+ return;
+ }
-// Perform a hyperlink click that initiates an operation. If there is no operation, ignore click.
-function do_operation_from_href(href) {
- // Get operation, id in hyperlink's href.
- var href_parts = href.split("?");
- if (href_parts.length > 1) {
- var href_parms_str = href_parts[1];
- var href_parms = href_parms_str.split("&");
- var operation = null;
- var id = -1;
- for (var index = 0; index < href_parms.length; index++) {
- if (href_parms[index].indexOf('operation') != -1) {
- // Found operation parm; get operation value.
- operation = href_parms[index].split('=')[1];
- } else if (href_parms[index].indexOf('id') != -1) {
- // Found id parm; get id value.
- id = href_parms[index].split('=')[1];
+ // If there's an operation, do POST; otherwise, do GET.
+ var method = (this.grid.get('operation') ? "POST" : "GET" );
+ $('.loading-elt-overlay').show(); // Show overlay to indicate loading and prevent user actions.
+ var self = this;
+ $.ajax({
+ type: method,
+ url: self.grid.get('url_base'),
+ data: self.grid.get_url_data(),
+ error: function() { alert( "Grid refresh failed" ); },
+ success: function(response_text) {
+ // HACK: use a simple string to separate the elements in the
+ // response: (1) table body; (2) number of pages in table; and (3) message.
+ var parsed_response_text = response_text.split("*****");
+
+ // Update grid body and footer.
+ $('#grid-table-body').html(parsed_response_text[0]);
+ // FIXME: this does not work at all; what's needed is a function
+ // that updates page links when number of pages changes.
+ $('#grid-table-footer').html(parsed_response_text[1]);
+
+ // Trigger custom event to indicate grid body has changed.
+ $('#grid-table-body').trigger('update');
+
+ // Init grid.
+ self.init_grid_elements();
+ make_popup_menus();
+
+ // Hide loading overlay.
+ $('.loading-elt-overlay').hide();
+
+ // Show message if there is one.
+ var message = $.trim( parsed_response_text[2] );
+ if (message !== "") {
+ $('#grid-message').html( message ).show();
+ setTimeout( function() { $('#grid-message').hide(); }, 5000);
+ }
+ },
+ complete: function() {
+ // Clear grid of transient request attributes.
+ self.grid.set({
+ operation: undefined,
+ item_ids: undefined
+ });
+ }
+ });
+ },
+
+ check_all_items: function () {
+ var chk_all = document.getElementById('check_all'),
+ checks = document.getElementsByTagName('input'),
+ total = 0,
+ i;
+ if ( chk_all.checked === true ) {
+ for ( i=0; i < checks.length; i++ ) {
+ if ( checks[i].name.indexOf( 'id' ) !== -1) {
+ checks[i].checked = true;
+ total++;
+ }
}
}
- // Do operation.
- do_operation(operation, id);
- return false;
- }
-}
+ else {
+ for ( i=0; i < checks.length; i++ ) {
+ if ( checks[i].name.indexOf( 'id' ) !== -1) {
+ checks[i].checked = false;
+ }
-// Navigate window to the URL defined by url_args. This method can be used to short-circuit grid AJAXing.
-function go_to_URL() {
- // Not async request.
- grid.set('async', false);
-
- // Go.
- window.location = grid.get('url_base') + "?" + $.param(grid.get_url_data());
-}
-
-// Update grid.
-function update_grid(maintain_page_links) {
- // If grid is not using async, then go to URL.
- if (!grid.get('async')) {
- go_to_URL();
- return;
- }
-
- // If there's an operation, do POST; otherwise, do GET.
- var method = (grid.get('operation') ? "POST" : "GET" );
- $('.loading-elt-overlay').show(); // Show overlay to indicate loading and prevent user actions.
- $.ajax({
- type: method,
- url: grid.get('url_base'),
- data: grid.get_url_data(),
- error: function() { alert( "Grid refresh failed" ); },
- success: function(response_text) {
- // HACK: use a simple string to separate the elements in the
- // response: (1) table body; (2) number of pages in table; and (3) message.
- var parsed_response_text = response_text.split("*****");
-
- // Update grid body and footer.
- $('#grid-table-body').html(parsed_response_text[0]);
- // FIXME: this does not work at all; what's needed is a function
- // that updates page links when number of pages changes.
- $('#grid-table-footer').html(parsed_response_text[1]);
-
- // Trigger custom event to indicate grid body has changed.
- $('#grid-table-body').trigger('update');
-
- // Init grid.
- init_grid_elements();
- make_popup_menus();
-
- // Hide loading overlay.
- $('.loading-elt-overlay').hide();
-
- // Show message if there is one.
- var message = $.trim( parsed_response_text[2] );
- if (message !== "") {
- $('#grid-message').html( message ).show();
- setTimeout( function() { $('#grid-message').hide(); }, 5000);
- }
- },
- complete: function() {
- // Clear grid of transient request attributes.
- grid.set({
- operation: undefined,
- item_ids: undefined
- });
- }
- });
-}
-
-function check_all_items() {
- var chk_all = document.getElementById('check_all'),
- checks = document.getElementsByTagName('input'),
- total = 0,
- i;
- if ( chk_all.checked === true ) {
- for ( i=0; i < checks.length; i++ ) {
- if ( checks[i].name.indexOf( 'id' ) !== -1) {
- checks[i].checked = true;
- total++;
}
}
+ this.init_grid_elements();
+ },
+
+ // confirmation/submission of operation request
+ submit_operation: function (selected_button, confirmation_text)
+ {
+ // verify in any item is selected
+ var number_of_checked_ids = $('input[name="id"]:checked').length;
+ if (!number_of_checked_ids > 0)
+ return false;
+
+ // show confirmation box
+ if (confirmation_text != 'None' && confirmation_text != '')
+ if(!confirm(confirmation_text))
+ return false;
+
+ // collect ids
+ var operation_name = $(selected_button).val();
+ var item_ids = [];
+ $('input[name=id]:checked').each(function() {
+ item_ids.push( $(this).val() );
+ });
+ this.do_operation(operation_name, item_ids);
+
+ // return
+ return true;
}
- else {
- for ( i=0; i < checks.length; i++ ) {
- if ( checks[i].name.indexOf( 'id' ) !== -1) {
- checks[i].checked = false;
- }
- }
- }
- init_grid_elements();
-}
-
-
-// confirmation/submission of operation request
-function submit_operation(selected_button, confirmation_text)
-{
- // verify in any item is selected
- var number_of_checked_ids = $('input[name="id"]:checked').length;
- if (!number_of_checked_ids > 0)
- return false;
-
- // show confirmation box
- if (confirmation_text != 'None' && confirmation_text != '')
- if(!confirm(confirmation_text))
- return false;
-
- // add ids
- var operation_name = selected_button.value;
- var item_ids = [];
- $('input[name=id]:checked').each(function() {
- item_ids.push( $(this).val() );
- });
- do_operation(operation_name, item_ids);
-
- // return
- return true;
-}
+});
diff -r 5e534cc8da856ad598d63b8b9f03fe20629df05f -r f1cef709a9e5631cae2126ffff71dbba64611f87 static/scripts/packed/galaxy.grids.js
--- a/static/scripts/packed/galaxy.grids.js
+++ b/static/scripts/packed/galaxy.grids.js
@@ -1,1 +1,1 @@
-jQuery.ajaxSettings.traditional=true;var Grid=Backbone.Model.extend({defaults:{url_base:"",async:false,async_ops:[],categorical_filters:[],filters:{},sort_key:null,show_item_checkboxes:false,cur_page:1,num_pages:1,operation:undefined,item_ids:undefined},can_async_op:function(a){return _.indexOf(this.attributes.async_ops,a)!==-1},add_filter:function(e,f,b){if(b){var c=this.attributes.filters[e],a;if(c===null||c===undefined){a=f}else{if(typeof(c)=="string"){if(c=="All"){a=f}else{var d=[];d[0]=c;d[1]=f;a=d}}else{a=c;a.push(f)}}this.attributes.filters[e]=a}else{this.attributes.filters[e]=f}},remove_filter:function(b,e){var a=this.attributes.filters[b];if(a===null||a===undefined){return false}var d=true;if(typeof(a)==="string"){if(a=="All"){d=false}else{delete this.attributes.filters[b]}}else{var c=_.indexOf(a,e);if(c!==-1){a.splice(c,1)}else{d=false}}return d},get_url_data:function(){var a={async:this.attributes.async,sort:this.attributes.sort_key,page:this.attributes.cur_page,show_item_checkboxes:this.attributes.show_item_checkboxes};if(this.attributes.operation){a.operation=this.attributes.operation}if(this.attributes.item_ids){a.id=this.attributes.item_ids}var b=this;_.each(_.keys(b.attributes.filters),function(c){a["f-"+c]=b.attributes.filters[c]});return a}});function init_grid_controls(){$(".submit-image").each(function(){$(this).mousedown(function(){$(this).addClass("gray-background")});$(this).mouseup(function(){$(this).removeClass("gray-background")})});$(".sort-link").each(function(){$(this).click(function(){set_sort_condition($(this).attr("sort_key"));return false})});$(".page-link > a").each(function(){$(this).click(function(){set_page($(this).attr("page_num"));return false})});$(".categorical-filter > a").each(function(){$(this).click(function(){set_categorical_filter($(this).attr("filter_key"),$(this).attr("filter_val"));return false})});$(".text-filter-form").each(function(){$(this).submit(function(){var d=$(this).attr("column_key");var c=$("#input-"+d+"-filter");var e=c.val();c.val("");add_filter_condition(d,e,true);return false})});var a=$("#input-tags-filter");if(a.length){a.autocomplete(history_tag_autocomplete_url,{selectFirst:false,autoFill:false,highlight:false,mustMatch:false})}var b=$("#input-name-filter");if(b.length){b.autocomplete(history_name_autocomplete_url,{selectFirst:false,autoFill:false,highlight:false,mustMatch:false})}$(".advanced-search-toggle").each(function(){$(this).click(function(){$("#standard-search").slideToggle("fast");$("#advanced-search").slideToggle("fast");return false})})}function init_grid_elements(){$(".grid").each(function(){var b=$(this).find("input.grid-row-select-checkbox");var a=$(this).find("span.grid-selected-count");var c=function(){a.text($(b).filter(":checked").length)};$(b).each(function(){$(this).change(c)});c()});$(".label").each(function(){var a=$(this).attr("href");if(a!==undefined&&a.indexOf("operation=")!=-1){$(this).click(function(){do_operation_from_href($(this).attr("href"));return false})}});if($(".community_rating_star").length!==0){$(".community_rating_star").rating({})}make_popup_menus()}function go_page_one(){var a=grid.get("cur_page");if(a!==null&&a!==undefined&&a!=="all"){grid.set("cur_page",1)}}function add_filter_condition(c,e,a){if(e===""){return false}grid.add_filter(c,e,a);var d=$("<span>"+e+"<a href='javascript:void(0);'><span class='delete-search-icon' /></a></span>");d.addClass("text-filter-val");d.click(function(){grid.remove_filter(c,e);$(this).remove();go_page_one();update_grid()});var b=$("#"+c+"-filtering-criteria");b.append(d);go_page_one();update_grid()}function add_tag_to_grid_filter(c,b){var a=c+(b!==undefined&&b!==""?":"+b:"");$("#advanced-search").show("fast");add_filter_condition("tags",a,true)}function set_sort_condition(f){var e=grid.get("sort_key");var d=f;if(e.indexOf(f)!==-1){if(e.substring(0,1)!=="-"){d="-"+f}else{}}$(".sort-arrow").remove();var c=(d.substring(0,1)=="-")?"↑":"↓";var a=$("<span>"+c+"</span>").addClass("sort-arrow");var b=$("#"+f+"-header");b.append(a);grid.set("sort_key",d);go_page_one();update_grid()}function set_categorical_filter(b,d){var a=grid.get("categorical_filters")[b],c=grid.get("filters")[b];$("."+b+"-filter").each(function(){var h=$.trim($(this).text());var f=a[h];var g=f[b];if(g==d){$(this).empty();$(this).addClass("current-filter");$(this).append(h)}else{if(g==c){$(this).empty();var e=$("<a href='#'>"+h+"</a>");e.click(function(){set_categorical_filter(b,g)});$(this).removeClass("current-filter");$(this).append(e)}}});grid.add_filter(b,d);go_page_one();update_grid()}function set_page(a){$(".page-link").each(function(){var g=$(this).attr("id"),e=parseInt(g.split("-")[2],10),c=grid.get("cur_page"),f;if(e===a){f=$(this).children().text();$(this).empty();$(this).addClass("inactive-link");$(this).text(f)}else{if(e===c){f=$(this).text();$(this).empty();$(this).removeClass("inactive-link");var d=$("<a href='#'>"+f+"</a>");d.click(function(){set_page(e)});$(this).append(d)}}});var b=true;if(a==="all"){grid.set("cur_page",a);b=false}else{grid.set("cur_page",parseInt(a,10))}update_grid(b)}function do_operation(b,a){b=b.toLowerCase();grid.set({operation:b,item_ids:a});if(grid.can_async_op(b)){update_grid(true)}else{go_to_URL()}}function do_operation_from_href(c){var f=c.split("?");if(f.length>1){var a=f[1];var e=a.split("&");var b=null;var g=-1;for(var d=0;d<e.length;d++){if(e[d].indexOf("operation")!=-1){b=e[d].split("=")[1]}else{if(e[d].indexOf("id")!=-1){g=e[d].split("=")[1]}}}do_operation(b,g);return false}}function go_to_URL(){grid.set("async",false);window.location=grid.get("url_base")+"?"+$.param(grid.get_url_data())}function update_grid(a){if(!grid.get("async")){go_to_URL();return}var b=(grid.get("operation")?"POST":"GET");$(".loading-elt-overlay").show();$.ajax({type:b,url:grid.get("url_base"),data:grid.get_url_data(),error:function(){alert("Grid refresh failed")},success:function(d){var c=d.split("*****");$("#grid-table-body").html(c[0]);$("#grid-table-footer").html(c[1]);$("#grid-table-body").trigger("update");init_grid_elements();make_popup_menus();$(".loading-elt-overlay").hide();var e=$.trim(c[2]);if(e!==""){$("#grid-message").html(e).show();setTimeout(function(){$("#grid-message").hide()},5000)}},complete:function(){grid.set({operation:undefined,item_ids:undefined})}})}function check_all_items(){var a=document.getElementById("check_all"),b=document.getElementsByTagName("input"),d=0,c;if(a.checked===true){for(c=0;c<b.length;c++){if(b[c].name.indexOf("id")!==-1){b[c].checked=true;d++}}}else{for(c=0;c<b.length;c++){if(b[c].name.indexOf("id")!==-1){b[c].checked=false}}}init_grid_elements()}function submit_operation(d,e){var c=$('input[name="id"]:checked').length;if(!c>0){return false}if(e!="None"&&e!=""){if(!confirm(e)){return false}}var b=d.value;var a=[];$("input[name=id]:checked").each(function(){a.push($(this).val())});do_operation(b,a);return true};
\ No newline at end of file
+jQuery.ajaxSettings.traditional=true;var Grid=Backbone.Model.extend({defaults:{url_base:"",async:false,async_ops:[],categorical_filters:[],filters:{},sort_key:null,show_item_checkboxes:false,cur_page:1,num_pages:1,operation:undefined,item_ids:undefined},can_async_op:function(a){return _.indexOf(this.attributes.async_ops,a)!==-1},add_filter:function(e,f,b){if(b){var c=this.attributes.filters[e],a;if(c===null||c===undefined){a=f}else{if(typeof(c)=="string"){if(c=="All"){a=f}else{var d=[];d[0]=c;d[1]=f;a=d}}else{a=c;a.push(f)}}this.attributes.filters[e]=a}else{this.attributes.filters[e]=f}},remove_filter:function(b,e){var a=this.attributes.filters[b];if(a===null||a===undefined){return false}var d=true;if(typeof(a)==="string"){if(a=="All"){d=false}else{delete this.attributes.filters[b]}}else{var c=_.indexOf(a,e);if(c!==-1){a.splice(c,1)}else{d=false}}return d},get_url_data:function(){var a={async:this.attributes.async,sort:this.attributes.sort_key,page:this.attributes.cur_page,show_item_checkboxes:this.attributes.show_item_checkboxes};if(this.attributes.operation){a.operation=this.attributes.operation}if(this.attributes.item_ids){a.id=this.attributes.item_ids}var b=this;_.each(_.pairs(b.attributes.filters),function(c){a["f-"+c[0]]=c[1]});return a}});var GridView=Backbone.View.extend({grid:null,initialize:function(a){this.grid=a;this.init_grid_elements();this.init_grid_controls();$("input[type=text]").each(function(){$(this).click(function(){$(this).select()}).keyup(function(){$(this).css("font-style","normal")})})},init_grid_controls:function(){$(".submit-image").each(function(){$(this).mousedown(function(){$(this).addClass("gray-background")});$(this).mouseup(function(){$(this).removeClass("gray-background")})});var a=this;$(".sort-link").each(function(){$(this).click(function(){a.set_sort_condition($(this).attr("sort_key"));return false})});$(".page-link > a").each(function(){$(this).click(function(){a.set_page($(this).attr("page_num"));return false})});$(".categorical-filter > a").each(function(){$(this).click(function(){a.set_categorical_filter($(this).attr("filter_key"),$(this).attr("filter_val"));return false})});$(".text-filter-form").each(function(){$(this).submit(function(){var e=$(this).attr("column_key");var d=$("#input-"+e+"-filter");var f=d.val();d.val("");a.add_filter_condition(e,f,true);return false})});var b=$("#input-tags-filter");if(b.length){b.autocomplete(this.grid.history_tag_autocomplete_url,{selectFirst:false,autoFill:false,highlight:false,mustMatch:false})}var c=$("#input-name-filter");if(c.length){c.autocomplete(this.grid.history_name_autocomplete_url,{selectFirst:false,autoFill:false,highlight:false,mustMatch:false})}$(".advanced-search-toggle").each(function(){$(this).click(function(){$("#standard-search").slideToggle("fast");$("#advanced-search").slideToggle("fast");return false})})},init_grid_elements:function(){$(".grid").each(function(){var c=$(this).find("input.grid-row-select-checkbox");var b=$(this).find("span.grid-selected-count");var d=function(){b.text($(c).filter(":checked").length)};$(c).each(function(){$(this).change(d)});d()});var a=this;$(".label").each(function(){var b=$(this).attr("href");if(b!==undefined&&b.indexOf("operation=")!=-1){$(this).click(function(){a.do_operation_from_href($(this).attr("href"));return false})}});if($(".community_rating_star").length!==0){$(".community_rating_star").rating({})}make_popup_menus()},go_page_one:function(){var a=this.grid.get("cur_page");if(a!==null&&a!==undefined&&a!=="all"){this.grid.set("cur_page",1)}},add_filter_condition:function(d,f,a){if(f===""){return false}this.grid.add_filter(d,f,a);var e=$("<span>"+f+"<a href='javascript:void(0);'><span class='delete-search-icon' /></a></span>");e.addClass("text-filter-val");var c=this;e.click(function(){c.grid.remove_filter(d,f);$(this).remove();c.go_page_one();c.update_grid()});var b=$("#"+d+"-filtering-criteria");b.append(e);this.go_page_one();this.update_grid()},set_sort_condition:function(f){var e=this.grid.get("sort_key");var d=f;if(e.indexOf(f)!==-1){if(e.substring(0,1)!=="-"){d="-"+f}else{}}$(".sort-arrow").remove();var c=(d.substring(0,1)=="-")?"↑":"↓";var a=$("<span>"+c+"</span>").addClass("sort-arrow");var b=$("#"+f+"-header");b.append(a);this.grid.set("sort_key",d);this.go_page_one();this.update_grid()},set_categorical_filter:function(c,e){var b=this.grid.get("categorical_filters")[c],d=this.grid.get("filters")[c];var a=this;$("."+c+"-filter").each(function(){var i=$.trim($(this).text());var g=b[i];var h=g[c];if(h==e){$(this).empty();$(this).addClass("current-filter");$(this).append(i)}else{if(h==d){$(this).empty();var f=$("<a href='#'>"+i+"</a>");f.click(function(){a.set_categorical_filter(c,h)});$(this).removeClass("current-filter");$(this).append(f)}}});this.grid.add_filter(c,e);this.go_page_one();this.update_grid()},set_page:function(a){var b=this;$(".page-link").each(function(){var h=$(this).attr("id"),f=parseInt(h.split("-")[2],10),d=b.grid.get("cur_page"),g;if(f===a){g=$(this).children().text();$(this).empty();$(this).addClass("inactive-link");$(this).text(g)}else{if(f===d){g=$(this).text();$(this).empty();$(this).removeClass("inactive-link");var e=$("<a href='#'>"+g+"</a>");e.click(function(){set_page(f)});$(this).append(e)}}});var c=true;if(a==="all"){this.grid.set("cur_page",a);c=false}else{this.grid.set("cur_page",parseInt(a,10))}this.update_grid(c)},do_operation:function(b,a){b=b.toLowerCase();this.grid.set({operation:b,item_ids:a});if(this.grid.can_async_op(b)){this.update_grid(true)}else{this.go_to_URL()}},do_operation_from_href:function(c){var f=c.split("?");if(f.length>1){var a=f[1];var e=a.split("&");var b=null;var g=-1;for(var d=0;d<e.length;d++){if(e[d].indexOf("operation")!=-1){b=e[d].split("=")[1]}else{if(e[d].indexOf("id")!=-1){g=e[d].split("=")[1]}}}this.do_operation(b,g);return false}},go_to_URL:function(){this.grid.set("async",false);window.location=this.grid.get("url_base")+"?"+$.param(this.grid.get_url_data());this.grid.set({operation:undefined,item_ids:undefined})},update_grid:function(b){if(!this.grid.get("async")){this.go_to_URL();return}var c=(this.grid.get("operation")?"POST":"GET");$(".loading-elt-overlay").show();var a=this;$.ajax({type:c,url:a.grid.get("url_base"),data:a.grid.get_url_data(),error:function(){alert("Grid refresh failed")},success:function(e){var d=e.split("*****");$("#grid-table-body").html(d[0]);$("#grid-table-footer").html(d[1]);$("#grid-table-body").trigger("update");a.init_grid_elements();make_popup_menus();$(".loading-elt-overlay").hide();var f=$.trim(d[2]);if(f!==""){$("#grid-message").html(f).show();setTimeout(function(){$("#grid-message").hide()},5000)}},complete:function(){a.grid.set({operation:undefined,item_ids:undefined})}})},check_all_items:function(){var a=document.getElementById("check_all"),b=document.getElementsByTagName("input"),d=0,c;if(a.checked===true){for(c=0;c<b.length;c++){if(b[c].name.indexOf("id")!==-1){b[c].checked=true;d++}}}else{for(c=0;c<b.length;c++){if(b[c].name.indexOf("id")!==-1){b[c].checked=false}}}this.init_grid_elements()},submit_operation:function(d,e){var c=$('input[name="id"]:checked').length;if(!c>0){return false}if(e!="None"&&e!=""){if(!confirm(e)){return false}}var b=$(d).val();var a=[];$("input[name=id]:checked").each(function(){a.push($(this).val())});this.do_operation(b,a);return true}});
\ No newline at end of file
diff -r 5e534cc8da856ad598d63b8b9f03fe20629df05f -r f1cef709a9e5631cae2126ffff71dbba64611f87 templates/base.mako
--- a/templates/base.mako
+++ b/templates/base.mako
@@ -2,6 +2,7 @@
<!DOCTYPE HTML><html><!--base.mako-->
+ ${self.init()}
<head><title>${self.title()}</title><meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
@@ -17,6 +18,9 @@
## Default title
<%def name="title()"></%def>
+## Default init
+<%def name="init()"></%def>
+
## Default stylesheets
<%def name="stylesheets()">
${h.css('base')}
diff -r 5e534cc8da856ad598d63b8b9f03fe20629df05f -r f1cef709a9e5631cae2126ffff71dbba64611f87 templates/grid_base.mako
--- a/templates/grid_base.mako
+++ b/templates/grid_base.mako
@@ -12,16 +12,167 @@
return '/base.mako'
%><%inherit file="${inherit(context)}"/>
-<%namespace file="/display_common.mako" import="render_message" />
+<%namespace file="./grid_common.mako" import="*" /><%namespace file="/refresh_frames.mako" import="handle_refresh_frames" />
+<%namespace file="/display_common.mako" import="get_class_plural" /><%def name="init()"><%
- self.has_left_panel=False
- self.has_right_panel=False
- self.message_box_visible=False
- self.active_view="user"
- self.overlay_visible=False
+ self.has_left_panel = False
+ self.has_right_panel = False
+ self.message_box_visible = False
+ self.overlay_visible = False
+ self.active_view = 'user'
+
+ self.grid_config = {
+ 'title' : grid.title,
+ 'url_base' : trans.request.path_url,
+ 'async' : grid.use_async,
+ 'async_ops' : [],
+ 'categorical_filters' : {},
+ 'filters' : cur_filter_dict,
+ 'sort_key' : sort_key,
+ 'show_item_checkboxes' : context.get('show_item_checkboxes', False),
+ 'cur_page_num' : cur_page_num,
+ 'num_pages' : num_pages,
+ 'history_tag_autocomplete_url' : url( controller='tag', action='tag_autocomplete_data', item_class='History' ),
+ 'history_name_autocomplete_url' : url( controller='history', action='name_autocomplete_data' ),
+ 'status' : status,
+ 'message' : util.restore_text(message),
+ 'global_actions' : [],
+ 'operations' : [],
+ 'items' : [],
+ 'columns' : [],
+ 'multiple_item_ops_exist' : None,
+ 'get_class_plural' : get_class_plural( grid.model_class ).lower(),
+ 'use_paging' : grid.use_paging,
+ 'legend' : grid.legend,
+ 'current_item_id' : ''
+ }
+
+ ## add current item if exists
+ if current_item:
+ self.grid_config['current_item_id'] = current_item.id
+ endif
+
+ ## column
+ for column in grid.columns:
+
+ ## add column sort links
+ href = None
+ extra = ''
+ if column.sortable:
+ if sort_key.endswith(column.key):
+ if not sort_key.startswith("-"):
+ href = url( sort=( "-" + column.key ) )
+ extra = "↓"
+ else:
+ href = url( sort=( column.key ) )
+ extra = "↑"
+ else:
+ href = url( sort=column.key )
+
+ ## add to configuration
+ self.grid_config['columns'].append({
+ 'key' : column.key,
+ 'visible' : column.visible,
+ 'nowrap' : column.nowrap,
+ 'attach_popup' : column.attach_popup,
+ 'label_id_prefix' : column.label_id_prefix,
+ 'sortable' : column.sortable,
+ 'label' : column.label,
+ 'href' : href,
+ 'extra' : extra
+ })
+ endfor
+
+ ## operations
+ for operation in grid.operations:
+ self.grid_config['operations'].append({
+ 'allow_multiple' : operation.allow_multiple,
+ 'allow_popup' : operation.allow_popup,
+ 'target' : operation.target,
+ 'label' : operation.label,
+ 'confirm' : operation.confirm,
+ 'global_operation' : False
+ })
+ if operation.allow_multiple:
+ self.grid_config['multiple_item_ops_exist'] = True
+
+ if operation.global_operation:
+ self.grid_config['global_operation'] = url( ** (operation.global_operation()) )
+ endfor
+
+ ## global actions
+ for action in grid.global_actions:
+ self.grid_config['global_actions'].append({
+ 'url_args' : url(**action.url_args),
+ 'label' : action.label
+ })
+ endfor
+
+ ## Operations that are async (AJAX) compatible.
+ for operation in [op for op in grid.operations if op.async_compatible]:
+ self.grid_config['async_ops'].append(operation.label.lower());
+ endfor
+
+ ## Filter values for categorical filters.
+ for column in grid.columns:
+ if column.filterable is not None and not isinstance( column, TextColumn ):
+ self.grid_config['categorical_filters'][column.key] = dict([ (filter.label, filter.args) for filter in column.get_accepted_filters() ])
+ endif
+ endfor
+
+ # items
+ for i, item in enumerate( query ):
+ item_dict = {
+ 'id' : item.id,
+ 'encode_id' : trans.security.encode_id(item.id),
+ 'link' : [],
+ 'operation_config' : {},
+ 'column_config' : {}
+ }
+
+ ## data columns
+ for column in grid.columns:
+ if column.visible:
+ ## get link
+ link = column.get_link(trans, grid, item)
+ if link:
+ link = url(**link)
+ else:
+ link = None
+ endif
+
+ ## get value
+ value = column.get_value( trans, grid, item )
+
+ # Handle non-ascii chars.
+ if isinstance(value, str):
+ value = unicode(value, 'utf-8')
+
+ # escape string
+ value = value.replace('/', '//')
+ endif
+
+ ## Item dictionary
+ item_dict['column_config'][column.label] = {
+ 'link' : link,
+ 'value' : value
+ }
+ endif
+ endfor
+ ## add operation details to item
+ for operation in grid.operations:
+ item_dict['operation_config'][operation.label] = {
+ 'allowed' : operation.allowed(item),
+ 'url_args' : url( **operation.get_url_args( item ) )
+ }
+ endfor
+
+ ## add item to list
+ self.grid_config['items'].append(item_dict)
+ endfor
%></%def>
@@ -45,7 +196,7 @@
${self.make_grid( grid )}
</%def>
-<%def name="title()">${grid.title}</%def>
+<%def name="title()">${self.grid_config['title']}</%def><%def name="javascripts()">
${parent.javascripts()}
@@ -57,65 +208,33 @@
${handle_refresh_frames()}
<script type="text/javascript">
-
- // Needed URLs for grid history searching.
- var history_tag_autocomplete_url = "${url( controller='tag', action='tag_autocomplete_data', item_class='History' )}",
- history_name_autocomplete_url = "${url( controller='history', action='name_autocomplete_data' )}";
- //
- // Create grid object.
- //
+ var gridView = null;
- // Operations that are async (AJAX) compatible.
- var async_ops = [];
- %for operation in [op for op in grid.operations if op.async_compatible]:
- async_ops.push('${operation.label.lower()}');
- %endfor
+ function add_tag_to_grid_filter (tag_name, tag_value)
+ {
+ // Put tag name and value together.
+ var tag = tag_name + (tag_value !== undefined && tag_value !== "" ? ":" + tag_value : "");
+ $('#advanced-search').show('fast');
+ gridView.add_filter_condition("tags", tag, true);
+ };
- // Filter values for categorical filters.
- var categorical_filters = {};
- %for column in grid.columns:
- %if column.filterable is not None and not isinstance( column, TextColumn ):
- var ${column.key}_filters = ${ h.to_json_string( dict([ (filter.label, filter.args) for filter in column.get_accepted_filters() ]) ) };
- categorical_filters['${column.key}'] = ${column.key}_filters;
- %endif
- %endfor
-
- /** Returns true if string denotes true. */
- var is_true = function(s) { return _.indexOf(['True', 'true', 't'], s) !== -1; };
-
- // Create grid.
- var grid = new Grid({
- url_base: '${trans.request.path_url}',
- async: is_true('${grid.use_async}'),
- async_ops: async_ops,
- categorical_filters: categorical_filters,
- filters: ${h.to_json_string( cur_filter_dict )},
- sort_key: '${sort_key}',
- show_item_checkboxes: is_true('${context.get('show_item_checkboxes', False)}'),
- cur_page: ${cur_page_num},
- // persistent page="all"
- //cur_page: ('${cur_page_num}' === 'all')?('all'):(Number('${cur_page_num}')),
- num_pages: ${num_pages}
- });
-
- // Initialize grid objects on load.
- // FIXME: use a grid view object eventually.
- $(document).ready(function() {
+ $(function() {
+ ## get configuration
+ var grid_config = ${ h.to_json_string( self.grid_config ) };
+ console.log(grid_config);
+ // Create grid.
+ var grid = new Grid(grid_config);
// strip protocol and domain
var url = grid.get('url_base');
url = url.replace(/^.*\/\/[^\/]+/, '');
grid.set('url_base', url);
-
- init_grid_elements();
- init_grid_controls();
- // Initialize text filters to select text on click and use normal font when user is typing.
- $('input[type=text]').each(function() {
- $(this).click(function() { $(this).select(); } )
- .keyup(function () { $(this).css("font-style", "normal"); });
- });
+
+ // Create view.
+ gridView = new GridView(grid);
});
+
</script></%def>
@@ -127,17 +246,12 @@
%if context.get('use_panels'):
div#center {
padding: 10px;
+ overflow: auto;
}
%endif
</style></%def>
-##
-## Custom grid methods.
-##
-
-<%namespace file="./grid_common.mako" import="*" />
-
<%def name="make_grid( grid )"><div class="loading-elt-overlay"></div><table>
@@ -147,7 +261,14 @@
<td></td></tr><tr>
- <td width="100%" id="grid-message" valign="top">${render_message( message, status )}</td>
+ <td width="100%" id="grid-message" valign="top">
+ %if message:
+ <p>
+ <div class="${self.grid_config['status']}message transient-message">${self.grid_config['message']}</div>
+ <div style="clear: both"></div>
+ </p>
+ %endif
+ </td><td></td><td></td></tr>
@@ -157,7 +278,7 @@
</%def><%def name="grid_title()">
- <h2>${grid.title}</h2>
+ <h2>${self.grid_config['title']}</h2></%def>
## Render grid header.
@@ -166,18 +287,18 @@
%if render_title:
${self.grid_title()}
%endif
-
- %if grid.global_actions:
+
+ %if self.grid_config['global_actions']:
<ul class="manage-table-actions">
- %if len( grid.global_actions ) < 3:
- %for action in grid.global_actions:
- <li><a class="action-button" href="${url( **action.url_args )}">${action.label}</a></li>
+ %if len( self.grid_config['global_actions'] ) < 3:
+ %for action in self.grid_config['global_actions']:
+ <li><a class="action-button" href="${action['url_args']}">${action['label']}</a></li>
%endfor
%else:
<li><a class="action-button" id="action-8675309-popup" class="menubutton">Actions</a></li><div popupmenu="action-8675309-popup">
- %for action in grid.global_actions:
- <a class="action-button" href="${url( **action.url_args )}">${action.label}</a>
+ %for action in self.grid_config['global_actions']:
+ <a class="action-button" href="${action['url_args']}">${action['label']}</a>
%endfor
</div>
%endif
@@ -191,55 +312,37 @@
## Render grid.
<%def name="render_grid_table( grid, show_item_checkboxes=False)"><%
- # Set flag to indicate whether grid has operations that operate on multiple items.
- multiple_item_ops_exist = False
- for operation in grid.operations:
- if operation.allow_multiple:
- multiple_item_ops_exist = True
-
+ # get configuration
+ show_item_checkboxes = self.grid_config['show_item_checkboxes']
+ multiple_item_ops_exist = self.grid_config['multiple_item_ops_exist']
+ sort_key = self.grid_config['sort_key']
+
# Show checkboxes if flag is set or if multiple item ops exist.
if show_item_checkboxes or multiple_item_ops_exist:
show_item_checkboxes = True
%>
- <form action="${url()}" method="post" onsubmit="return false;">
+ <form method="post" onsubmit="return false;"><table id="grid-table" class="grid"><thead id="grid-table-header"><tr>
%if show_item_checkboxes:
<th>
- %if query.count() > 0:
- <input type="checkbox" id="check_all" name=select_all_checkbox value="true" onclick='check_all_items(1);'><input type="hidden" name=select_all_checkbox value="true">
+ %if len(self.grid_config['items']) > 0:
+ <input type="checkbox" id="check_all" name=select_all_checkbox value="true" onclick='gridView.check_all_items(1);'><input type="hidden" name=select_all_checkbox value="true">
%endif
</th>
%endif
- %for column in grid.columns:
- %if column.visible:
- <%
- href = ""
- extra = ""
- if column.sortable:
- if sort_key.endswith(column.key):
- if not sort_key.startswith("-"):
- href = url( sort=( "-" + column.key ) )
- extra = "↓"
- else:
- href = url( sort=( column.key ) )
- extra = "↑"
- else:
- href = url( sort=column.key )
- %>
+ %for column in self.grid_config['columns']:
+ %if column['visible']:
<th\
- id="${column.key}-header"
- %if column.ncells > 1:
- colspan="${column.ncells}"
- %endif
+ id="${column['key']}-header"
>
- %if href:
- <a href="${href}" class="sort-link" sort_key="${column.key}">${column.label}</a>
+ %if column['href']:
+ <a href="${column['href']}" class="sort-link" sort_key="${column['key']}">${column['label']}</a>
%else:
- ${column.label}
+ ${column['label']}
%endif
- <span class="sort-arrow">${extra}</span>
+ <span class="sort-arrow">${column['extra']}</span></th>
%endif
%endfor
@@ -259,15 +362,16 @@
## Render grid table body contents.
<%def name="render_grid_table_body_contents(grid, show_item_checkboxes=False)"><% num_rows_rendered = 0 %>
- %if query.count() == 0:
+ %if len(self.grid_config['items']) == 0:
## No results.
<tr><td colspan="100"><em>No Items</em></td></tr><% num_rows_rendered = 1 %>
%endif
- %for i, item in enumerate( query ):
- <% encoded_id = trans.security.encode_id( item.id ) %>
+ %for i, item in enumerate( self.grid_config['items'] ):
+ <% encoded_id = item['encode_id'] %>
+ <% popupmenu_id = "grid-" + str(i) + "-popup" %><tr \
- %if current_item == item:
+ %if self.grid_config['current_item_id'] == item['id']:
class="current" \
%endif
>
@@ -278,71 +382,72 @@
</td>
%endif
## Data columns
- %for column in grid.columns:
- %if column.visible:
+ %for column in self.grid_config['columns']:
+ %if column['visible']:
<%
- # Nowrap
+ ## Nowrap
nowrap = ""
- if column.nowrap:
- nowrap = 'style="white-space:nowrap;"'
- # Link
- link = column.get_link( trans, grid, item )
- if link:
- href = url( **link )
- else:
- href = None
- # Value (coerced to list so we can loop)
- value = column.get_value( trans, grid, item )
- if column.ncells == 1:
- value = [ value ]
+ if column['nowrap']:
+ nowrap = 'style="white-space:nowrap;"'
+
+ # get column settings
+ column_settings = item['column_config'][column['label']]
+
+ # load attributes
+ link = column_settings['link']
+ value = column_settings['value']
+
+ # check if formatting is defined
+ value = str(value).replace('//', '/')
+
+ # Attach popup menu?
+ id = ""
+ if column['attach_popup']:
+ id = 'grid-%d-popup' % i
+ endif
+
+ # Determine appropriate class
+ cls = ""
+ if column['attach_popup']:
+ cls = "menubutton"
+ if link:
+ cls += " split"
+ endif
+ endif
%>
- %for cellnum, v in enumerate( value ):
- <%
- id = ""
- # Handle non-ascii chars.
- if isinstance(v, str):
- v = unicode(v, 'utf-8')
- # Attach popup menu?
- if column.attach_popup and cellnum == 0:
- id = 'grid-%d-popup' % i
- # Determine appropriate class
- cls = ""
- if column.attach_popup:
- cls = "menubutton"
- if href:
- cls += " split"
-
- %>
- <td ${nowrap}>
- %if href:
- %if len(grid.operations) != 0:
+ <td ${nowrap}>
+ %if link:
+ %if len(self.grid_config['operations']) != 0:
<div id="${id}" class="${cls}" style="float: left;">
- %endif
- <a class="label" href="${href}">${v}</a>
- %if len(grid.operations) != 0:
+ %endif
+ <a class="label" href="${link}">${value}</a>
+ %if len(self.grid_config['operations']) != 0:
</div>
- %endif
- %else:
- <div id="${id}" class="${cls}"><label id="${column.label_id_prefix}${encoded_id}" for="${encoded_id}">${v}</label></div>
%endif
- </td>
- %endfor
+ %else:
+ <div id="${id}" class="${cls}"><label id="${column['label_id_prefix']}${encoded_id}" for="${encoded_id}">${value}</label></div>
+ %endif
+ </td>
%endif
%endfor
## Actions column
<td>
- <div popupmenu="grid-${i}-popup">
- %for operation in grid.operations:
- %if operation.allowed( item ) and operation.allow_popup:
+ <div popupmenu="${popupmenu_id}">
+ %for operation in self.grid_config['operations']:
+ <%
+ operation_id = operation['label']
+ operation_settings = item['operation_config'][operation_id]
+ %>
+ %if operation_settings['allowed'] and operation['allow_popup']:
<%
target = ""
- if operation.target:
- target = "target='" + operation.target + "'"
+ if operation['target']:
+ target = "target='" + operation['target'] + "'"
%>
- %if operation.confirm:
- <a class="action-button" ${target} confirm="${operation.confirm}" href="${ url( **operation.get_url_args( item ) ) }">${operation.label}</a>
+ %if operation['confirm']:
+ <a class="action-button" ${target} confirm="${operation['confirm']}" href="${operation_settings['url_args']}">${operation_id}</a>
%else:
- <a class="action-button" ${target} href="${ url( **operation.get_url_args( item ) ) }">${operation.label}</a>
+ <a class="action-button" ${target} href="${operation_settings['url_args']}">${operation_id}</a>
%endif
%endif
%endfor
@@ -351,20 +456,16 @@
</tr><% num_rows_rendered += 1 %>
%endfor
- ## Dummy rows to prevent table for moving too much.
- ##%if grid.use_paging:
- ## %for i in range( num_rows_rendered , grid.num_rows_per_page ):
- ## <tr><td colspan="1000"></td></tr>
- ## %endfor
- ##%endif
</%def>
## Render grid table footer contents.
<%def name="render_grid_table_footer_contents(grid, show_item_checkboxes=False)">
- ## Row for navigating among pages.
- <%namespace file="/display_common.mako" import="get_class_plural" />
- <% items_plural = get_class_plural( grid.model_class ).lower() %>
- %if grid.use_paging and num_pages > 1:
+ <%
+ items_plural = self.grid_config['get_class_plural']
+ num_pages = self.grid_config['num_pages']
+ cur_page_num = self.grid_config['cur_page_num']
+ %>
+ %if self.grid_config['use_paging'] and num_pages > 1:
<tr id="page-links-row">
%if show_item_checkboxes:
<td></td>
@@ -438,33 +539,29 @@
<td></td><td colspan="100">
For <span class="grid-selected-count"></span> selected ${items_plural}:
- %for operation in grid.operations:
- %if operation.allow_multiple:
- <input type="button" value="${operation.label}" class="action-button" onclick="submit_operation(this, '${operation.confirm}')">
+ %for operation in self.grid_config['operations']:
+ %if operation['allow_multiple']:
+ <input type="button" value="${operation['label']}" class="action-button" onclick="gridView.submit_operation(this, '${operation['confirm']}')">
%endif
%endfor
</td></tr>
%endif
- %if len([o for o in grid.operations if o.global_operation]) > 0:
+ %if len([o for o in self.grid_config['operations'] if o['global_operation']]) > 0:
<tr><td colspan="100">
- %for operation in grid.operations:
- %if operation.global_operation:
- <%
- link = operation.global_operation()
- href = url( **link )
- %>
- <a class="action-button" href="${href}">${operation.label}</a>
- %endif
+ %for operation in self.grid_config['operations']:
+ %if operation['global_operation']:
+ <a class="action-button" href="${operation['global_operation']}">${operation['label']}</a>
+ %endif
%endfor
</td></tr>
%endif
- %if grid.legend:
+ %if self.grid_config['legend']:
<tr><td colspan="100">
- ${grid.legend}
+ ${self.grid_config['legend']}
</td></tr>
%endif
diff -r 5e534cc8da856ad598d63b8b9f03fe20629df05f -r f1cef709a9e5631cae2126ffff71dbba64611f87 templates/grid_base_async.mako
--- a/templates/grid_base_async.mako
+++ b/templates/grid_base_async.mako
@@ -1,6 +1,8 @@
<%namespace file="./grid_base.mako" import="*" /><%namespace file="/display_common.mako" import="render_message" />
+${init()}
+
<%
# Set flag to indicate whether grid has operations that operate on multiple items.
multiple_item_ops_exist = False
diff -r 5e534cc8da856ad598d63b8b9f03fe20629df05f -r f1cef709a9e5631cae2126ffff71dbba64611f87 templates/webapps/galaxy/page/select_items_grid.mako
--- a/templates/webapps/galaxy/page/select_items_grid.mako
+++ b/templates/webapps/galaxy/page/select_items_grid.mako
@@ -1,6 +1,6 @@
## Template generates a grid that enables user to select items.
<%namespace file="../grid_base.mako" import="*" />
-
+${init()}
${grid_javascripts()}
${stylesheets()}
${render_grid_header( grid, False )}
diff -r 5e534cc8da856ad598d63b8b9f03fe20629df05f -r f1cef709a9e5631cae2126ffff71dbba64611f87 templates/webapps/galaxy/page/select_items_grid_async.mako
--- a/templates/webapps/galaxy/page/select_items_grid_async.mako
+++ b/templates/webapps/galaxy/page/select_items_grid_async.mako
@@ -1,6 +1,6 @@
<%namespace file="../grid_base.mako" import="*" /><%namespace file="/display_common.mako" import="render_message" />
-
+${init()}
## Always show item checkboxes so that users can select items.
${render_grid_table_body_contents( grid, show_item_checkboxes=show_item_checkboxes )}
*****
diff -r 5e534cc8da856ad598d63b8b9f03fe20629df05f -r f1cef709a9e5631cae2126ffff71dbba64611f87 templates/webapps/galaxy/tracks/add_to_viz.mako
--- a/templates/webapps/galaxy/tracks/add_to_viz.mako
+++ b/templates/webapps/galaxy/tracks/add_to_viz.mako
@@ -1,6 +1,6 @@
## Template generates a grid that enables user to add tracks
<%namespace file="../grid_base.mako" import="*" />
-
+${init()}
${stylesheets()}
${grid_javascripts()}
${render_grid_header( grid, False )}
diff -r 5e534cc8da856ad598d63b8b9f03fe20629df05f -r f1cef709a9e5631cae2126ffff71dbba64611f87 templates/webapps/galaxy/tracks/add_tracks.mako
--- a/templates/webapps/galaxy/tracks/add_tracks.mako
+++ b/templates/webapps/galaxy/tracks/add_tracks.mako
@@ -1,6 +1,6 @@
## Template generates a grid that enables user to add tracks
<%namespace file="../grid_base.mako" import="*" />
-
+${init()}
${stylesheets()}
${grid_javascripts()}
${render_grid_header( grid, False )}
diff -r 5e534cc8da856ad598d63b8b9f03fe20629df05f -r f1cef709a9e5631cae2126ffff71dbba64611f87 templates/webapps/galaxy/tracks/history_select_grid.mako
--- a/templates/webapps/galaxy/tracks/history_select_grid.mako
+++ b/templates/webapps/galaxy/tracks/history_select_grid.mako
@@ -4,7 +4,7 @@
## not make it possible to easily subclass templates.
##
<%namespace file="../grid_base.mako" import="*" />
-
+${init()}
${stylesheets()}
${grid_javascripts()}
@@ -12,18 +12,16 @@
<script type="text/javascript">
// Load all grid URLs into modal-body element so that
// grid + links stays embedded.
- var load_urls_into_modal_body = function() {
+ $(document).ready(function() {
+ $(".addtracktab, #grid-table a").off();
$(".addtracktab, #grid-table a").click(function() {
+ console.log($(this).attr("href"));
var modal_body = $(".modal-body");
if (modal_body.length !== 0) {
modal_body.load($(this).attr("href"));
return false;
}
});
- };
- // Need to process label URLs when document loaded and when grid changes.
- $(document).ready(function() {
- load_urls_into_modal_body();
});
</script><style>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jmchilton: Functional tool test fix.
by commits-noreply@bitbucket.org 17 Nov '13
by commits-noreply@bitbucket.org 17 Nov '13
17 Nov '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/5e534cc8da85/
Changeset: 5e534cc8da85
User: jmchilton
Date: 2013-11-17 09:03:28
Summary: Functional tool test fix.
No tests with a repeat and min=1 were ever going to past.
Affected #: 1 file
diff -r ef9968a089db28349b22c302ca07e9aa152bfe51 -r 5e534cc8da856ad598d63b8b9f03fe20629df05f test/functional/test_toolbox.py
--- a/test/functional/test_toolbox.py
+++ b/test/functional/test_toolbox.py
@@ -93,7 +93,8 @@
repeat_name = None
for input_name, input_value in testdef.tool.inputs_by_page[0].items():
if isinstance( input_value, grouping.Repeat ) and all_inputs.get( input_name, 1 ) not in [ 0, "0" ]: # default behavior is to test 1 repeat, for backwards compatibility
- repeat_name = input_name
+ if not input_value.min: # If input_value.min == 1, the element is already on the page don't add new element.
+ repeat_name = input_name
break
#check if we need to verify number of outputs created dynamically by tool
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jmchilton: PEP-8 and style adjustments for lib/galaxy/webapps/galaxy/api/provenance.py.
by commits-noreply@bitbucket.org 17 Nov '13
by commits-noreply@bitbucket.org 17 Nov '13
17 Nov '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/ef9968a089db/
Changeset: ef9968a089db
User: jmchilton
Date: 2013-11-17 07:53:00
Summary: PEP-8 and style adjustments for lib/galaxy/webapps/galaxy/api/provenance.py.
Affected #: 1 file
diff -r ec285ee50bf72455ad5a7f63d73c0516c185ecd0 -r ef9968a089db28349b22c302ca07e9aa152bfe51 lib/galaxy/webapps/galaxy/api/provenance.py
--- a/lib/galaxy/webapps/galaxy/api/provenance.py
+++ b/lib/galaxy/webapps/galaxy/api/provenance.py
@@ -42,11 +42,12 @@
if item is not None:
if item.copied_from_library_dataset_dataset_association:
item = item.copied_from_library_dataset_dataset_association
+ job = item.creating_job
return {
- "id" : trans.security.encode_id(item.id),
- "uuid" : ( lambda uuid: str( uuid ) if uuid else None )( item.dataset.uuid),
- "tool_id" : item.creating_job.tool_id,
- "parameters" : self._get_job_record(trans, item.creating_job, follow)
+ "id": trans.security.encode_id(item.id),
+ "uuid": ( lambda uuid: str( uuid ) if uuid else None )( item.dataset.uuid),
+ "tool_id": job.tool_id,
+ "parameters": self._get_job_record(trans, job, follow),
}
return None
@@ -59,8 +60,8 @@
out[in_d.name] = self._get_record(trans, in_d.dataset, follow)
else:
out[in_d.name] = {
- "id" : trans.security.encode_id(in_d.dataset.id),
- "uuid" : ( lambda uuid: str( uuid ) if uuid else None )( in_d.dataset.dataset.uuid )
+ "id": trans.security.encode_id(in_d.dataset.id),
+ "uuid": ( lambda uuid: str( uuid ) if uuid else None )( in_d.dataset.dataset.uuid ),
}
return out
@@ -75,5 +76,3 @@
controller_name = "ldda_provenance"
provenance_item_class = "LibraryDatasetDatasetAssociation"
provenance_item_id = "library_content_id"
-
-
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
3 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/ccbec227fcb9/
Changeset: ccbec227fcb9
User: jmchilton
Date: 2013-11-17 07:47:26
Summary: Do not reference values before use when GALAXY_TEST_EXTERNAL used.
GALAXY_TEST_EXTERNAL still quite broken.
Affected #: 1 file
diff -r 6ce38346b347dab8f4c7522df7a43874789e40ce -r ccbec227fcb958cb0137603ddad743be9ce8724f scripts/functional_tests.py
--- a/scripts/functional_tests.py
+++ b/scripts/functional_tests.py
@@ -217,9 +217,9 @@
database_auto_migrate = False
+ galaxy_test_proxy_port = None
+ psu_production = False
if start_server:
- psu_production = False
- galaxy_test_proxy_port = None
if 'GALAXY_TEST_PSU_PRODUCTION' in os.environ:
if not galaxy_test_port:
raise Exception( 'Please set GALAXY_TEST_PORT to the port to which the proxy server will proxy' )
https://bitbucket.org/galaxy/galaxy-central/commits/91b23579fb92/
Changeset: 91b23579fb92
User: jmchilton
Date: 2013-11-17 07:47:26
Summary: Fix logic in tool's populate_state logic to handle multiple uploads.
Enables composite uploads through API.
Affected #: 1 file
diff -r ccbec227fcb958cb0137603ddad743be9ce8724f -r 91b23579fb923ba358bae9768eb08c28e51dfa23 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -2155,11 +2155,19 @@
#remove extra files
while len( group_state ) > len( writable_files ):
del group_state[-1]
+
+ # Add new fileupload as needed
+ while len( writable_files ) > len( group_state ):
+ new_state = {}
+ new_state['__index__'] = len( group_state )
+ self.fill_in_new_state( trans, input.inputs, new_state, context )
+ group_state.append( new_state )
+ if any_group_errors:
+ group_errors.append( {} )
+
# Update state
- max_index = -1
for i, rep_state in enumerate( group_state ):
rep_index = rep_state['__index__']
- max_index = max( max_index, rep_index )
rep_prefix = "%s_%d|" % ( key, rep_index )
rep_errors = self.populate_state( trans,
input.inputs,
@@ -2174,16 +2182,6 @@
group_errors.append( rep_errors )
else:
group_errors.append( {} )
- # Add new fileupload as needed
- offset = 1
- while len( writable_files ) > len( group_state ):
- new_state = {}
- new_state['__index__'] = max_index + offset
- offset += 1
- self.fill_in_new_state( trans, input.inputs, new_state, context )
- group_state.append( new_state )
- if any_group_errors:
- group_errors.append( {} )
# Were there *any* errors for any repetition?
if any_group_errors:
errors[input.name] = group_errors
https://bitbucket.org/galaxy/galaxy-central/commits/ec285ee50bf7/
Changeset: ec285ee50bf7
User: jmchilton
Date: 2013-11-17 07:47:26
Summary: Consolidate duplicated code for loading HDAs from the API.
Affected #: 3 files
diff -r 91b23579fb923ba358bae9768eb08c28e51dfa23 -r ec285ee50bf72455ad5a7f63d73c0516c185ecd0 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -568,6 +568,31 @@
error( "Please wait until this dataset finishes uploading before attempting to view it." )
return hda
+ def get_history_dataset_association_from_ids( self, trans, id, history_id ):
+ # Just to echo other TODOs, there seems to be some overlap here, still
+ # this block appears multiple places (dataset show, history_contents
+ # show, upcoming history job show) so I am consolodating it here.
+ # Someone smarter than me should determine if there is some redundancy here.
+
+ # for anon users:
+ #TODO: check login_required?
+ #TODO: this isn't actually most_recently_used (as defined in histories)
+ if( ( trans.user == None )
+ and ( history_id == trans.security.encode_id( trans.history.id ) ) ):
+ history = trans.history
+ #TODO: dataset/hda by id (from history) OR check_ownership for anon user
+ hda = self.get_history_dataset_association( trans, history, id,
+ check_ownership=False, check_accessible=True )
+ else:
+ #TODO: do we really need the history?
+ history = self.get_history( trans, history_id,
+ check_ownership=True, check_accessible=True, deleted=False )
+ hda = self.get_history_dataset_association( trans, history, id,
+ check_ownership=True, check_accessible=True )
+ return hda
+
+
+
def get_hda_list( self, trans, hda_ids, check_ownership=True, check_accessible=False, check_state=True ):
"""
Returns one or more datasets in a list.
diff -r 91b23579fb923ba358bae9768eb08c28e51dfa23 -r ec285ee50bf72455ad5a7f63d73c0516c185ecd0 lib/galaxy/webapps/galaxy/api/datasets.py
--- a/lib/galaxy/webapps/galaxy/api/datasets.py
+++ b/lib/galaxy/webapps/galaxy/api/datasets.py
@@ -255,24 +255,9 @@
datatype prior to display (the defult if raw is unspecified or explicitly false.
"""
raw = string_as_bool_or_none( raw )
- # Huge amount of code overlap with lib/galaxy/webapps/galaxy/api/history_content:show here.
rval = ''
try:
- # for anon users:
- #TODO: check login_required?
- #TODO: this isn't actually most_recently_used (as defined in histories)
- if( ( trans.user == None )
- and ( history_id == trans.security.encode_id( trans.history.id ) ) ):
- history = trans.history
- #TODO: dataset/hda by id (from history) OR check_ownership for anon user
- hda = self.get_history_dataset_association( trans, history, history_content_id,
- check_ownership=False, check_accessible=True )
-
- else:
- history = self.get_history( trans, history_id,
- check_ownership=True, check_accessible=True, deleted=False )
- hda = self.get_history_dataset_association( trans, history, history_content_id,
- check_ownership=True, check_accessible=True )
+ hda = self.get_history_dataset_association_from_ids( trans, history_content_id, history_id )
display_kwd = kwd.copy()
try:
diff -r 91b23579fb923ba358bae9768eb08c28e51dfa23 -r ec285ee50bf72455ad5a7f63d73c0516c185ecd0 lib/galaxy/webapps/galaxy/api/history_contents.py
--- a/lib/galaxy/webapps/galaxy/api/history_contents.py
+++ b/lib/galaxy/webapps/galaxy/api/history_contents.py
@@ -135,32 +135,17 @@
:returns: dictionary containing detailed HDA information
.. seealso:: :func:`galaxy.web.base.controller.UsesHistoryDatasetAssociationMixin.get_hda_dict`
"""
- hda_dict = {}
try:
- # for anon users:
- #TODO: check login_required?
- #TODO: this isn't actually most_recently_used (as defined in histories)
- if( ( trans.user == None )
- and ( history_id == trans.security.encode_id( trans.history.id ) ) ):
- history = trans.history
- #TODO: dataset/hda by id (from history) OR check_ownership for anon user
- hda = self.get_history_dataset_association( trans, history, id,
- check_ownership=False, check_accessible=True )
- else:
- #TODO: do we really need the history?
- history = self.get_history( trans, history_id,
- check_ownership=True, check_accessible=True, deleted=False )
- hda = self.get_history_dataset_association( trans, history, id,
- check_ownership=True, check_accessible=True )
+ hda = self.get_history_dataset_association_from_ids( trans, id, history_id )
hda_dict = self.get_hda_dict( trans, hda )
hda_dict[ 'display_types' ] = self.get_old_display_applications( trans, hda )
hda_dict[ 'display_apps' ] = self.get_display_apps( trans, hda )
+ return hda_dict
except Exception, e:
msg = "Error in history API at listing dataset: %s" % ( str(e) )
log.error( msg, exc_info=True )
trans.response.status = 500
return msg
- return hda_dict
@web.expose_api
def create( self, trans, history_id, payload, **kwd ):
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
4 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/9591da01c73a/
Changeset: 9591da01c73a
User: nsoranzo
Date: 2013-11-16 00:52:36
Summary: Enhance trinity to utilize GALAXY_SLOTS configuration when available.
Affected #: 1 file
diff -r 69f348f4b3c7fac9c406b1666309f82810566802 -r 9591da01c73a5af50b87aba15ada6c22e70a94a7 tools/ngs_rna/trinity_all.xml
--- a/tools/ngs_rna/trinity_all.xml
+++ b/tools/ngs_rna/trinity_all.xml
@@ -36,7 +36,7 @@
--JM 10G
## CPU and butterfly options.
- --CPU 6 --bfly_opts "-V 10 --stderr" > $trinity_log 2>&1
+ --CPU \${GALAXY_SLOTS:-6} --bfly_opts "-V 10 --stderr" > $trinity_log 2>&1
</command><inputs><conditional name="inputs">
https://bitbucket.org/galaxy/galaxy-central/commits/1cfe8a7b1885/
Changeset: 1cfe8a7b1885
User: nsoranzo
Date: 2013-11-16 00:53:35
Summary: Enhance mosaik to utilize GALAXY_SLOTS configuration when available.
Affected #: 1 file
diff -r 9591da01c73a5af50b87aba15ada6c22e70a94a7 -r 1cfe8a7b18856e160565afb7fe6160ca2c717569 tools/sr_mapping/mosaik.xml
--- a/tools/sr_mapping/mosaik.xml
+++ b/tools/sr_mapping/mosaik.xml
@@ -3,7 +3,7 @@
<description/><requirements><requirement type="package">mosaik</requirement></requirements><command>
- #set $processors = '-p 4'
+ #set $processors = '-p ${GALAXY_SLOTS:-4}'
#set $lm = ''
#if $paired.kind == 'single':
#set $mfl = ''
https://bitbucket.org/galaxy/galaxy-central/commits/1b19cd2a77b5/
Changeset: 1b19cd2a77b5
User: nsoranzo
Date: 2013-11-16 00:53:52
Summary: Enhance bowtie2 to utilize GALAXY_SLOTS configuration when available.
Affected #: 1 file
diff -r 1cfe8a7b18856e160565afb7fe6160ca2c717569 -r 1b19cd2a77b52a8a0003bdc27f4073ff07ddbbd4 tools/sr_mapping/bowtie2_wrapper.xml
--- a/tools/sr_mapping/bowtie2_wrapper.xml
+++ b/tools/sr_mapping/bowtie2_wrapper.xml
@@ -21,7 +21,7 @@
bowtie2
## number of threads
- -p 4
+ -p \${GALAXY_SLOTS:-4}
## index file path
-x $index_path
https://bitbucket.org/galaxy/galaxy-central/commits/6ce38346b347/
Changeset: 6ce38346b347
User: natefoo
Date: 2013-11-16 01:05:06
Summary: Merged in nsoranzo/galaxy-central (pull request #262)
Convert other 3 tools to $GALAXY_SLOTS
Affected #: 3 files
diff -r a461269e7fd2cf7cf012fa16582f4bc5bd5dd1da -r 6ce38346b347dab8f4c7522df7a43874789e40ce tools/ngs_rna/trinity_all.xml
--- a/tools/ngs_rna/trinity_all.xml
+++ b/tools/ngs_rna/trinity_all.xml
@@ -36,7 +36,7 @@
--JM 10G
## CPU and butterfly options.
- --CPU 6 --bfly_opts "-V 10 --stderr" > $trinity_log 2>&1
+ --CPU \${GALAXY_SLOTS:-6} --bfly_opts "-V 10 --stderr" > $trinity_log 2>&1
</command><inputs><conditional name="inputs">
diff -r a461269e7fd2cf7cf012fa16582f4bc5bd5dd1da -r 6ce38346b347dab8f4c7522df7a43874789e40ce tools/sr_mapping/bowtie2_wrapper.xml
--- a/tools/sr_mapping/bowtie2_wrapper.xml
+++ b/tools/sr_mapping/bowtie2_wrapper.xml
@@ -21,7 +21,7 @@
bowtie2
## number of threads
- -p 4
+ -p \${GALAXY_SLOTS:-4}
## index file path
-x $index_path
diff -r a461269e7fd2cf7cf012fa16582f4bc5bd5dd1da -r 6ce38346b347dab8f4c7522df7a43874789e40ce tools/sr_mapping/mosaik.xml
--- a/tools/sr_mapping/mosaik.xml
+++ b/tools/sr_mapping/mosaik.xml
@@ -3,7 +3,7 @@
<description/><requirements><requirement type="package">mosaik</requirement></requirements><command>
- #set $processors = '-p 4'
+ #set $processors = '-p ${GALAXY_SLOTS:-4}'
#set $lm = ''
#if $paired.kind == 'single':
#set $mfl = ''
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: History panel: fix disabled class on icon buttons
by commits-noreply@bitbucket.org 15 Nov '13
by commits-noreply@bitbucket.org 15 Nov '13
15 Nov '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/a461269e7fd2/
Changeset: a461269e7fd2
User: carlfeberhard
Date: 2013-11-15 21:53:59
Summary: History panel: fix disabled class on icon buttons
Affected #: 2 files
diff -r a61de575700cc4c2e648699591415a090b3ee4e8 -r a461269e7fd2cf7cf012fa16582f4bc5bd5dd1da static/scripts/mvc/dataset/hda-edit.js
--- a/static/scripts/mvc/dataset/hda-edit.js
+++ b/static/scripts/mvc/dataset/hda-edit.js
@@ -74,7 +74,7 @@
// disable if purged or deleted and explain why in the tooltip
if( deleted || purged ){
- editBtnData.enabled = false;
+ editBtnData.disabled = true;
if( purged ){
editBtnData.title = _l( 'Cannot edit attributes of datasets removed from disk' );
} else if( deleted ){
@@ -117,7 +117,7 @@
deleteBtnData = {
title : _l( 'Dataset is already deleted' ),
icon_class : 'delete',
- enabled : false
+ disabled : true
};
}
deleteBtnData.faIcon = 'fa-times';
diff -r a61de575700cc4c2e648699591415a090b3ee4e8 -r a461269e7fd2cf7cf012fa16582f4bc5bd5dd1da static/scripts/packed/mvc/dataset/hda-edit.js
--- a/static/scripts/packed/mvc/dataset/hda-edit.js
+++ b/static/scripts/packed/mvc/dataset/hda-edit.js
@@ -1,1 +1,1 @@
-define(["mvc/dataset/hda-model","mvc/dataset/hda-base"],function(d,a){var f=a.HDABaseView.extend(LoggableMixin).extend({initialize:function(g){a.HDABaseView.prototype.initialize.call(this,g);this.hasUser=g.hasUser;this.defaultPrimaryActionButtonRenderers=[this._render_showParamsButton,this._render_rerunButton]},_render_titleButtons:function(){return a.HDABaseView.prototype._render_titleButtons.call(this).concat([this._render_editButton(),this._render_deleteButton()])},_render_editButton:function(){if((this.model.get("state")===d.HistoryDatasetAssociation.STATES.NEW)||(this.model.get("state")===d.HistoryDatasetAssociation.STATES.DISCARDED)||(this.model.get("state")===d.HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){return null}var i=this.model.get("purged"),g=this.model.get("deleted"),h={title:_l("Edit Attributes"),href:this.urls.edit,target:"galaxy_main",icon_class:"edit"};if(g||i){h.enabled=false;if(i){h.title=_l("Cannot edit attributes of datasets removed from disk")}else{if(g){h.title=_l("Undelete dataset to edit attributes")}}}else{if(this.model.get("state")===d.HistoryDatasetAssociation.STATES.UPLOAD){h.disabled=true;h.title=_l("This dataset must finish uploading before it can be edited")}}h.faIcon="fa-pencil";return faIconButton(h)},_render_deleteButton:function(){if((this.model.get("state")===d.HistoryDatasetAssociation.STATES.NEW)||(this.model.get("state")===d.HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){return null}var g=this,h=g.urls["delete"],i={title:_l("Delete"),href:h,icon_class:"delete",onclick:function(){g.$el.find(".menu-button.delete").trigger("mouseout");g.model["delete"]()}};if(this.model.get("deleted")||this.model.get("purged")){i={title:_l("Dataset is already deleted"),icon_class:"delete",enabled:false}}i.faIcon="fa-times";return faIconButton(i)},_render_errButton:function(){if(this.model.get("state")!==d.HistoryDatasetAssociation.STATES.ERROR){return null}return faIconButton({title:_l("View or report this error"),href:this.urls.report_error,target:"galaxy_main",faIcon:"fa-bug"})},_render_rerunButton:function(){return faIconButton({title:_l("Run this job again"),href:this.urls.rerun,target:"galaxy_main",faIcon:"fa-refresh"})},_render_visualizationsButton:function(){var g=this.model.get("visualizations");if((!this.model.hasData())||(_.isEmpty(g))){return null}if(_.isObject(g[0])){return this._render_visualizationsFrameworkButton(g)}if(!this.urls.visualization){return null}var i=this.model.get("dbkey"),l=this.urls.visualization,j={},m={dataset_id:this.model.get("id"),hda_ldda:"hda"};if(i){m.dbkey=i}var h=faIconButton({title:_l("Visualize"),href:this.urls.visualization,faIcon:"fa-bar-chart-o"});function k(n){switch(n){case"trackster":return b(l,m,i);case"scatterplot":return e(l,m);default:return function(){Galaxy.frame.add({title:"Visualization",type:"url",content:l+"/"+n+"?"+$.param(m)})}}}if(g.length===1){h.attr("title",g[0]);h.click(k(g[0]))}else{_.each(g,function(o){var n=o.charAt(0).toUpperCase()+o.slice(1);j[_l(n)]=k(o)});make_popupmenu(h,j)}return h},_render_visualizationsFrameworkButton:function(g){if(!(this.model.hasData())||!(g&&!_.isEmpty(g))){return null}var i=faIconButton({title:_l("Visualize"),faIcon:"fa-bar-chart-o"});i.addClass("visualize-icon");if(_.keys(g).length===1){i.attr("title",_.keys(g)[0]);i.attr("href",_.values(g)[0])}else{var j=[];_.each(g,function(k){j.push(k)});var h=new PopupMenu(i,j)}return i},_render_body_failed_metadata:function(){var h=$("<a/>").attr({href:this.urls.edit,target:"galaxy_main"}).text(_l("set it manually or retry auto-detection")),g=$("<span/>").text(". "+_l("You may be able to")+" ").append(h),i=a.HDABaseView.prototype._render_body_failed_metadata.call(this);i.find(".warningmessagesmall strong").append(g);return i},_render_body_error:function(){var g=a.HDABaseView.prototype._render_body_error.call(this);g.find(".dataset-actions .left").prepend(this._render_errButton());return g},_render_body_ok:function(){var g=a.HDABaseView.prototype._render_body_ok.call(this);if(this.model.isDeletedOrPurged()){return g}this.makeDbkeyEditLink(g);if(this.hasUser){g.find(".dataset-actions .left").append(this._render_visualizationsButton());this._renderTags(g);this._renderAnnotation(g)}return g},_renderTags:function(g){this.tagsEditor=new TagsEditor({model:this.model,el:g.find(".tags-display"),onshowFirstTime:function(){this.render()},$activator:faIconButton({title:_l("Edit dataset tags"),classes:"dataset-tag-btn",faIcon:"fa-tags"}).appendTo(g.find(".dataset-actions .right"))})},_renderAnnotation:function(g){this.annotationEditor=new AnnotationEditor({model:this.model,el:g.find(".annotation-display"),onshowFirstTime:function(){this.render()},$activator:faIconButton({title:_l("Edit dataset annotation"),classes:"dataset-annotate-btn",faIcon:"fa-comment"}).appendTo(g.find(".dataset-actions .right"))})},makeDbkeyEditLink:function(g){if(this.model.get("metadata_dbkey")==="?"&&!this.model.isDeletedOrPurged()){g.find(".dataset-dbkey .value").replaceWith($('<a target="galaxy_main">?</a>').attr("href",this.urls.edit))}},events:{"click .dataset-title-bar":"toggleBodyVisibility","click .dataset-undelete":function(g){this.model.undelete();return false},"click .dataset-unhide":function(g){this.model.unhide();return false},"click .dataset-purge":"confirmPurge"},confirmPurge:function c(g){this.model.purge();return false},toString:function(){var g=(this.model)?(this.model+""):("(no model)");return"HDAView("+g+")"}});function e(g,h){action=function(){Galaxy.frame.add({title:"Scatterplot",type:"url",content:g+"/scatterplot?"+$.param(h),target:"galaxy_main",scratchbook:true});$("div.popmenu-wrapper").remove();return false};return action}function b(g,i,h){return function(){var j={};if(h){j["f-dbkey"]=h}$.ajax({url:g+"/list_tracks?"+$.param(j),dataType:"html",error:function(){alert(("Could not add this dataset to browser")+".")},success:function(k){var l=window.parent;l.Galaxy.modal.show({title:"View Data in a New or Saved Visualization",buttons:{Cancel:function(){l.Galaxy.modal.hide()},"View in saved visualization":function(){l.Galaxy.modal.show({title:"Add Data to Saved Visualization",body:k,buttons:{Cancel:function(){l.Galaxy.modal.hide()},"Add to visualization":function(){$(l.document).find("input[name=id]:checked").each(function(){l.Galaxy.modal.hide();var m=$(this).val();i.id=m;l.Galaxy.frame.add({title:"Trackster",type:"url",content:g+"/trackster?"+$.param(i),scratchbook:true})})}}})},"View in new visualization":function(){l.Galaxy.modal.hide();var m=g+"/trackster?"+$.param(i);l.Galaxy.frame.add({title:"Trackster",type:"url",content:m,scratchbook:true})}}})}});return false}}return{HDAEditView:f}});
\ No newline at end of file
+define(["mvc/dataset/hda-model","mvc/dataset/hda-base"],function(d,a){var f=a.HDABaseView.extend(LoggableMixin).extend({initialize:function(g){a.HDABaseView.prototype.initialize.call(this,g);this.hasUser=g.hasUser;this.defaultPrimaryActionButtonRenderers=[this._render_showParamsButton,this._render_rerunButton]},_render_titleButtons:function(){return a.HDABaseView.prototype._render_titleButtons.call(this).concat([this._render_editButton(),this._render_deleteButton()])},_render_editButton:function(){if((this.model.get("state")===d.HistoryDatasetAssociation.STATES.NEW)||(this.model.get("state")===d.HistoryDatasetAssociation.STATES.DISCARDED)||(this.model.get("state")===d.HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){return null}var i=this.model.get("purged"),g=this.model.get("deleted"),h={title:_l("Edit Attributes"),href:this.urls.edit,target:"galaxy_main",icon_class:"edit"};if(g||i){h.disabled=true;if(i){h.title=_l("Cannot edit attributes of datasets removed from disk")}else{if(g){h.title=_l("Undelete dataset to edit attributes")}}}else{if(this.model.get("state")===d.HistoryDatasetAssociation.STATES.UPLOAD){h.disabled=true;h.title=_l("This dataset must finish uploading before it can be edited")}}h.faIcon="fa-pencil";return faIconButton(h)},_render_deleteButton:function(){if((this.model.get("state")===d.HistoryDatasetAssociation.STATES.NEW)||(this.model.get("state")===d.HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){return null}var g=this,h=g.urls["delete"],i={title:_l("Delete"),href:h,icon_class:"delete",onclick:function(){g.$el.find(".menu-button.delete").trigger("mouseout");g.model["delete"]()}};if(this.model.get("deleted")||this.model.get("purged")){i={title:_l("Dataset is already deleted"),icon_class:"delete",disabled:true}}i.faIcon="fa-times";return faIconButton(i)},_render_errButton:function(){if(this.model.get("state")!==d.HistoryDatasetAssociation.STATES.ERROR){return null}return faIconButton({title:_l("View or report this error"),href:this.urls.report_error,target:"galaxy_main",faIcon:"fa-bug"})},_render_rerunButton:function(){return faIconButton({title:_l("Run this job again"),href:this.urls.rerun,target:"galaxy_main",faIcon:"fa-refresh"})},_render_visualizationsButton:function(){var g=this.model.get("visualizations");if((!this.model.hasData())||(_.isEmpty(g))){return null}if(_.isObject(g[0])){return this._render_visualizationsFrameworkButton(g)}if(!this.urls.visualization){return null}var i=this.model.get("dbkey"),l=this.urls.visualization,j={},m={dataset_id:this.model.get("id"),hda_ldda:"hda"};if(i){m.dbkey=i}var h=faIconButton({title:_l("Visualize"),href:this.urls.visualization,faIcon:"fa-bar-chart-o"});function k(n){switch(n){case"trackster":return b(l,m,i);case"scatterplot":return e(l,m);default:return function(){Galaxy.frame.add({title:"Visualization",type:"url",content:l+"/"+n+"?"+$.param(m)})}}}if(g.length===1){h.attr("title",g[0]);h.click(k(g[0]))}else{_.each(g,function(o){var n=o.charAt(0).toUpperCase()+o.slice(1);j[_l(n)]=k(o)});make_popupmenu(h,j)}return h},_render_visualizationsFrameworkButton:function(g){if(!(this.model.hasData())||!(g&&!_.isEmpty(g))){return null}var i=faIconButton({title:_l("Visualize"),faIcon:"fa-bar-chart-o"});i.addClass("visualize-icon");if(_.keys(g).length===1){i.attr("title",_.keys(g)[0]);i.attr("href",_.values(g)[0])}else{var j=[];_.each(g,function(k){j.push(k)});var h=new PopupMenu(i,j)}return i},_render_body_failed_metadata:function(){var h=$("<a/>").attr({href:this.urls.edit,target:"galaxy_main"}).text(_l("set it manually or retry auto-detection")),g=$("<span/>").text(". "+_l("You may be able to")+" ").append(h),i=a.HDABaseView.prototype._render_body_failed_metadata.call(this);i.find(".warningmessagesmall strong").append(g);return i},_render_body_error:function(){var g=a.HDABaseView.prototype._render_body_error.call(this);g.find(".dataset-actions .left").prepend(this._render_errButton());return g},_render_body_ok:function(){var g=a.HDABaseView.prototype._render_body_ok.call(this);if(this.model.isDeletedOrPurged()){return g}this.makeDbkeyEditLink(g);if(this.hasUser){g.find(".dataset-actions .left").append(this._render_visualizationsButton());this._renderTags(g);this._renderAnnotation(g)}return g},_renderTags:function(g){this.tagsEditor=new TagsEditor({model:this.model,el:g.find(".tags-display"),onshowFirstTime:function(){this.render()},$activator:faIconButton({title:_l("Edit dataset tags"),classes:"dataset-tag-btn",faIcon:"fa-tags"}).appendTo(g.find(".dataset-actions .right"))})},_renderAnnotation:function(g){this.annotationEditor=new AnnotationEditor({model:this.model,el:g.find(".annotation-display"),onshowFirstTime:function(){this.render()},$activator:faIconButton({title:_l("Edit dataset annotation"),classes:"dataset-annotate-btn",faIcon:"fa-comment"}).appendTo(g.find(".dataset-actions .right"))})},makeDbkeyEditLink:function(g){if(this.model.get("metadata_dbkey")==="?"&&!this.model.isDeletedOrPurged()){g.find(".dataset-dbkey .value").replaceWith($('<a target="galaxy_main">?</a>').attr("href",this.urls.edit))}},events:{"click .dataset-title-bar":"toggleBodyVisibility","click .dataset-undelete":function(g){this.model.undelete();return false},"click .dataset-unhide":function(g){this.model.unhide();return false},"click .dataset-purge":"confirmPurge"},confirmPurge:function c(g){this.model.purge();return false},toString:function(){var g=(this.model)?(this.model+""):("(no model)");return"HDAView("+g+")"}});function e(g,h){action=function(){Galaxy.frame.add({title:"Scatterplot",type:"url",content:g+"/scatterplot?"+$.param(h),target:"galaxy_main",scratchbook:true});$("div.popmenu-wrapper").remove();return false};return action}function b(g,i,h){return function(){var j={};if(h){j["f-dbkey"]=h}$.ajax({url:g+"/list_tracks?"+$.param(j),dataType:"html",error:function(){alert(("Could not add this dataset to browser")+".")},success:function(k){var l=window.parent;l.Galaxy.modal.show({title:"View Data in a New or Saved Visualization",buttons:{Cancel:function(){l.Galaxy.modal.hide()},"View in saved visualization":function(){l.Galaxy.modal.show({title:"Add Data to Saved Visualization",body:k,buttons:{Cancel:function(){l.Galaxy.modal.hide()},"Add to visualization":function(){$(l.document).find("input[name=id]:checked").each(function(){l.Galaxy.modal.hide();var m=$(this).val();i.id=m;l.Galaxy.frame.add({title:"Trackster",type:"url",content:g+"/trackster?"+$.param(i),scratchbook:true})})}}})},"View in new visualization":function(){l.Galaxy.modal.hide();var m=g+"/trackster?"+$.param(i);l.Galaxy.frame.add({title:"Trackster",type:"url",content:m,scratchbook:true})}}})}});return false}}return{HDAEditView:f}});
\ No newline at end of file
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: Update jquery.form.js to 3.45 and fix chrome upload bug; pack scripts
by commits-noreply@bitbucket.org 15 Nov '13
by commits-noreply@bitbucket.org 15 Nov '13
15 Nov '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/a61de575700c/
Changeset: a61de575700c
User: carlfeberhard
Date: 2013-11-15 21:18:18
Summary: Update jquery.form.js to 3.45 and fix chrome upload bug; pack scripts
Affected #: 6 files
diff -r e057f2263f4bf8d2f5c277ae09360e36aa96cbbb -r a61de575700cc4c2e648699591415a090b3ee4e8 static/scripts/libs/jquery/jquery.form.js
--- a/static/scripts/libs/jquery/jquery.form.js
+++ b/static/scripts/libs/jquery/jquery.form.js
@@ -1,447 +1,785 @@
/*!
* jQuery Form Plugin
- * version: 2.63 (29-JAN-2011)
- * @requires jQuery v1.3.2 or later
- *
+ * version: 3.45.0-2013.10.17
+ * Requires jQuery v1.5 or later
+ * Copyright (c) 2013 M. Alsup
* Examples and documentation at: http://malsup.com/jquery/form/
- * Dual licensed under the MIT and GPL licenses:
- * http://www.opensource.org/licenses/mit-license.php
- * http://www.gnu.org/licenses/gpl.html
+ * Project repository: https://github.com/malsup/form
+ * Dual licensed under the MIT and GPL licenses.
+ * https://github.com/malsup/form#copyright-and-license
*/
+/*global ActiveXObject */
;(function($) {
+"use strict";
/*
- Usage Note:
- -----------
- Do not use both ajaxSubmit and ajaxForm on the same form. These
- functions are intended to be exclusive. Use ajaxSubmit if you want
- to bind your own submit handler to the form. For example,
+ Usage Note:
+ -----------
+ Do not use both ajaxSubmit and ajaxForm on the same form. These
+ functions are mutually exclusive. Use ajaxSubmit if you want
+ to bind your own submit handler to the form. For example,
- $(document).ready(function() {
- $('#myForm').bind('submit', function(e) {
- e.preventDefault(); // <-- important
- $(this).ajaxSubmit({
- target: '#output'
- });
- });
- });
+ $(document).ready(function() {
+ $('#myForm').on('submit', function(e) {
+ e.preventDefault(); // <-- important
+ $(this).ajaxSubmit({
+ target: '#output'
+ });
+ });
+ });
- Use ajaxForm when you want the plugin to manage all the event binding
- for you. For example,
+ Use ajaxForm when you want the plugin to manage all the event binding
+ for you. For example,
- $(document).ready(function() {
- $('#myForm').ajaxForm({
- target: '#output'
- });
- });
+ $(document).ready(function() {
+ $('#myForm').ajaxForm({
+ target: '#output'
+ });
+ });
- When using ajaxForm, the ajaxSubmit function will be invoked for you
- at the appropriate time.
+ You can also use ajaxForm with delegation (requires jQuery v1.7+), so the
+ form does not have to exist when you invoke ajaxForm:
+
+ $('#myForm').ajaxForm({
+ delegation: true,
+ target: '#output'
+ });
+
+ When using ajaxForm, the ajaxSubmit function will be invoked for you
+ at the appropriate time.
*/
/**
+ * Feature detection
+ */
+var feature = {};
+feature.fileapi = $("<input type='file'/>").get(0).files !== undefined;
+feature.formdata = window.FormData !== undefined;
+
+var hasProp = !!$.fn.prop;
+
+// attr2 uses prop when it can but checks the return type for
+// an expected string. this accounts for the case where a form
+// contains inputs with names like "action" or "method"; in those
+// cases "prop" returns the element
+$.fn.attr2 = function() {
+ if ( ! hasProp )
+ return this.attr.apply(this, arguments);
+ var val = this.prop.apply(this, arguments);
+ if ( ( val && val.jquery ) || typeof val === 'string' )
+ return val;
+ return this.attr.apply(this, arguments);
+};
+
+/**
* ajaxSubmit() provides a mechanism for immediately submitting
* an HTML form using AJAX.
*/
$.fn.ajaxSubmit = function(options) {
- // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
- if (!this.length) {
- log('ajaxSubmit: skipping submit process - no element selected');
- return this;
- }
+ /*jshint scripturl:true */
- if (typeof options == 'function') {
- options = { success: options };
- }
+ // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
+ if (!this.length) {
+ log('ajaxSubmit: skipping submit process - no element selected');
+ return this;
+ }
- var action = this.attr('action');
- var url = (typeof action === 'string') ? $.trim(action) : '';
- if (url) {
- // clean url (don't include hash vaue)
- url = (url.match(/^([^#]+)/)||[])[1];
- }
- url = url || window.location.href || '';
+ var method, action, url, $form = this;
- options = $.extend(true, {
- url: url,
- type: this[0].getAttribute('method') || 'GET', // IE7 massage (see issue 57)
- iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
- }, options);
+ if (typeof options == 'function') {
+ options = { success: options };
+ }
+ else if ( options === undefined ) {
+ options = {};
+ }
- // hook for manipulating the form data before it is extracted;
- // convenient for use with rich editors like tinyMCE or FCKEditor
- var veto = {};
- this.trigger('form-pre-serialize', [this, options, veto]);
- if (veto.veto) {
- log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
- return this;
- }
+ method = options.type || this.attr2('method');
+ action = options.url || this.attr2('action');
- // provide opportunity to alter form data before it is serialized
- if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
- log('ajaxSubmit: submit aborted via beforeSerialize callback');
- return this;
- }
+ url = (typeof action === 'string') ? $.trim(action) : '';
+ url = url || window.location.href || '';
+ if (url) {
+ // clean url (don't include hash vaue)
+ url = (url.match(/^([^#]+)/)||[])[1];
+ }
- var n,v,a = this.formToArray(options.semantic);
- if (options.data) {
- options.extraData = options.data;
- for (n in options.data) {
- if(options.data[n] instanceof Array) {
- for (var k in options.data[n]) {
- a.push( { name: n, value: options.data[n][k] } );
- }
- }
- else {
- v = options.data[n];
- v = $.isFunction(v) ? v() : v; // if value is fn, invoke it
- a.push( { name: n, value: v } );
- }
- }
- }
+ options = $.extend(true, {
+ url: url,
+ success: $.ajaxSettings.success,
+ type: method || $.ajaxSettings.type,
+ iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
+ }, options);
- // give pre-submit callback an opportunity to abort the submit
- if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
- log('ajaxSubmit: submit aborted via beforeSubmit callback');
- return this;
- }
+ // hook for manipulating the form data before it is extracted;
+ // convenient for use with rich editors like tinyMCE or FCKEditor
+ var veto = {};
+ this.trigger('form-pre-serialize', [this, options, veto]);
+ if (veto.veto) {
+ log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
+ return this;
+ }
- // fire vetoable 'validate' event
- this.trigger('form-submit-validate', [a, this, options, veto]);
- if (veto.veto) {
- log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
- return this;
- }
+ // provide opportunity to alter form data before it is serialized
+ if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
+ log('ajaxSubmit: submit aborted via beforeSerialize callback');
+ return this;
+ }
- var q = $.param(a);
+ var traditional = options.traditional;
+ if ( traditional === undefined ) {
+ traditional = $.ajaxSettings.traditional;
+ }
- if (options.type.toUpperCase() == 'GET') {
- options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
- options.data = null; // data is null for 'get'
- }
- else {
- options.data = q; // data is the query string for 'post'
- }
+ var elements = [];
+ var qx, a = this.formToArray(options.semantic, elements);
+ if (options.data) {
+ options.extraData = options.data;
+ qx = $.param(options.data, traditional);
+ }
- var $form = this, callbacks = [];
- if (options.resetForm) {
- callbacks.push(function() { $form.resetForm(); });
- }
- if (options.clearForm) {
- callbacks.push(function() { $form.clearForm(); });
- }
+ // give pre-submit callback an opportunity to abort the submit
+ if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
+ log('ajaxSubmit: submit aborted via beforeSubmit callback');
+ return this;
+ }
- // perform a load on the target only if dataType is not provided
- if (!options.dataType && options.target) {
- var oldSuccess = options.success || function(){};
- callbacks.push(function(data) {
- var fn = options.replaceTarget ? 'replaceWith' : 'html';
- $(options.target)[fn](data).each(oldSuccess, arguments);
- });
- }
- else if (options.success) {
- callbacks.push(options.success);
- }
+ // fire vetoable 'validate' event
+ this.trigger('form-submit-validate', [a, this, options, veto]);
+ if (veto.veto) {
+ log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
+ return this;
+ }
- options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
- var context = options.context || options; // jQuery 1.4+ supports scope context
- for (var i=0, max=callbacks.length; i < max; i++) {
- callbacks[i].apply(context, [data, status, xhr || $form, $form]);
- }
- };
+ var q = $.param(a, traditional);
+ if (qx) {
+ q = ( q ? (q + '&' + qx) : qx );
+ }
+ if (options.type.toUpperCase() == 'GET') {
+ options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
+ options.data = null; // data is null for 'get'
+ }
+ else {
+ options.data = q; // data is the query string for 'post'
+ }
- // are there files to upload?
- var fileInputs = $('input:file', this).length > 0;
- var mp = 'multipart/form-data';
- var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
+ var callbacks = [];
+ if (options.resetForm) {
+ callbacks.push(function() { $form.resetForm(); });
+ }
+ if (options.clearForm) {
+ callbacks.push(function() { $form.clearForm(options.includeHidden); });
+ }
- // options.iframe allows user to force iframe mode
- // 06-NOV-09: now defaulting to iframe mode if file input is detected
- if (options.iframe !== false && (fileInputs || options.iframe || multipart)) {
- // hack to fix Safari hang (thanks to Tim Molendijk for this)
- // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510…
- if (options.closeKeepAlive) {
- $.get(options.closeKeepAlive, fileUpload);
- }
- else {
- fileUpload();
- }
- }
- else {
- $.ajax(options);
- }
+ // perform a load on the target only if dataType is not provided
+ if (!options.dataType && options.target) {
+ var oldSuccess = options.success || function(){};
+ callbacks.push(function(data) {
+ var fn = options.replaceTarget ? 'replaceWith' : 'html';
+ $(options.target)[fn](data).each(oldSuccess, arguments);
+ });
+ }
+ else if (options.success) {
+ callbacks.push(options.success);
+ }
- // fire 'notify' event
- this.trigger('form-submit-notify', [this, options]);
- return this;
+ options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
+ var context = options.context || this ; // jQuery 1.4+ supports scope context
+ for (var i=0, max=callbacks.length; i < max; i++) {
+ callbacks[i].apply(context, [data, status, xhr || $form, $form]);
+ }
+ };
+ if (options.error) {
+ var oldError = options.error;
+ options.error = function(xhr, status, error) {
+ var context = options.context || this;
+ oldError.apply(context, [xhr, status, error, $form]);
+ };
+ }
- // private function for handling file uploads (hat tip to YAHOO!)
- function fileUpload() {
- var form = $form[0];
+ if (options.complete) {
+ var oldComplete = options.complete;
+ options.complete = function(xhr, status) {
+ var context = options.context || this;
+ oldComplete.apply(context, [xhr, status, $form]);
+ };
+ }
- if ($(':input[name=submit],:input[id=submit]', form).length) {
- // if there is an input with a name or id of 'submit' then we won't be
- // able to invoke the submit fn on the form (at least not x-browser)
- alert('Error: Form elements must not have name or id of "submit".');
- return;
- }
-
- var s = $.extend(true, {}, $.ajaxSettings, options);
- s.context = s.context || s;
- var id = 'jqFormIO' + (new Date().getTime()), fn = '_'+id;
- var $io = $('<iframe id="' + id + '" name="' + id + '" src="'+ s.iframeSrc +'" />');
- var io = $io[0];
+ // are there files to upload?
- $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
+ // [value] (issue #113), also see comment:
+ // https://github.com/malsup/form/commit/588306aedba1de01388032d5f42a60159eea9…
+ var fileInputs = $('input[type=file]:enabled', this).filter(function() { return $(this).val() !== ''; });
- var xhr = { // mock object
- aborted: 0,
- responseText: null,
- responseXML: null,
- status: 0,
- statusText: 'n/a',
- getAllResponseHeaders: function() {},
- getResponseHeader: function() {},
- setRequestHeader: function() {},
- abort: function() {
- this.aborted = 1;
- $io.attr('src', s.iframeSrc); // abort op in progress
- }
- };
+ var hasFileInputs = fileInputs.length > 0;
+ var mp = 'multipart/form-data';
+ var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
- var g = s.global;
- // trigger ajax global events so that activity/block indicators work like normal
- if (g && ! $.active++) {
- $.event.trigger("ajaxStart");
- }
- if (g) {
- $.event.trigger("ajaxSend", [xhr, s]);
- }
+ var fileAPI = feature.fileapi && feature.formdata;
+ log("fileAPI :" + fileAPI);
+ var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI;
- if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
- if (s.global) {
- $.active--;
- }
- return;
- }
- if (xhr.aborted) {
- return;
- }
+ var jqxhr;
- var timedOut = 0;
+ // options.iframe allows user to force iframe mode
+ // 06-NOV-09: now defaulting to iframe mode if file input is detected
+ if (options.iframe !== false && (options.iframe || shouldUseFrame)) {
+ // hack to fix Safari hang (thanks to Tim Molendijk for this)
+ // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510…
+ if (options.closeKeepAlive) {
+ $.get(options.closeKeepAlive, function() {
+ jqxhr = fileUploadIframe(a);
+ });
+ }
+ else {
+ jqxhr = fileUploadIframe(a);
+ }
+ }
+ else if ((hasFileInputs || multipart) && fileAPI) {
+ jqxhr = fileUploadXhr(a);
+ }
+ else {
+ jqxhr = $.ajax(options);
+ }
- // add submitting element to data if we know it
- var sub = form.clk;
- if (sub) {
- var n = sub.name;
- if (n && !sub.disabled) {
- s.extraData = s.extraData || {};
- s.extraData[n] = sub.value;
- if (sub.type == "image") {
- s.extraData[n+'.x'] = form.clk_x;
- s.extraData[n+'.y'] = form.clk_y;
- }
- }
- }
+ $form.removeData('jqxhr').data('jqxhr', jqxhr);
- // take a breath so that pending repaints get some cpu time before the upload starts
- function doSubmit() {
- // make sure form attrs are set
- var t = $form.attr('target'), a = $form.attr('action');
+ // clear element array
+ for (var k=0; k < elements.length; k++)
+ elements[k] = null;
- // update form attrs in IE friendly way
- form.setAttribute('target',id);
- if (form.getAttribute('method') != 'POST') {
- form.setAttribute('method', 'POST');
- }
- if (form.getAttribute('action') != s.url) {
- form.setAttribute('action', s.url);
- }
+ // fire 'notify' event
+ this.trigger('form-submit-notify', [this, options]);
+ return this;
- // ie borks in some cases when setting encoding
- if (! s.skipEncodingOverride) {
- $form.attr({
- encoding: 'multipart/form-data',
- enctype: 'multipart/form-data'
- });
- }
+ // utility fn for deep serialization
+ function deepSerialize(extraData){
+ var serialized = $.param(extraData, options.traditional).split('&');
+ var len = serialized.length;
+ var result = [];
+ var i, part;
+ for (i=0; i < len; i++) {
+ // #252; undo param space replacement
+ serialized[i] = serialized[i].replace(/\+/g,' ');
+ part = serialized[i].split('=');
+ // #278; use array instead of object storage, favoring array serializations
+ result.push([decodeURIComponent(part[0]), decodeURIComponent(part[1])]);
+ }
+ return result;
+ }
- // support timout
- if (s.timeout) {
- setTimeout(function() { timedOut = true; cb(); }, s.timeout);
- }
+ // XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz)
+ function fileUploadXhr(a) {
+ var formdata = new FormData();
- // add "extra" data to form if provided in options
- var extraInputs = [];
- try {
- if (s.extraData) {
- for (var n in s.extraData) {
- extraInputs.push(
- $('<input type="hidden" name="'+n+'" value="'+s.extraData[n]+'" />')
- .appendTo(form)[0]);
- }
- }
+ for (var i=0; i < a.length; i++) {
+ formdata.append(a[i].name, a[i].value);
+ }
- // add iframe to doc and submit the form
- $io.appendTo('body');
- io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
- form.submit();
- }
- finally {
- // reset attrs and remove "extra" input elements
- form.setAttribute('action',a);
- if(t) {
- form.setAttribute('target', t);
- } else {
- $form.removeAttr('target');
- }
- $(extraInputs).remove();
- }
- }
+ if (options.extraData) {
+ var serializedData = deepSerialize(options.extraData);
+ for (i=0; i < serializedData.length; i++)
+ if (serializedData[i])
+ formdata.append(serializedData[i][0], serializedData[i][1]);
+ }
- if (s.forceSync) {
- doSubmit();
- }
- else {
- setTimeout(doSubmit, 10); // this lets dom updates render
- }
-
- var data, doc, domCheckCount = 50;
+ options.data = null;
- function cb() {
- doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
- if (!doc || doc.location.href == s.iframeSrc) {
- // response not received yet
- return;
- }
- io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
+ var s = $.extend(true, {}, $.ajaxSettings, options, {
+ contentType: false,
+ processData: false,
+ cache: false,
+ type: method || 'POST'
+ });
- var ok = true;
- try {
- if (timedOut) {
- throw 'timeout';
- }
+ if (options.uploadProgress) {
+ // workaround because jqXHR does not expose upload property
+ s.xhr = function() {
+ var xhr = $.ajaxSettings.xhr();
+ if (xhr.upload) {
+ xhr.upload.addEventListener('progress', function(event) {
+ var percent = 0;
+ var position = event.loaded || event.position; /*event.position is deprecated*/
+ var total = event.total;
+ if (event.lengthComputable) {
+ percent = Math.ceil(position / total * 100);
+ }
+ options.uploadProgress(event, position, total, percent);
+ }, false);
+ }
+ return xhr;
+ };
+ }
- var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
- log('isXml='+isXml);
- if (!isXml && window.opera && (doc.body == null || doc.body.innerHTML == '')) {
- if (--domCheckCount) {
- // in some browsers (Opera) the iframe DOM is not always traversable when
- // the onload callback fires, so we loop a bit to accommodate
- log('requeing onLoad callback, DOM not available');
- setTimeout(cb, 250);
- return;
- }
- // let this fall through because server response could be an empty document
- //log('Could not access iframe DOM after mutiple tries.');
- //throw 'DOMException: not available';
- }
+ s.data = null;
+ var beforeSend = s.beforeSend;
+ s.beforeSend = function(xhr, o) {
+ //Send FormData() provided by user
+ if (options.formData)
+ o.data = options.formData;
+ else
+ o.data = formdata;
+ if(beforeSend)
+ beforeSend.call(this, xhr, o);
+ };
+ return $.ajax(s);
+ }
- //log('response detected');
- xhr.responseText = doc.body ? doc.body.innerHTML : doc.documentElement ? doc.documentElement.innerHTML : null;
- xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
- xhr.getResponseHeader = function(header){
- var headers = {'content-type': s.dataType};
- return headers[header];
- };
+ // private function for handling file uploads (hat tip to YAHOO!)
+ function fileUploadIframe(a) {
+ var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle;
+ var deferred = $.Deferred();
- var scr = /(json|script)/.test(s.dataType);
- if (scr || s.textarea) {
- // see if user embedded response in textarea
- var ta = doc.getElementsByTagName('textarea')[0];
- if (ta) {
- xhr.responseText = ta.value;
- }
- else if (scr) {
- // account for browsers injecting pre around json response
- var pre = doc.getElementsByTagName('pre')[0];
- var b = doc.getElementsByTagName('body')[0];
- if (pre) {
- xhr.responseText = pre.textContent;
- }
- else if (b) {
- xhr.responseText = b.innerHTML;
- }
- }
- }
- else if (s.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
- xhr.responseXML = toXml(xhr.responseText);
- }
-
- data = httpData(xhr, s.dataType, s);
- }
- catch(e){
- log('error caught:',e);
- ok = false;
- xhr.error = e;
- s.error.call(s.context, xhr, 'error', e);
- g && $.event.trigger("ajaxError", [xhr, s, e]);
- }
-
- if (xhr.aborted) {
- log('upload aborted');
- ok = false;
- }
+ // #341
+ deferred.abort = function(status) {
+ xhr.abort(status);
+ };
- // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
- if (ok) {
- s.success.call(s.context, data, 'success', xhr);
- g && $.event.trigger("ajaxSuccess", [xhr, s]);
- }
-
- g && $.event.trigger("ajaxComplete", [xhr, s]);
+ if (a) {
+ // ensure that every serialized input is still enabled
+ for (i=0; i < elements.length; i++) {
+ el = $(elements[i]);
+ if ( hasProp )
+ el.prop('disabled', false);
+ else
+ el.removeAttr('disabled');
+ }
+ }
- if (g && ! --$.active) {
- $.event.trigger("ajaxStop");
- }
-
- s.complete && s.complete.call(s.context, xhr, ok ? 'success' : 'error');
+ s = $.extend(true, {}, $.ajaxSettings, options);
+ s.context = s.context || s;
+ id = 'jqFormIO' + (new Date().getTime());
+ if (s.iframeTarget) {
+ $io = $(s.iframeTarget);
+ n = $io.attr2('name');
+ if (!n)
+ $io.attr2('name', id);
+ else
+ id = n;
+ }
+ else {
+ $io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />');
+ $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
+ }
+ io = $io[0];
- // clean up
- setTimeout(function() {
- $io.removeData('form-plugin-onload');
- $io.remove();
- xhr.responseXML = null;
- }, 100);
- }
- var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)
- if (window.ActiveXObject) {
- doc = new ActiveXObject('Microsoft.XMLDOM');
- doc.async = 'false';
- doc.loadXML(s);
- }
- else {
- doc = (new DOMParser()).parseFromString(s, 'text/xml');
- }
- return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;
- };
- var parseJSON = $.parseJSON || function(s) {
- return window['eval']('(' + s + ')');
- };
-
- var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4
- var ct = xhr.getResponseHeader('content-type') || '',
- xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,
- data = xml ? xhr.responseXML : xhr.responseText;
+ xhr = { // mock object
+ aborted: 0,
+ responseText: null,
+ responseXML: null,
+ status: 0,
+ statusText: 'n/a',
+ getAllResponseHeaders: function() {},
+ getResponseHeader: function() {},
+ setRequestHeader: function() {},
+ abort: function(status) {
+ var e = (status === 'timeout' ? 'timeout' : 'aborted');
+ log('aborting upload... ' + e);
+ this.aborted = 1;
- if (xml && data.documentElement.nodeName === 'parsererror') {
- $.error && $.error('parsererror');
- }
- if (s && s.dataFilter) {
- data = s.dataFilter(data, type);
- }
- if (typeof data === 'string') {
- if (type === 'json' || !type && ct.indexOf('json') >= 0) {
- data = parseJSON(data);
- } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {
- $.globalEval(data);
- }
- }
- return data;
- };
- }
+ try { // #214, #257
+ if (io.contentWindow.document.execCommand) {
+ io.contentWindow.document.execCommand('Stop');
+ }
+ }
+ catch(ignore) {}
+
+ $io.attr('src', s.iframeSrc); // abort op in progress
+ xhr.error = e;
+ if (s.error)
+ s.error.call(s.context, xhr, e, status);
+ if (g)
+ $.event.trigger("ajaxError", [xhr, s, e]);
+ if (s.complete)
+ s.complete.call(s.context, xhr, e);
+ }
+ };
+
+ g = s.global;
+ // trigger ajax global events so that activity/block indicators work like normal
+ if (g && 0 === $.active++) {
+ $.event.trigger("ajaxStart");
+ }
+ if (g) {
+ $.event.trigger("ajaxSend", [xhr, s]);
+ }
+
+ if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
+ if (s.global) {
+ $.active--;
+ }
+ deferred.reject();
+ return deferred;
+ }
+ if (xhr.aborted) {
+ deferred.reject();
+ return deferred;
+ }
+
+ // add submitting element to data if we know it
+ sub = form.clk;
+ if (sub) {
+ n = sub.name;
+ if (n && !sub.disabled) {
+ s.extraData = s.extraData || {};
+ s.extraData[n] = sub.value;
+ if (sub.type == "image") {
+ s.extraData[n+'.x'] = form.clk_x;
+ s.extraData[n+'.y'] = form.clk_y;
+ }
+ }
+ }
+
+ var CLIENT_TIMEOUT_ABORT = 1;
+ var SERVER_ABORT = 2;
+
+ function getDoc(frame) {
+ /* it looks like contentWindow or contentDocument do not
+ * carry the protocol property in ie8, when running under ssl
+ * frame.document is the only valid response document, since
+ * the protocol is know but not on the other two objects. strange?
+ * "Same origin policy" http://en.wikipedia.org/wiki/Same_origin_policy
+ */
+
+ var doc = null;
+
+ // IE8 cascading access check
+ try {
+ if (frame.contentWindow) {
+ doc = frame.contentWindow.document;
+ }
+ } catch(err) {
+ // IE8 access denied under ssl & missing protocol
+ log('cannot get iframe.contentWindow document: ' + err);
+ }
+
+ if (doc) { // successful getting content
+ return doc;
+ }
+
+ try { // simply checking may throw in ie8 under ssl or mismatched protocol
+ doc = frame.contentDocument ? frame.contentDocument : frame.document;
+ } catch(err) {
+ // last attempt
+ log('cannot get iframe.contentDocument: ' + err);
+ doc = frame.document;
+ }
+ return doc;
+ }
+
+ // Rails CSRF hack (thanks to Yvan Barthelemy)
+ var csrf_token = $('meta[name=csrf-token]').attr('content');
+ var csrf_param = $('meta[name=csrf-param]').attr('content');
+ if (csrf_param && csrf_token) {
+ s.extraData = s.extraData || {};
+ s.extraData[csrf_param] = csrf_token;
+ }
+
+ // take a breath so that pending repaints get some cpu time before the upload starts
+ function doSubmit() {
+ // make sure form attrs are set
+ var t = $form.attr2('target'), a = $form.attr2('action');
+
+ // update form attrs in IE friendly way
+ form.setAttribute('target',id);
+ if (!method || /post/i.test(method) ) {
+ form.setAttribute('method', 'POST');
+ }
+ if (a != s.url) {
+ form.setAttribute('action', s.url);
+ }
+
+ // ie borks in some cases when setting encoding
+ if (! s.skipEncodingOverride && (!method || /post/i.test(method))) {
+ $form.attr({
+ encoding: 'multipart/form-data',
+ enctype: 'multipart/form-data'
+ });
+ }
+
+ // support timout
+ if (s.timeout) {
+ timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout);
+ }
+
+ // look for server aborts
+ function checkState() {
+ try {
+ var state = getDoc(io).readyState;
+ log('state = ' + state);
+ if (state && state.toLowerCase() == 'uninitialized')
+ setTimeout(checkState,50);
+ }
+ catch(e) {
+ log('Server abort: ' , e, ' (', e.name, ')');
+ cb(SERVER_ABORT);
+ if (timeoutHandle)
+ clearTimeout(timeoutHandle);
+ timeoutHandle = undefined;
+ }
+ }
+
+ // add "extra" data to form if provided in options
+ var extraInputs = [];
+ try {
+ if (s.extraData) {
+ for (var n in s.extraData) {
+ if (s.extraData.hasOwnProperty(n)) {
+ // if using the $.param format that allows for multiple values with the same name
+ if($.isPlainObject(s.extraData[n]) && s.extraData[n].hasOwnProperty('name') && s.extraData[n].hasOwnProperty('value')) {
+ extraInputs.push(
+ $('<input type="hidden" name="'+s.extraData[n].name+'">').val(s.extraData[n].value)
+ .appendTo(form)[0]);
+ } else {
+ extraInputs.push(
+ $('<input type="hidden" name="'+n+'">').val(s.extraData[n])
+ .appendTo(form)[0]);
+ }
+ }
+ }
+ }
+
+ if (!s.iframeTarget) {
+ // add iframe to doc and submit the form
+ $io.appendTo('body');
+ }
+ if (io.attachEvent)
+ io.attachEvent('onload', cb);
+ else
+ io.addEventListener('load', cb, false);
+ setTimeout(checkState,15);
+
+ try {
+ form.submit();
+ } catch(err) {
+ // just in case form has element with name/id of 'submit'
+ var submitFn = document.createElement('form').submit;
+ submitFn.apply(form);
+ }
+ }
+ finally {
+ // reset attrs and remove "extra" input elements
+ form.setAttribute('action',a);
+ if(t) {
+ form.setAttribute('target', t);
+ } else {
+ $form.removeAttr('target');
+ }
+ $(extraInputs).remove();
+ }
+ }
+
+ if (s.forceSync) {
+ doSubmit();
+ }
+ else {
+ setTimeout(doSubmit, 10); // this lets dom updates render
+ }
+
+ var data, doc, domCheckCount = 50, callbackProcessed;
+
+ function cb(e) {
+ if (xhr.aborted || callbackProcessed) {
+ return;
+ }
+
+ doc = getDoc(io);
+ if(!doc) {
+ log('cannot access response document');
+ e = SERVER_ABORT;
+ }
+ if (e === CLIENT_TIMEOUT_ABORT && xhr) {
+ xhr.abort('timeout');
+ deferred.reject(xhr, 'timeout');
+ return;
+ }
+ else if (e == SERVER_ABORT && xhr) {
+ xhr.abort('server abort');
+ deferred.reject(xhr, 'error', 'server abort');
+ return;
+ }
+
+ if (!doc || doc.location.href == s.iframeSrc) {
+ // response not received yet
+ if (!timedOut)
+ return;
+ }
+ if (io.detachEvent)
+ io.detachEvent('onload', cb);
+ else
+ io.removeEventListener('load', cb, false);
+
+ var status = 'success', errMsg;
+ try {
+ if (timedOut) {
+ throw 'timeout';
+ }
+
+ var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
+ log('isXml='+isXml);
+ if (!isXml && window.opera && (doc.body === null || !doc.body.innerHTML)) {
+ if (--domCheckCount) {
+ // in some browsers (Opera) the iframe DOM is not always traversable when
+ // the onload callback fires, so we loop a bit to accommodate
+ log('requeing onLoad callback, DOM not available');
+ setTimeout(cb, 250);
+ return;
+ }
+ // let this fall through because server response could be an empty document
+ //log('Could not access iframe DOM after mutiple tries.');
+ //throw 'DOMException: not available';
+ }
+
+ //log('response detected');
+ var docRoot = doc.body ? doc.body : doc.documentElement;
+ xhr.responseText = docRoot ? docRoot.innerHTML : null;
+ xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
+ if (isXml)
+ s.dataType = 'xml';
+ xhr.getResponseHeader = function(header){
+ var headers = {'content-type': s.dataType};
+ return headers[header.toLowerCase()];
+ };
+ // support for XHR 'status' & 'statusText' emulation :
+ if (docRoot) {
+ xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status;
+ xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText;
+ }
+
+ var dt = (s.dataType || '').toLowerCase();
+ var scr = /(json|script|text)/.test(dt);
+ if (scr || s.textarea) {
+ // see if user embedded response in textarea
+ var ta = doc.getElementsByTagName('textarea')[0];
+ if (ta) {
+ xhr.responseText = ta.value;
+ // support for XHR 'status' & 'statusText' emulation :
+ xhr.status = Number( ta.getAttribute('status') ) || xhr.status;
+ xhr.statusText = ta.getAttribute('statusText') || xhr.statusText;
+ }
+ else if (scr) {
+ // account for browsers injecting pre around json response
+ var pre = doc.getElementsByTagName('pre')[0];
+ var b = doc.getElementsByTagName('body')[0];
+ if (pre) {
+ xhr.responseText = pre.textContent ? pre.textContent : pre.innerText;
+ }
+ else if (b) {
+ xhr.responseText = b.textContent ? b.textContent : b.innerText;
+ }
+ }
+ }
+ else if (dt == 'xml' && !xhr.responseXML && xhr.responseText) {
+ xhr.responseXML = toXml(xhr.responseText);
+ }
+
+ try {
+ data = httpData(xhr, dt, s);
+ }
+ catch (err) {
+ status = 'parsererror';
+ xhr.error = errMsg = (err || status);
+ }
+ }
+ catch (err) {
+ log('error caught: ',err);
+ status = 'error';
+ xhr.error = errMsg = (err || status);
+ }
+
+ if (xhr.aborted) {
+ log('upload aborted');
+ status = null;
+ }
+
+ if (xhr.status) { // we've set xhr.status
+ status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error';
+ }
+
+ // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
+ if (status === 'success') {
+ if (s.success)
+ s.success.call(s.context, data, 'success', xhr);
+ deferred.resolve(xhr.responseText, 'success', xhr);
+ if (g)
+ $.event.trigger("ajaxSuccess", [xhr, s]);
+ }
+ else if (status) {
+ if (errMsg === undefined)
+ errMsg = xhr.statusText;
+ if (s.error)
+ s.error.call(s.context, xhr, status, errMsg);
+ deferred.reject(xhr, 'error', errMsg);
+ if (g)
+ $.event.trigger("ajaxError", [xhr, s, errMsg]);
+ }
+
+ if (g)
+ $.event.trigger("ajaxComplete", [xhr, s]);
+
+ if (g && ! --$.active) {
+ $.event.trigger("ajaxStop");
+ }
+
+ if (s.complete)
+ s.complete.call(s.context, xhr, status);
+
+ callbackProcessed = true;
+ if (s.timeout)
+ clearTimeout(timeoutHandle);
+
+ // clean up
+ setTimeout(function() {
+ if (!s.iframeTarget)
+ $io.remove();
+ else //adding else to clean up existing iframe response.
+ $io.attr('src', s.iframeSrc);
+ xhr.responseXML = null;
+ }, 100);
+ }
+
+ var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)
+ if (window.ActiveXObject) {
+ doc = new ActiveXObject('Microsoft.XMLDOM');
+ doc.async = 'false';
+ doc.loadXML(s);
+ }
+ else {
+ doc = (new DOMParser()).parseFromString(s, 'text/xml');
+ }
+ return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;
+ };
+ var parseJSON = $.parseJSON || function(s) {
+ /*jslint evil:true */
+ return window['eval']('(' + s + ')');
+ };
+
+ var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4
+
+ var ct = xhr.getResponseHeader('content-type') || '',
+ xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,
+ data = xml ? xhr.responseXML : xhr.responseText;
+
+ if (xml && data.documentElement.nodeName === 'parsererror') {
+ if ($.error)
+ $.error('parsererror');
+ }
+ if (s && s.dataFilter) {
+ data = s.dataFilter(data, type);
+ }
+ if (typeof data === 'string') {
+ if (type === 'json' || !type && ct.indexOf('json') >= 0) {
+ data = parseJSON(data);
+ } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {
+ $.globalEval(data);
+ }
+ }
+ return data;
+ };
+
+ return deferred;
+ }
};
/**
@@ -450,9 +788,9 @@
* The advantages of using this method instead of ajaxSubmit() are:
*
* 1: This method will include coordinates for <input type="image" /> elements (if the element
- * is used to submit the form).
+ * is used to submit the form).
* 2. This method will include the submit element's name/value data (for the element that was
- * used to submit the form).
+ * used to submit the form).
* 3. This method binds the submit() method to the form for you.
*
* The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely
@@ -460,60 +798,83 @@
* the form itself.
*/
$.fn.ajaxForm = function(options) {
- // in jQuery 1.3+ we can fix mistakes with the ready state
- if (this.length === 0) {
- var o = { s: this.selector, c: this.context };
- if (!$.isReady && o.s) {
- log('DOM not ready, queuing ajaxForm');
- $(function() {
- $(o.s,o.c).ajaxForm(options);
- });
- return this;
- }
- // is your DOM ready? http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
- log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
- return this;
- }
-
- return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) {
- if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
- e.preventDefault();
- $(this).ajaxSubmit(options);
- }
- }).bind('click.form-plugin', function(e) {
- var target = e.target;
- var $el = $(target);
- if (!($el.is(":submit,input:image"))) {
- // is this a child element of the submit el? (ex: a span within a button)
- var t = $el.closest(':submit');
- if (t.length == 0) {
- return;
- }
- target = t[0];
- }
- var form = this;
- form.clk = target;
- if (target.type == 'image') {
- if (e.offsetX != undefined) {
- form.clk_x = e.offsetX;
- form.clk_y = e.offsetY;
- } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
- var offset = $el.offset();
- form.clk_x = e.pageX - offset.left;
- form.clk_y = e.pageY - offset.top;
- } else {
- form.clk_x = e.pageX - target.offsetLeft;
- form.clk_y = e.pageY - target.offsetTop;
- }
- }
- // clear form vars
- setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
- });
+ options = options || {};
+ options.delegation = options.delegation && $.isFunction($.fn.on);
+
+ // in jQuery 1.3+ we can fix mistakes with the ready state
+ if (!options.delegation && this.length === 0) {
+ var o = { s: this.selector, c: this.context };
+ if (!$.isReady && o.s) {
+ log('DOM not ready, queuing ajaxForm');
+ $(function() {
+ $(o.s,o.c).ajaxForm(options);
+ });
+ return this;
+ }
+ // is your DOM ready? http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
+ log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
+ return this;
+ }
+
+ if ( options.delegation ) {
+ $(document)
+ .off('submit.form-plugin', this.selector, doAjaxSubmit)
+ .off('click.form-plugin', this.selector, captureSubmittingElement)
+ .on('submit.form-plugin', this.selector, options, doAjaxSubmit)
+ .on('click.form-plugin', this.selector, options, captureSubmittingElement);
+ return this;
+ }
+
+ return this.ajaxFormUnbind()
+ .bind('submit.form-plugin', options, doAjaxSubmit)
+ .bind('click.form-plugin', options, captureSubmittingElement);
};
+// private event handlers
+function doAjaxSubmit(e) {
+ /*jshint validthis:true */
+ var options = e.data;
+ if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
+ e.preventDefault();
+ $(e.target).ajaxSubmit(options); // #365
+ }
+}
+
+function captureSubmittingElement(e) {
+ /*jshint validthis:true */
+ var target = e.target;
+ var $el = $(target);
+ if (!($el.is("[type=submit],[type=image]"))) {
+ // is this a child element of the submit el? (ex: a span within a button)
+ var t = $el.closest('[type=submit]');
+ if (t.length === 0) {
+ return;
+ }
+ target = t[0];
+ }
+ var form = this;
+ form.clk = target;
+ if (target.type == 'image') {
+ if (e.offsetX !== undefined) {
+ form.clk_x = e.offsetX;
+ form.clk_y = e.offsetY;
+ } else if (typeof $.fn.offset == 'function') {
+ var offset = $el.offset();
+ form.clk_x = e.pageX - offset.left;
+ form.clk_y = e.pageY - offset.top;
+ } else {
+ form.clk_x = e.pageX - target.offsetLeft;
+ form.clk_y = e.pageY - target.offsetTop;
+ }
+ }
+ // clear form vars
+ setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
+}
+
+
// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
$.fn.ajaxFormUnbind = function() {
- return this.unbind('submit.form-plugin click.form-plugin');
+ return this.unbind('submit.form-plugin click.form-plugin');
};
/**
@@ -527,56 +888,74 @@
* It is this array that is passed to pre-submit callback functions provided to the
* ajaxSubmit() and ajaxForm() methods.
*/
-$.fn.formToArray = function(semantic) {
- var a = [];
- if (this.length === 0) {
- return a;
- }
+$.fn.formToArray = function(semantic, elements) {
+ var a = [];
+ if (this.length === 0) {
+ return a;
+ }
- var form = this[0];
- var els = semantic ? form.getElementsByTagName('*') : form.elements;
- if (!els) {
- return a;
- }
-
- var i,j,n,v,el,max,jmax;
- for(i=0, max=els.length; i < max; i++) {
- el = els[i];
- n = el.name;
- if (!n) {
- continue;
- }
+ var form = this[0];
+ var els = semantic ? form.getElementsByTagName('*') : form.elements;
+ if (!els) {
+ return a;
+ }
- if (semantic && form.clk && el.type == "image") {
- // handle image inputs on the fly when semantic == true
- if(!el.disabled && form.clk == el) {
- a.push({name: n, value: $(el).val()});
- a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
- }
- continue;
- }
+ var i,j,n,v,el,max,jmax;
+ for(i=0, max=els.length; i < max; i++) {
+ el = els[i];
+ n = el.name;
+ if (!n || el.disabled) {
+ continue;
+ }
- v = $.fieldValue(el, true);
- if (v && v.constructor == Array) {
- for(j=0, jmax=v.length; j < jmax; j++) {
- a.push({name: n, value: v[j]});
- }
- }
- else if (v !== null && typeof v != 'undefined') {
- a.push({name: n, value: v});
- }
- }
+ if (semantic && form.clk && el.type == "image") {
+ // handle image inputs on the fly when semantic == true
+ if(form.clk == el) {
+ a.push({name: n, value: $(el).val(), type: el.type });
+ a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
+ }
+ continue;
+ }
- if (!semantic && form.clk) {
- // input type=='image' are not found in elements array! handle it here
- var $input = $(form.clk), input = $input[0];
- n = input.name;
- if (n && !input.disabled && input.type == 'image') {
- a.push({name: n, value: $input.val()});
- a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
- }
- }
- return a;
+ v = $.fieldValue(el, true);
+ if (v && v.constructor == Array) {
+ if (elements)
+ elements.push(el);
+ for(j=0, jmax=v.length; j < jmax; j++) {
+ a.push({name: n, value: v[j]});
+ }
+ }
+ else if (feature.fileapi && el.type == 'file') {
+ if (elements)
+ elements.push(el);
+ var files = el.files;
+ if (files.length) {
+ for (j=0; j < files.length; j++) {
+ a.push({name: n, value: files[j], type: el.type});
+ }
+ }
+ else {
+ // #180
+ a.push({ name: n, value: '', type: el.type });
+ }
+ }
+ else if (v !== null && typeof v != 'undefined') {
+ if (elements)
+ elements.push(el);
+ a.push({name: n, value: v, type: el.type, required: el.required});
+ }
+ }
+
+ if (!semantic && form.clk) {
+ // input type=='image' are not found in elements array! handle it here
+ var $input = $(form.clk), input = $input[0];
+ n = input.name;
+ if (n && !input.disabled && input.type == 'image') {
+ a.push({name: n, value: $input.val()});
+ a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
+ }
+ }
+ return a;
};
/**
@@ -584,8 +963,8 @@
* in the format: name1=value1&name2=value2
*/
$.fn.formSerialize = function(semantic) {
- //hand off to jQuery.param for proper encoding
- return $.param(this.formToArray(semantic));
+ //hand off to jQuery.param for proper encoding
+ return $.param(this.formToArray(semantic));
};
/**
@@ -593,51 +972,51 @@
* This method will return a string in the format: name1=value1&name2=value2
*/
$.fn.fieldSerialize = function(successful) {
- var a = [];
- this.each(function() {
- var n = this.name;
- if (!n) {
- return;
- }
- var v = $.fieldValue(this, successful);
- if (v && v.constructor == Array) {
- for (var i=0,max=v.length; i < max; i++) {
- a.push({name: n, value: v[i]});
- }
- }
- else if (v !== null && typeof v != 'undefined') {
- a.push({name: this.name, value: v});
- }
- });
- //hand off to jQuery.param for proper encoding
- return $.param(a);
+ var a = [];
+ this.each(function() {
+ var n = this.name;
+ if (!n) {
+ return;
+ }
+ var v = $.fieldValue(this, successful);
+ if (v && v.constructor == Array) {
+ for (var i=0,max=v.length; i < max; i++) {
+ a.push({name: n, value: v[i]});
+ }
+ }
+ else if (v !== null && typeof v != 'undefined') {
+ a.push({name: this.name, value: v});
+ }
+ });
+ //hand off to jQuery.param for proper encoding
+ return $.param(a);
};
/**
* Returns the value(s) of the element in the matched set. For example, consider the following form:
*
* <form><fieldset>
- * <input name="A" type="text" />
- * <input name="A" type="text" />
- * <input name="B" type="checkbox" value="B1" />
- * <input name="B" type="checkbox" value="B2"/>
- * <input name="C" type="radio" value="C1" />
- * <input name="C" type="radio" value="C2" />
+ * <input name="A" type="text" />
+ * <input name="A" type="text" />
+ * <input name="B" type="checkbox" value="B1" />
+ * <input name="B" type="checkbox" value="B2"/>
+ * <input name="C" type="radio" value="C1" />
+ * <input name="C" type="radio" value="C2" />
* </fieldset></form>
*
- * var v = $(':text').fieldValue();
+ * var v = $('input[type=text]').fieldValue();
* // if no values are entered into the text inputs
* v == ['','']
* // if values entered into the text inputs are 'foo' and 'bar'
* v == ['foo','bar']
*
- * var v = $(':checkbox').fieldValue();
+ * var v = $('input[type=checkbox]').fieldValue();
* // if neither checkbox is checked
* v === undefined
* // if both checkboxes are checked
* v == ['B1', 'B2']
*
- * var v = $(':radio').fieldValue();
+ * var v = $('input[type=radio]').fieldValue();
* // if neither radio is checked
* v === undefined
* // if first radio is checked
@@ -649,60 +1028,63 @@
* for each element is returned.
*
* Note: This method *always* returns an array. If no valid value can be determined the
- * array will be empty, otherwise it will contain one or more values.
+ * array will be empty, otherwise it will contain one or more values.
*/
$.fn.fieldValue = function(successful) {
- for (var val=[], i=0, max=this.length; i < max; i++) {
- var el = this[i];
- var v = $.fieldValue(el, successful);
- if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
- continue;
- }
- v.constructor == Array ? $.merge(val, v) : val.push(v);
- }
- return val;
+ for (var val=[], i=0, max=this.length; i < max; i++) {
+ var el = this[i];
+ var v = $.fieldValue(el, successful);
+ if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
+ continue;
+ }
+ if (v.constructor == Array)
+ $.merge(val, v);
+ else
+ val.push(v);
+ }
+ return val;
};
/**
* Returns the value of the field element.
*/
$.fieldValue = function(el, successful) {
- var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
- if (successful === undefined) {
- successful = true;
- }
+ var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
+ if (successful === undefined) {
+ successful = true;
+ }
- if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
- (t == 'checkbox' || t == 'radio') && !el.checked ||
- (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
- tag == 'select' && el.selectedIndex == -1)) {
- return null;
- }
+ if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
+ (t == 'checkbox' || t == 'radio') && !el.checked ||
+ (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
+ tag == 'select' && el.selectedIndex == -1)) {
+ return null;
+ }
- if (tag == 'select') {
- var index = el.selectedIndex;
- if (index < 0) {
- return null;
- }
- var a = [], ops = el.options;
- var one = (t == 'select-one');
- var max = (one ? index+1 : ops.length);
- for(var i=(one ? index : 0); i < max; i++) {
- var op = ops[i];
- if (op.selected) {
- var v = op.value;
- if (!v) { // extra pain for IE...
- v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
- }
- if (one) {
- return v;
- }
- a.push(v);
- }
- }
- return a;
- }
- return $(el).val();
+ if (tag == 'select') {
+ var index = el.selectedIndex;
+ if (index < 0) {
+ return null;
+ }
+ var a = [], ops = el.options;
+ var one = (t == 'select-one');
+ var max = (one ? index+1 : ops.length);
+ for(var i=(one ? index : 0); i < max; i++) {
+ var op = ops[i];
+ if (op.selected) {
+ var v = op.value;
+ if (!v) { // extra pain for IE...
+ v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
+ }
+ if (one) {
+ return v;
+ }
+ a.push(v);
+ }
+ }
+ return a;
+ }
+ return $(el).val();
};
/**
@@ -713,53 +1095,70 @@
* - inputs of type submit, button, reset, and hidden will *not* be effected
* - button elements will *not* be effected
*/
-$.fn.clearForm = function() {
- return this.each(function() {
- $('input,select,textarea', this).clearFields();
- });
+$.fn.clearForm = function(includeHidden) {
+ return this.each(function() {
+ $('input,select,textarea', this).clearFields(includeHidden);
+ });
};
/**
* Clears the selected form elements.
*/
-$.fn.clearFields = $.fn.clearInputs = function() {
- return this.each(function() {
- var t = this.type, tag = this.tagName.toLowerCase();
- if (t == 'text' || t == 'password' || tag == 'textarea') {
- this.value = '';
+$.fn.clearFields = $.fn.clearInputs = function(includeHidden) {
+ var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list
+ return this.each(function() {
+ var t = this.type, tag = this.tagName.toLowerCase();
+ if (re.test(t) || tag == 'textarea') {
+ this.value = '';
+ }
+ else if (t == 'checkbox' || t == 'radio') {
+ this.checked = false;
+ }
+ else if (tag == 'select') {
+ this.selectedIndex = -1;
+ }
+ else if (t == "file") {
+ if (/MSIE/.test(navigator.userAgent)) {
+ $(this).replaceWith($(this).clone(true));
+ } else {
+ $(this).val('');
+ }
}
- else if (t == 'checkbox' || t == 'radio') {
- this.checked = false;
- }
- else if (tag == 'select') {
- this.selectedIndex = -1;
- }
- });
+ else if (includeHidden) {
+ // includeHidden can be the value true, or it can be a selector string
+ // indicating a special test; for example:
+ // $('#myForm').clearForm('.special:hidden')
+ // the above would clean hidden inputs that have the class of 'special'
+ if ( (includeHidden === true && /hidden/.test(t)) ||
+ (typeof includeHidden == 'string' && $(this).is(includeHidden)) )
+ this.value = '';
+ }
+ });
};
/**
* Resets the form data. Causes all form elements to be reset to their original value.
*/
$.fn.resetForm = function() {
- return this.each(function() {
- // guard against an input with the name of 'reset'
- // note that IE reports the reset function as an 'object'
- if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
- this.reset();
- }
- });
+ return this.each(function() {
+ // guard against an input with the name of 'reset'
+ // note that IE reports the reset function as an 'object'
+ if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
+ this.reset();
+ }
+ });
};
/**
* Enables or disables any matching elements.
*/
$.fn.enable = function(b) {
- if (b === undefined) {
- b = true;
- }
- return this.each(function() {
- this.disabled = !b;
- });
+ if (b === undefined) {
+ b = true;
+ }
+ return this.each(function() {
+ this.disabled = !b;
+ });
};
/**
@@ -767,37 +1166,39 @@
* selects/deselects and matching option elements.
*/
$.fn.selected = function(select) {
- if (select === undefined) {
- select = true;
- }
- return this.each(function() {
- var t = this.type;
- if (t == 'checkbox' || t == 'radio') {
- this.checked = select;
- }
- else if (this.tagName.toLowerCase() == 'option') {
- var $sel = $(this).parent('select');
- if (select && $sel[0] && $sel[0].type == 'select-one') {
- // deselect all other options
- $sel.find('option').selected(false);
- }
- this.selected = select;
- }
- });
+ if (select === undefined) {
+ select = true;
+ }
+ return this.each(function() {
+ var t = this.type;
+ if (t == 'checkbox' || t == 'radio') {
+ this.checked = select;
+ }
+ else if (this.tagName.toLowerCase() == 'option') {
+ var $sel = $(this).parent('select');
+ if (select && $sel[0] && $sel[0].type == 'select-one') {
+ // deselect all other options
+ $sel.find('option').selected(false);
+ }
+ this.selected = select;
+ }
+ });
};
+// expose debug var
+$.fn.ajaxSubmit.debug = false;
+
// helper fn for console logging
-// set $.fn.ajaxSubmit.debug to true to enable debug logging
function log() {
- if ($.fn.ajaxSubmit.debug) {
- var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
- if (window.console && window.console.log) {
- window.console.log(msg);
- }
- else if (window.opera && window.opera.postError) {
- window.opera.postError(msg);
- }
- }
-};
+ if (!$.fn.ajaxSubmit.debug)
+ return;
+ var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
+ if (window.console && window.console.log) {
+ window.console.log(msg);
+ }
+ else if (window.opera && window.opera.postError) {
+ window.opera.postError(msg);
+ }
+}
-})(jQuery);
+})( (typeof(jQuery) != 'undefined') ? jQuery : window.Zepto );
diff -r e057f2263f4bf8d2f5c277ae09360e36aa96cbbb -r a61de575700cc4c2e648699591415a090b3ee4e8 static/scripts/packed/galaxy.grids.js
--- a/static/scripts/packed/galaxy.grids.js
+++ b/static/scripts/packed/galaxy.grids.js
@@ -1,1 +1,1 @@
-jQuery.ajaxSettings.traditional=true;var Grid=Backbone.Model.extend({defaults:{url_base:"",async:false,async_ops:[],categorical_filters:[],filters:{},sort_key:null,show_item_checkboxes:false,cur_page:1,num_pages:1,operation:undefined,item_ids:undefined},can_async_op:function(a){return _.indexOf(this.attributes.async_ops,a)!==-1},add_filter:function(e,f,b){if(b){var c=this.attributes.filters[e],a;if(c===null||c===undefined){a=f}else{if(typeof(c)=="string"){if(c=="All"){a=f}else{var d=[];d[0]=c;d[1]=f;a=d}}else{a=c;a.push(f)}}this.attributes.filters[e]=a}else{this.attributes.filters[e]=f}},remove_filter:function(b,e){var a=this.attributes.filters[b];if(a===null||a===undefined){return false}var d=true;if(typeof(a)==="string"){if(a=="All"){d=false}else{delete this.attributes.filters[b]}}else{var c=_.indexOf(a,e);if(c!==-1){a.splice(c,1)}else{d=false}}return d},get_url_data:function(){var a={async:this.attributes.async,sort:this.attributes.sort_key,page:this.attributes.cur_page,show_item_checkboxes:this.attributes.show_item_checkboxes};if(this.attributes.operation){a.operation=this.attributes.operation}if(this.attributes.item_ids){a.id=this.attributes.item_ids}var b=this;_.each(_.keys(b.attributes.filters),function(c){a["f-"+c]=b.attributes.filters[c]});return a}});function init_operation_buttons(){$("input[name=operation]:submit").each(function(){$(this).click(function(){var b=$(this).val();var a=[];$("input[name=id]:checked").each(function(){a.push($(this).val())});do_operation(b,a)})})}function init_grid_controls(){init_operation_buttons();$(".submit-image").each(function(){$(this).mousedown(function(){$(this).addClass("gray-background")});$(this).mouseup(function(){$(this).removeClass("gray-background")})});$(".sort-link").each(function(){$(this).click(function(){set_sort_condition($(this).attr("sort_key"));return false})});$(".page-link > a").each(function(){$(this).click(function(){set_page($(this).attr("page_num"));return false})});$(".categorical-filter > a").each(function(){$(this).click(function(){set_categorical_filter($(this).attr("filter_key"),$(this).attr("filter_val"));return false})});$(".text-filter-form").each(function(){$(this).submit(function(){var d=$(this).attr("column_key");var c=$("#input-"+d+"-filter");var e=c.val();c.val("");add_filter_condition(d,e,true);return false})});var a=$("#input-tags-filter");if(a.length){a.autocomplete(history_tag_autocomplete_url,{selectFirst:false,autoFill:false,highlight:false,mustMatch:false})}var b=$("#input-name-filter");if(b.length){b.autocomplete(history_name_autocomplete_url,{selectFirst:false,autoFill:false,highlight:false,mustMatch:false})}$(".advanced-search-toggle").each(function(){$(this).click(function(){$("#standard-search").slideToggle("fast");$("#advanced-search").slideToggle("fast");return false})})}function init_grid_elements(){$(".grid").each(function(){var b=$(this).find("input.grid-row-select-checkbox");var a=$(this).find("span.grid-selected-count");var c=function(){a.text($(b).filter(":checked").length)};$(b).each(function(){$(this).change(c)});c()});$(".label").each(function(){var a=$(this).attr("href");if(a!==undefined&&a.indexOf("operation=")!=-1){$(this).click(function(){do_operation_from_href($(this).attr("href"));return false})}});if($(".community_rating_star").length!==0){$(".community_rating_star").rating({})}make_popup_menus()}function go_page_one(){var a=grid.get("cur_page");if(a!==null&&a!==undefined&&a!=="all"){grid.set("cur_page",1)}}function add_filter_condition(c,e,a){if(e===""){return false}grid.add_filter(c,e,a);var d=$("<span>"+e+"<a href='javascript:void(0);'><span class='delete-search-icon' /></a></span>");d.addClass("text-filter-val");d.click(function(){grid.remove_filter(c,e);$(this).remove();go_page_one();update_grid()});var b=$("#"+c+"-filtering-criteria");b.append(d);go_page_one();update_grid()}function add_tag_to_grid_filter(c,b){var a=c+(b!==undefined&&b!==""?":"+b:"");$("#advanced-search").show("fast");add_filter_condition("tags",a,true)}function set_sort_condition(f){var e=grid.get("sort_key");var d=f;if(e.indexOf(f)!==-1){if(e.substring(0,1)!=="-"){d="-"+f}else{}}$(".sort-arrow").remove();var c=(d.substring(0,1)=="-")?"↑":"↓";var a=$("<span>"+c+"</span>").addClass("sort-arrow");var b=$("#"+f+"-header");b.append(a);grid.set("sort_key",d);go_page_one();update_grid()}function set_categorical_filter(b,d){var a=grid.get("categorical_filters")[b],c=grid.get("filters")[b];$("."+b+"-filter").each(function(){var h=$.trim($(this).text());var f=a[h];var g=f[b];if(g==d){$(this).empty();$(this).addClass("current-filter");$(this).append(h)}else{if(g==c){$(this).empty();var e=$("<a href='#'>"+h+"</a>");e.click(function(){set_categorical_filter(b,g)});$(this).removeClass("current-filter");$(this).append(e)}}});grid.add_filter(b,d);go_page_one();update_grid()}function set_page(a){$(".page-link").each(function(){var g=$(this).attr("id"),e=parseInt(g.split("-")[2],10),c=grid.get("cur_page"),f;if(e===a){f=$(this).children().text();$(this).empty();$(this).addClass("inactive-link");$(this).text(f)}else{if(e===c){f=$(this).text();$(this).empty();$(this).removeClass("inactive-link");var d=$("<a href='#'>"+f+"</a>");d.click(function(){set_page(e)});$(this).append(d)}}});var b=true;if(a==="all"){grid.set("cur_page",a);b=false}else{grid.set("cur_page",parseInt(a,10))}update_grid(b)}function do_operation(b,a){b=b.toLowerCase();grid.set({operation:b,item_ids:a});if(grid.can_async_op(b)){update_grid(true)}else{go_to_URL()}}function do_operation_from_href(c){var f=c.split("?");if(f.length>1){var a=f[1];var e=a.split("&");var b=null;var g=-1;for(var d=0;d<e.length;d++){if(e[d].indexOf("operation")!=-1){b=e[d].split("=")[1]}else{if(e[d].indexOf("id")!=-1){g=e[d].split("=")[1]}}}do_operation(b,g);return false}}function go_to_URL(){grid.set("async",false);window.location=grid.get("url_base")+"?"+$.param(grid.get_url_data())}function update_grid(a){if(!grid.get("async")){go_to_URL();return}var b=(grid.get("operation")?"POST":"GET");$(".loading-elt-overlay").show();$.ajax({type:b,url:grid.get("url_base"),data:grid.get_url_data(),error:function(){alert("Grid refresh failed")},success:function(d){var c=d.split("*****");$("#grid-table-body").html(c[0]);$("#grid-table-footer").html(c[1]);$("#grid-table-body").trigger("update");init_grid_elements();init_operation_buttons();make_popup_menus();$(".loading-elt-overlay").hide();var e=$.trim(c[2]);if(e!==""){$("#grid-message").html(e).show();setTimeout(function(){$("#grid-message").hide()},5000)}},complete:function(){grid.set({operation:undefined,item_ids:undefined})}})}function check_all_items(){var a=document.getElementById("check_all"),b=document.getElementsByTagName("input"),d=0,c;if(a.checked===true){for(c=0;c<b.length;c++){if(b[c].name.indexOf("id")!==-1){b[c].checked=true;d++}}}else{for(c=0;c<b.length;c++){if(b[c].name.indexOf("id")!==-1){b[c].checked=false}}}init_grid_elements()}function submit_operation(b,c){var a=$('input[name="id"]:checked').length;if(!a>0){return false}if(c!="None"&&c!=""){if(!confirm(c)){return false}}$("#operation").val(b.value);b.form.submit();return true};
\ No newline at end of file
+jQuery.ajaxSettings.traditional=true;var Grid=Backbone.Model.extend({defaults:{url_base:"",async:false,async_ops:[],categorical_filters:[],filters:{},sort_key:null,show_item_checkboxes:false,cur_page:1,num_pages:1,operation:undefined,item_ids:undefined},can_async_op:function(a){return _.indexOf(this.attributes.async_ops,a)!==-1},add_filter:function(e,f,b){if(b){var c=this.attributes.filters[e],a;if(c===null||c===undefined){a=f}else{if(typeof(c)=="string"){if(c=="All"){a=f}else{var d=[];d[0]=c;d[1]=f;a=d}}else{a=c;a.push(f)}}this.attributes.filters[e]=a}else{this.attributes.filters[e]=f}},remove_filter:function(b,e){var a=this.attributes.filters[b];if(a===null||a===undefined){return false}var d=true;if(typeof(a)==="string"){if(a=="All"){d=false}else{delete this.attributes.filters[b]}}else{var c=_.indexOf(a,e);if(c!==-1){a.splice(c,1)}else{d=false}}return d},get_url_data:function(){var a={async:this.attributes.async,sort:this.attributes.sort_key,page:this.attributes.cur_page,show_item_checkboxes:this.attributes.show_item_checkboxes};if(this.attributes.operation){a.operation=this.attributes.operation}if(this.attributes.item_ids){a.id=this.attributes.item_ids}var b=this;_.each(_.keys(b.attributes.filters),function(c){a["f-"+c]=b.attributes.filters[c]});return a}});function init_grid_controls(){$(".submit-image").each(function(){$(this).mousedown(function(){$(this).addClass("gray-background")});$(this).mouseup(function(){$(this).removeClass("gray-background")})});$(".sort-link").each(function(){$(this).click(function(){set_sort_condition($(this).attr("sort_key"));return false})});$(".page-link > a").each(function(){$(this).click(function(){set_page($(this).attr("page_num"));return false})});$(".categorical-filter > a").each(function(){$(this).click(function(){set_categorical_filter($(this).attr("filter_key"),$(this).attr("filter_val"));return false})});$(".text-filter-form").each(function(){$(this).submit(function(){var d=$(this).attr("column_key");var c=$("#input-"+d+"-filter");var e=c.val();c.val("");add_filter_condition(d,e,true);return false})});var a=$("#input-tags-filter");if(a.length){a.autocomplete(history_tag_autocomplete_url,{selectFirst:false,autoFill:false,highlight:false,mustMatch:false})}var b=$("#input-name-filter");if(b.length){b.autocomplete(history_name_autocomplete_url,{selectFirst:false,autoFill:false,highlight:false,mustMatch:false})}$(".advanced-search-toggle").each(function(){$(this).click(function(){$("#standard-search").slideToggle("fast");$("#advanced-search").slideToggle("fast");return false})})}function init_grid_elements(){$(".grid").each(function(){var b=$(this).find("input.grid-row-select-checkbox");var a=$(this).find("span.grid-selected-count");var c=function(){a.text($(b).filter(":checked").length)};$(b).each(function(){$(this).change(c)});c()});$(".label").each(function(){var a=$(this).attr("href");if(a!==undefined&&a.indexOf("operation=")!=-1){$(this).click(function(){do_operation_from_href($(this).attr("href"));return false})}});if($(".community_rating_star").length!==0){$(".community_rating_star").rating({})}make_popup_menus()}function go_page_one(){var a=grid.get("cur_page");if(a!==null&&a!==undefined&&a!=="all"){grid.set("cur_page",1)}}function add_filter_condition(c,e,a){if(e===""){return false}grid.add_filter(c,e,a);var d=$("<span>"+e+"<a href='javascript:void(0);'><span class='delete-search-icon' /></a></span>");d.addClass("text-filter-val");d.click(function(){grid.remove_filter(c,e);$(this).remove();go_page_one();update_grid()});var b=$("#"+c+"-filtering-criteria");b.append(d);go_page_one();update_grid()}function add_tag_to_grid_filter(c,b){var a=c+(b!==undefined&&b!==""?":"+b:"");$("#advanced-search").show("fast");add_filter_condition("tags",a,true)}function set_sort_condition(f){var e=grid.get("sort_key");var d=f;if(e.indexOf(f)!==-1){if(e.substring(0,1)!=="-"){d="-"+f}else{}}$(".sort-arrow").remove();var c=(d.substring(0,1)=="-")?"↑":"↓";var a=$("<span>"+c+"</span>").addClass("sort-arrow");var b=$("#"+f+"-header");b.append(a);grid.set("sort_key",d);go_page_one();update_grid()}function set_categorical_filter(b,d){var a=grid.get("categorical_filters")[b],c=grid.get("filters")[b];$("."+b+"-filter").each(function(){var h=$.trim($(this).text());var f=a[h];var g=f[b];if(g==d){$(this).empty();$(this).addClass("current-filter");$(this).append(h)}else{if(g==c){$(this).empty();var e=$("<a href='#'>"+h+"</a>");e.click(function(){set_categorical_filter(b,g)});$(this).removeClass("current-filter");$(this).append(e)}}});grid.add_filter(b,d);go_page_one();update_grid()}function set_page(a){$(".page-link").each(function(){var g=$(this).attr("id"),e=parseInt(g.split("-")[2],10),c=grid.get("cur_page"),f;if(e===a){f=$(this).children().text();$(this).empty();$(this).addClass("inactive-link");$(this).text(f)}else{if(e===c){f=$(this).text();$(this).empty();$(this).removeClass("inactive-link");var d=$("<a href='#'>"+f+"</a>");d.click(function(){set_page(e)});$(this).append(d)}}});var b=true;if(a==="all"){grid.set("cur_page",a);b=false}else{grid.set("cur_page",parseInt(a,10))}update_grid(b)}function do_operation(b,a){b=b.toLowerCase();grid.set({operation:b,item_ids:a});if(grid.can_async_op(b)){update_grid(true)}else{go_to_URL()}}function do_operation_from_href(c){var f=c.split("?");if(f.length>1){var a=f[1];var e=a.split("&");var b=null;var g=-1;for(var d=0;d<e.length;d++){if(e[d].indexOf("operation")!=-1){b=e[d].split("=")[1]}else{if(e[d].indexOf("id")!=-1){g=e[d].split("=")[1]}}}do_operation(b,g);return false}}function go_to_URL(){grid.set("async",false);window.location=grid.get("url_base")+"?"+$.param(grid.get_url_data())}function update_grid(a){if(!grid.get("async")){go_to_URL();return}var b=(grid.get("operation")?"POST":"GET");$(".loading-elt-overlay").show();$.ajax({type:b,url:grid.get("url_base"),data:grid.get_url_data(),error:function(){alert("Grid refresh failed")},success:function(d){var c=d.split("*****");$("#grid-table-body").html(c[0]);$("#grid-table-footer").html(c[1]);$("#grid-table-body").trigger("update");init_grid_elements();make_popup_menus();$(".loading-elt-overlay").hide();var e=$.trim(c[2]);if(e!==""){$("#grid-message").html(e).show();setTimeout(function(){$("#grid-message").hide()},5000)}},complete:function(){grid.set({operation:undefined,item_ids:undefined})}})}function check_all_items(){var a=document.getElementById("check_all"),b=document.getElementsByTagName("input"),d=0,c;if(a.checked===true){for(c=0;c<b.length;c++){if(b[c].name.indexOf("id")!==-1){b[c].checked=true;d++}}}else{for(c=0;c<b.length;c++){if(b[c].name.indexOf("id")!==-1){b[c].checked=false}}}init_grid_elements()}function submit_operation(d,e){var c=$('input[name="id"]:checked').length;if(!c>0){return false}if(e!="None"&&e!=""){if(!confirm(e)){return false}}var b=d.value;var a=[];$("input[name=id]:checked").each(function(){a.push($(this).val())});do_operation(b,a);return true};
\ No newline at end of file
diff -r e057f2263f4bf8d2f5c277ae09360e36aa96cbbb -r a61de575700cc4c2e648699591415a090b3ee4e8 static/scripts/packed/galaxy.masthead.js
--- a/static/scripts/packed/galaxy.masthead.js
+++ b/static/scripts/packed/galaxy.masthead.js
@@ -1,1 +1,1 @@
-define(["utils/galaxy.utils","libs/backbone/backbone-relational"],function(c){var a=Backbone.View.extend({el_masthead:"#everything",options:null,list:{},itemLast:null,itemCounter:0,$background:null,backgroundVisible:false,initialize:function(f){this.options=f;$("body").off();this.setElement($(this._template(f)));$(this.el_masthead).append($(this.el));this.$background=$(this.el).find("#masthead-background");var e=this;window.onbeforeunload=function(){var h="";for(key in e.list){if(e.list[key].options.on_unload){var g=e.list[key].options.on_unload();if(g){h+=g+" "}}}if(h!=""){return h}}},events:{click:"_eventRefresh",mousedown:function(f){f.preventDefault()}},append:function(e){return this._add(e,true)},prepend:function(e){return this._add(e,false)},_add:function(g,f){var e=$(this.el).find("#"+g.mastheadLocation);if(e){var h="masthead-item-"+this.itemCounter++;var i=$(g.el);i.attr("id",h);i.addClass("masthead-item");if(f){e.append(i)}else{e.prepend(i)}this.list[h]=g;return h}return null},_eventRefresh:function(h){var i=$(h.target).closest(".masthead-item");if(i.length){i=i.attr("id")}if(this.itemLast&&this.itemLast!=i){var g=this.list[this.itemLast];if(g){if(g.mastheadReset){g.mastheadReset()}}}var f=false;if(i){var g=this.list[i];if(g){if(g.mastheadReset){if(this.itemLast==i){f=this.backgroundVisible?false:true}else{f=true}}}}if(f){this.$background.show()}else{this.$background.hide()}this.backgroundVisible=f;this.itemLast=i},_templateItem:function(e){return'<div id="'+e+'" class="masthead-item"></div>'},_template:function(e){return'<div><div id="masthead" class="navbar navbar-fixed-top navbar-inverse"><div style="position: relative; right: -50%; float: left;"><div id="navbar" style="display: block; position: relative; right: 50%;"></div></div><div class="navbar-brand"><a href="'+e.logo_url+'"><img border="0" src="'+galaxy_config.root+'static/images/galaxyIcon_noText.png"><span id="brand"> Galaxy '+e.brand+'</span></a></div><div class="quota-meter-container"></div><div id="iconbar" class="iconbar"></div></div><div id="masthead-background" style="display: none; position: absolute; top: 33px; width: 100%; height: 100%; z-index: 1010"></div></div>'}});var b=Backbone.View.extend({options:{id:"galaxy-icon",icon:"fa-cog",tooltip:"galaxy-icon",with_number:false,on_click:function(){alert("clicked")},on_unload:null,visible:true},mastheadLocation:"iconbar",initialize:function(f){if(f){this.options=_.defaults(f,this.options)}this.setElement($(this._template(this.options)));var e=this;$(this.el).find(".icon").tooltip({title:this.options.tooltip}).on("mouseup",e.options.on_click);if(!this.options.visible){this.hide()}},show:function(){$(this.el).css({visibility:"visible"})},hide:function(){$(this.el).css({visibility:"hidden"})},icon:function(e){$(this.el).find(".icon").removeClass(this.options.icon).addClass(e);this.options.icon=e},toggle:function(){$(this.el).addClass("toggle")},untoggle:function(){$(this.el).removeClass("toggle")},number:function(e){$(this.el).find(".number").text(e)},_template:function(f){var e="<div id="+f.id+' class="symbol"><div class="icon fa fa-2x '+f.icon+'"></div>';if(f.with_number){e+='<div class="number"></div>'}e+="</div>";return e}});var d=Backbone.View.extend({options:{id:"",title:"Title",target:"_parent",content:"",type:"url",scratchbook:false,on_unload:null,visible:true},mastheadLocation:"navbar",$menu:null,menuVisible:false,events:{"click .head":"_eventClickHead"},initialize:function(e){if(e){this.options=_.defaults(e,this.options)}if(this.options.content&&this.options.content.indexOf("//")===-1){this.options.content=galaxy_config.root+this.options.content}this.setElement($(this._template(this.options)));if(!this.options.visible){this.hide()}},show:function(){$(this.el).css({visibility:"visible"})},hide:function(){$(this.el).css({visibility:"hidden"})},addMenu:function(g){var h={title:"Title",content:"",type:"url",target:"_parent",scratchbook:false,divider:false};if(g){h=_.defaults(g,h)}if(h.content&&h.content.indexOf("//")===-1){h.content=galaxy_config.root+h.content}if(!this.$menu){$(this.el).find(".root").append(this._templateMenu());$(this.el).find(".symbol").addClass("caret");this.$menu=$(this.el).find(".menu")}var f=$(this._templateMenuItem(h));this.$menu.append(f);var e=this;f.on("click",function(i){i.preventDefault();e._hideMenu();if(e.options.target==="_blank"){return true}Galaxy.frame.add(g)});if(h.divider){this.$menu.append($(this._templateDivider()))}},mastheadReset:function(){this._hideMenu()},_hideMenu:function(){if(this.$menu&&this.menuVisible){this.$menu.hide();this.menuVisible=false}},_eventClickHead:function(f){f.preventDefault();if(this.$menu){if(!this.menuVisible){this.$menu.show();this.menuVisible=true}else{this.$menu.hide();this.menuVisible=false}}else{Galaxy.frame.add(this.options)}},_templateMenuItem:function(e){return'<li><a href="'+e.content+'" target="'+e.target+'">'+e.title+"</a></li>"},_templateMenu:function(){return'<ul class="menu dropdown-menu"></ul>'},_templateDivider:function(){return'<li class="divider"></li>'},_template:function(f){var e='<ul class="nav navbar-nav" border="0" cellspacing="0"><li class="root dropdown" style=""><a class="head dropdown-toggle" data-toggle="dropdown" target="'+f.target+'" href="'+f.content+'">'+f.title+'<b class="symbol"></b></a></li></ul>';return e}});return{GalaxyMasthead:a,GalaxyMastheadTab:d,GalaxyMastheadIcon:b}});
\ No newline at end of file
+define(["utils/galaxy.utils","libs/backbone/backbone-relational"],function(c){var a=Backbone.View.extend({el_masthead:"#everything",options:null,list:{},itemLast:null,itemCounter:0,$background:null,backgroundVisible:false,initialize:function(f){this.options=f;$("body").off();this.setElement($(this._template(f)));$(this.el_masthead).append($(this.el));this.$background=$(this.el).find("#masthead-background");var e=this;window.onbeforeunload=function(){var h="";for(key in e.list){if(e.list[key].options.on_unload){var g=e.list[key].options.on_unload();if(g){h+=g+" "}}}if(h!=""){return h}}},events:{click:"_eventRefresh",mousedown:function(f){f.preventDefault()}},append:function(e){return this._add(e,true)},prepend:function(e){return this._add(e,false)},_add:function(g,f){var e=$(this.el).find("#"+g.mastheadLocation);if(e){var h="masthead-item-"+this.itemCounter++;var i=$(g.el);i.attr("id",h);i.addClass("masthead-item");if(f){e.append(i)}else{e.prepend(i)}this.list[h]=g;return h}return null},_eventRefresh:function(h){var i=$(h.target).closest(".masthead-item");if(i.length){i=i.attr("id")}if(this.itemLast&&this.itemLast!=i){var g=this.list[this.itemLast];if(g){if(g.mastheadReset){g.mastheadReset()}}}var f=false;if(i){var g=this.list[i];if(g){if(g.mastheadReset){if(this.itemLast==i){f=this.backgroundVisible?false:true}else{f=true}}}}if(f){this.$background.show()}else{this.$background.hide()}this.backgroundVisible=f;this.itemLast=i},_templateItem:function(e){return'<div id="'+e+'" class="masthead-item"></div>'},_template:function(e){return'<div><div id="masthead" class="navbar navbar-fixed-top navbar-inverse"><div style="position: relative; right: -50%; float: left;"><div id="navbar" style="display: block; position: relative; right: 50%;"></div></div><div class="navbar-brand"><a href="'+e.logo_url+'"><img border="0" src="'+galaxy_config.root+'static/images/galaxyIcon_noText.png"><span id="brand"> Galaxy '+e.brand+'</span></a></div><div class="quota-meter-container"></div><div id="iconbar" class="iconbar"></div></div><div id="masthead-background" style="display: none; position: absolute; top: 33px; width: 100%; height: 100%; z-index: 1010"></div></div>'}});var b=Backbone.View.extend({options:{id:"galaxy-icon",icon:"fa-cog",tooltip:"galaxy-icon",with_number:false,on_click:function(){alert("clicked")},on_unload:null,visible:true},mastheadLocation:"iconbar",initialize:function(f){if(f){this.options=_.defaults(f,this.options)}this.setElement($(this._template(this.options)));var e=this;$(this.el).find(".icon").tooltip({title:this.options.tooltip,placement:"bottom"}).on("mouseup",e.options.on_click);if(!this.options.visible){this.hide()}},show:function(){$(this.el).css({visibility:"visible"})},hide:function(){$(this.el).css({visibility:"hidden"})},icon:function(e){$(this.el).find(".icon").removeClass(this.options.icon).addClass(e);this.options.icon=e},toggle:function(){$(this.el).addClass("toggle")},untoggle:function(){$(this.el).removeClass("toggle")},number:function(e){$(this.el).find(".number").text(e)},_template:function(f){var e="<div id="+f.id+' class="symbol"><div class="icon fa fa-2x '+f.icon+'"></div>';if(f.with_number){e+='<div class="number"></div>'}e+="</div>";return e}});var d=Backbone.View.extend({options:{id:"",title:"Title",target:"_parent",content:"",type:"url",scratchbook:false,on_unload:null,visible:true},mastheadLocation:"navbar",$menu:null,menuVisible:false,events:{"click .head":"_eventClickHead"},initialize:function(e){if(e){this.options=_.defaults(e,this.options)}if(this.options.content&&this.options.content.indexOf("//")===-1){this.options.content=galaxy_config.root+this.options.content}this.setElement($(this._template(this.options)));if(!this.options.visible){this.hide()}},show:function(){$(this.el).css({visibility:"visible"})},hide:function(){$(this.el).css({visibility:"hidden"})},addMenu:function(g){var h={title:"Title",content:"",type:"url",target:"_parent",scratchbook:false,divider:false};if(g){h=_.defaults(g,h)}if(h.content&&h.content.indexOf("//")===-1){h.content=galaxy_config.root+h.content}if(!this.$menu){$(this.el).find(".root").append(this._templateMenu());$(this.el).find(".symbol").addClass("caret");this.$menu=$(this.el).find(".menu")}var f=$(this._templateMenuItem(h));this.$menu.append(f);var e=this;f.on("click",function(i){i.preventDefault();e._hideMenu();if(e.options.target==="_blank"){return true}Galaxy.frame.add(g)});if(h.divider){this.$menu.append($(this._templateDivider()))}},mastheadReset:function(){this._hideMenu()},_hideMenu:function(){if(this.$menu&&this.menuVisible){this.$menu.hide();this.menuVisible=false}},_eventClickHead:function(f){f.preventDefault();if(this.$menu){if(!this.menuVisible){this.$menu.show();this.menuVisible=true}else{this.$menu.hide();this.menuVisible=false}}else{Galaxy.frame.add(this.options)}},_templateMenuItem:function(e){return'<li><a href="'+e.content+'" target="'+e.target+'">'+e.title+"</a></li>"},_templateMenu:function(){return'<ul class="menu dropdown-menu"></ul>'},_templateDivider:function(){return'<li class="divider"></li>'},_template:function(f){var e='<ul class="nav navbar-nav" border="0" cellspacing="0"><li class="root dropdown" style=""><a class="head dropdown-toggle" data-toggle="dropdown" target="'+f.target+'" href="'+f.content+'">'+f.title+'<b class="symbol"></b></a></li></ul>';return e}});return{GalaxyMasthead:a,GalaxyMastheadTab:d,GalaxyMastheadIcon:b}});
\ No newline at end of file
diff -r e057f2263f4bf8d2f5c277ae09360e36aa96cbbb -r a61de575700cc4c2e648699591415a090b3ee4e8 static/scripts/packed/libs/jquery/jquery.form.js
--- a/static/scripts/packed/libs/jquery/jquery.form.js
+++ b/static/scripts/packed/libs/jquery/jquery.form.js
@@ -1,11 +1,11 @@
/*
* jQuery Form Plugin
- * version: 2.63 (29-JAN-2011)
- * @requires jQuery v1.3.2 or later
- *
+ * version: 3.45.0-2013.10.17
+ * Requires jQuery v1.5 or later
+ * Copyright (c) 2013 M. Alsup
* Examples and documentation at: http://malsup.com/jquery/form/
- * Dual licensed under the MIT and GPL licenses:
- * http://www.opensource.org/licenses/mit-license.php
- * http://www.gnu.org/licenses/gpl.html
+ * Project repository: https://github.com/malsup/form
+ * Dual licensed under the MIT and GPL licenses.
+ * https://github.com/malsup/form#copyright-and-license
*/
-(function(b){b.fn.ajaxSubmit=function(t){if(!this.length){a("ajaxSubmit: skipping submit process - no element selected");return this}if(typeof t=="function"){t={success:t}}var h=this.attr("action");var d=(typeof h==="string")?b.trim(h):"";if(d){d=(d.match(/^([^#]+)/)||[])[1]}d=d||window.location.href||"";t=b.extend(true,{url:d,type:this[0].getAttribute("method")||"GET",iframeSrc:/^https/i.test(window.location.href||"")?"javascript:false":"about:blank"},t);var u={};this.trigger("form-pre-serialize",[this,t,u]);if(u.veto){a("ajaxSubmit: submit vetoed via form-pre-serialize trigger");return this}if(t.beforeSerialize&&t.beforeSerialize(this,t)===false){a("ajaxSubmit: submit aborted via beforeSerialize callback");return this}var f,p,m=this.formToArray(t.semantic);if(t.data){t.extraData=t.data;for(f in t.data){if(t.data[f] instanceof Array){for(var i in t.data[f]){m.push({name:f,value:t.data[f][i]})}}else{p=t.data[f];p=b.isFunction(p)?p():p;m.push({name:f,value:p})}}}if(t.beforeSubmit&&t.beforeSubmit(m,this,t)===false){a("ajaxSubmit: submit aborted via beforeSubmit callback");return this}this.trigger("form-submit-validate",[m,this,t,u]);if(u.veto){a("ajaxSubmit: submit vetoed via form-submit-validate trigger");return this}var c=b.param(m);if(t.type.toUpperCase()=="GET"){t.url+=(t.url.indexOf("?")>=0?"&":"?")+c;t.data=null}else{t.data=c}var s=this,l=[];if(t.resetForm){l.push(function(){s.resetForm()})}if(t.clearForm){l.push(function(){s.clearForm()})}if(!t.dataType&&t.target){var r=t.success||function(){};l.push(function(n){var k=t.replaceTarget?"replaceWith":"html";b(t.target)[k](n).each(r,arguments)})}else{if(t.success){l.push(t.success)}}t.success=function(w,n,x){var v=t.context||t;for(var q=0,k=l.length;q<k;q++){l[q].apply(v,[w,n,x||s,s])}};var g=b("input:file",this).length>0;var e="multipart/form-data";var j=(s.attr("enctype")==e||s.attr("encoding")==e);if(t.iframe!==false&&(g||t.iframe||j)){if(t.closeKeepAlive){b.get(t.closeKeepAlive,o)}else{o()}}else{b.ajax(t)}this.trigger("form-submit-notify",[this,t]);return this;function o(){var v=s[0];if(b(":input[name=submit],:input[id=submit]",v).length){alert('Error: Form elements must not have name or id of "submit".');return}var B=b.extend(true,{},b.ajaxSettings,t);B.context=B.context||B;var E="jqFormIO"+(new Date().getTime()),z="_"+E;var w=b('<iframe id="'+E+'" name="'+E+'" src="'+B.iframeSrc+'" />');var A=w[0];w.css({position:"absolute",top:"-1000px",left:"-1000px"});var x={aborted:0,responseText:null,responseXML:null,status:0,statusText:"n/a",getAllResponseHeaders:function(){},getResponseHeader:function(){},setRequestHeader:function(){},abort:function(){this.aborted=1;w.attr("src",B.iframeSrc)}};var I=B.global;if(I&&!b.active++){b.event.trigger("ajaxStart")}if(I){b.event.trigger("ajaxSend",[x,B])}if(B.beforeSend&&B.beforeSend.call(B.context,x,B)===false){if(B.global){b.active--}return}if(x.aborted){return}var H=0;var y=v.clk;if(y){var F=y.name;if(F&&!y.disabled){B.extraData=B.extraData||{};B.extraData[F]=y.value;if(y.type=="image"){B.extraData[F+".x"]=v.clk_x;B.extraData[F+".y"]=v.clk_y}}}function G(){var O=s.attr("target"),M=s.attr("action");v.setAttribute("target",E);if(v.getAttribute("method")!="POST"){v.setAttribute("method","POST")}if(v.getAttribute("action")!=B.url){v.setAttribute("action",B.url)}if(!B.skipEncodingOverride){s.attr({encoding:"multipart/form-data",enctype:"multipart/form-data"})}if(B.timeout){setTimeout(function(){H=true;D()},B.timeout)}var N=[];try{if(B.extraData){for(var P in B.extraData){N.push(b('<input type="hidden" name="'+P+'" value="'+B.extraData[P]+'" />').appendTo(v)[0])}}w.appendTo("body");A.attachEvent?A.attachEvent("onload",D):A.addEventListener("load",D,false);v.submit()}finally{v.setAttribute("action",M);if(O){v.setAttribute("target",O)}else{s.removeAttr("target")}b(N).remove()}}if(B.forceSync){G()}else{setTimeout(G,10)}var K,L,J=50;function D(){L=A.contentWindow?A.contentWindow.document:A.contentDocument?A.contentDocument:A.document;if(!L||L.location.href==B.iframeSrc){return}A.detachEvent?A.detachEvent("onload",D):A.removeEventListener("load",D,false);var N=true;try{if(H){throw"timeout"}var R=B.dataType=="xml"||L.XMLDocument||b.isXMLDoc(L);a("isXml="+R);if(!R&&window.opera&&(L.body==null||L.body.innerHTML=="")){if(--J){a("requeing onLoad callback, DOM not available");setTimeout(D,250);return}}x.responseText=L.body?L.body.innerHTML:L.documentElement?L.documentElement.innerHTML:null;x.responseXML=L.XMLDocument?L.XMLDocument:L;x.getResponseHeader=function(T){var S={"content-type":B.dataType};return S[T]};var Q=/(json|script)/.test(B.dataType);if(Q||B.textarea){var M=L.getElementsByTagName("textarea")[0];if(M){x.responseText=M.value}else{if(Q){var P=L.getElementsByTagName("pre")[0];var n=L.getElementsByTagName("body")[0];if(P){x.responseText=P.textContent}else{if(n){x.responseText=n.innerHTML}}}}}else{if(B.dataType=="xml"&&!x.responseXML&&x.responseText!=null){x.responseXML=C(x.responseText)}}K=k(x,B.dataType,B)}catch(O){a("error caught:",O);N=false;x.error=O;B.error.call(B.context,x,"error",O);I&&b.event.trigger("ajaxError",[x,B,O])}if(x.aborted){a("upload aborted");N=false}if(N){B.success.call(B.context,K,"success",x);I&&b.event.trigger("ajaxSuccess",[x,B])}I&&b.event.trigger("ajaxComplete",[x,B]);if(I&&!--b.active){b.event.trigger("ajaxStop")}B.complete&&B.complete.call(B.context,x,N?"success":"error");setTimeout(function(){w.removeData("form-plugin-onload");w.remove();x.responseXML=null},100)}var C=b.parseXML||function(n,M){if(window.ActiveXObject){M=new ActiveXObject("Microsoft.XMLDOM");M.async="false";M.loadXML(n)}else{M=(new DOMParser()).parseFromString(n,"text/xml")}return(M&&M.documentElement&&M.documentElement.nodeName!="parsererror")?M:null};var q=b.parseJSON||function(n){return window["eval"]("("+n+")")};var k=function(Q,O,N){var M=Q.getResponseHeader("content-type")||"",n=O==="xml"||!O&&M.indexOf("xml")>=0,P=n?Q.responseXML:Q.responseText;if(n&&P.documentElement.nodeName==="parsererror"){b.error&&b.error("parsererror")}if(N&&N.dataFilter){P=N.dataFilter(P,O)}if(typeof P==="string"){if(O==="json"||!O&&M.indexOf("json")>=0){P=q(P)}else{if(O==="script"||!O&&M.indexOf("javascript")>=0){b.globalEval(P)}}}return P}}};b.fn.ajaxForm=function(c){if(this.length===0){var d={s:this.selector,c:this.context};if(!b.isReady&&d.s){a("DOM not ready, queuing ajaxForm");b(function(){b(d.s,d.c).ajaxForm(c)});return this}a("terminating; zero elements found by selector"+(b.isReady?"":" (DOM not ready)"));return this}return this.ajaxFormUnbind().bind("submit.form-plugin",function(f){if(!f.isDefaultPrevented()){f.preventDefault();b(this).ajaxSubmit(c)}}).bind("click.form-plugin",function(j){var i=j.target;var g=b(i);if(!(g.is(":submit,input:image"))){var f=g.closest(":submit");if(f.length==0){return}i=f[0]}var h=this;h.clk=i;if(i.type=="image"){if(j.offsetX!=undefined){h.clk_x=j.offsetX;h.clk_y=j.offsetY}else{if(typeof b.fn.offset=="function"){var k=g.offset();h.clk_x=j.pageX-k.left;h.clk_y=j.pageY-k.top}else{h.clk_x=j.pageX-i.offsetLeft;h.clk_y=j.pageY-i.offsetTop}}}setTimeout(function(){h.clk=h.clk_x=h.clk_y=null},100)})};b.fn.ajaxFormUnbind=function(){return this.unbind("submit.form-plugin click.form-plugin")};b.fn.formToArray=function(q){var p=[];if(this.length===0){return p}var d=this[0];var g=q?d.getElementsByTagName("*"):d.elements;if(!g){return p}var k,h,f,r,e,m,c;for(k=0,m=g.length;k<m;k++){e=g[k];f=e.name;if(!f){continue}if(q&&d.clk&&e.type=="image"){if(!e.disabled&&d.clk==e){p.push({name:f,value:b(e).val()});p.push({name:f+".x",value:d.clk_x},{name:f+".y",value:d.clk_y})}continue}r=b.fieldValue(e,true);if(r&&r.constructor==Array){for(h=0,c=r.length;h<c;h++){p.push({name:f,value:r[h]})}}else{if(r!==null&&typeof r!="undefined"){p.push({name:f,value:r})}}}if(!q&&d.clk){var l=b(d.clk),o=l[0];f=o.name;if(f&&!o.disabled&&o.type=="image"){p.push({name:f,value:l.val()});p.push({name:f+".x",value:d.clk_x},{name:f+".y",value:d.clk_y})}}return p};b.fn.formSerialize=function(c){return b.param(this.formToArray(c))};b.fn.fieldSerialize=function(d){var c=[];this.each(function(){var h=this.name;if(!h){return}var f=b.fieldValue(this,d);if(f&&f.constructor==Array){for(var g=0,e=f.length;g<e;g++){c.push({name:h,value:f[g]})}}else{if(f!==null&&typeof f!="undefined"){c.push({name:this.name,value:f})}}});return b.param(c)};b.fn.fieldValue=function(h){for(var g=[],e=0,c=this.length;e<c;e++){var f=this[e];var d=b.fieldValue(f,h);if(d===null||typeof d=="undefined"||(d.constructor==Array&&!d.length)){continue}d.constructor==Array?b.merge(g,d):g.push(d)}return g};b.fieldValue=function(c,j){var e=c.name,p=c.type,q=c.tagName.toLowerCase();if(j===undefined){j=true}if(j&&(!e||c.disabled||p=="reset"||p=="button"||(p=="checkbox"||p=="radio")&&!c.checked||(p=="submit"||p=="image")&&c.form&&c.form.clk!=c||q=="select"&&c.selectedIndex==-1)){return null}if(q=="select"){var k=c.selectedIndex;if(k<0){return null}var m=[],d=c.options;var g=(p=="select-one");var l=(g?k+1:d.length);for(var f=(g?k:0);f<l;f++){var h=d[f];if(h.selected){var o=h.value;if(!o){o=(h.attributes&&h.attributes.value&&!(h.attributes.value.specified))?h.text:h.value}if(g){return o}m.push(o)}}return m}return b(c).val()};b.fn.clearForm=function(){return this.each(function(){b("input,select,textarea",this).clearFields()})};b.fn.clearFields=b.fn.clearInputs=function(){return this.each(function(){var d=this.type,c=this.tagName.toLowerCase();if(d=="text"||d=="password"||c=="textarea"){this.value=""}else{if(d=="checkbox"||d=="radio"){this.checked=false}else{if(c=="select"){this.selectedIndex=-1}}}})};b.fn.resetForm=function(){return this.each(function(){if(typeof this.reset=="function"||(typeof this.reset=="object"&&!this.reset.nodeType)){this.reset()}})};b.fn.enable=function(c){if(c===undefined){c=true}return this.each(function(){this.disabled=!c})};b.fn.selected=function(c){if(c===undefined){c=true}return this.each(function(){var d=this.type;if(d=="checkbox"||d=="radio"){this.checked=c}else{if(this.tagName.toLowerCase()=="option"){var e=b(this).parent("select");if(c&&e[0]&&e[0].type=="select-one"){e.find("option").selected(false)}this.selected=c}}})};function a(){if(b.fn.ajaxSubmit.debug){var c="[jquery.form] "+Array.prototype.join.call(arguments,"");if(window.console&&window.console.log){window.console.log(c)}else{if(window.opera&&window.opera.postError){window.opera.postError(c)}}}}})(jQuery);
\ No newline at end of file
+(function(f){var c={};c.fileapi=f("<input type='file'/>").get(0).files!==undefined;c.formdata=window.FormData!==undefined;var e=!!f.fn.prop;f.fn.attr2=function(){if(!e){return this.attr.apply(this,arguments)}var g=this.prop.apply(this,arguments);if((g&&g.jquery)||typeof g==="string"){return g}return this.attr.apply(this,arguments)};f.fn.ajaxSubmit=function(j){if(!this.length){d("ajaxSubmit: skipping submit process - no element selected");return this}var i,C,m,o=this;if(typeof j=="function"){j={success:j}}else{if(j===undefined){j={}}}i=j.type||this.attr2("method");C=j.url||this.attr2("action");m=(typeof C==="string")?f.trim(C):"";m=m||window.location.href||"";if(m){m=(m.match(/^([^#]+)/)||[])[1]}j=f.extend(true,{url:m,success:f.ajaxSettings.success,type:i||f.ajaxSettings.type,iframeSrc:/^https/i.test(window.location.href||"")?"javascript:false":"about:blank"},j);var u={};this.trigger("form-pre-serialize",[this,j,u]);if(u.veto){d("ajaxSubmit: submit vetoed via form-pre-serialize trigger");return this}if(j.beforeSerialize&&j.beforeSerialize(this,j)===false){d("ajaxSubmit: submit aborted via beforeSerialize callback");return this}var n=j.traditional;if(n===undefined){n=f.ajaxSettings.traditional}var s=[];var E,F=this.formToArray(j.semantic,s);if(j.data){j.extraData=j.data;E=f.param(j.data,n)}if(j.beforeSubmit&&j.beforeSubmit(F,this,j)===false){d("ajaxSubmit: submit aborted via beforeSubmit callback");return this}this.trigger("form-submit-validate",[F,this,j,u]);if(u.veto){d("ajaxSubmit: submit vetoed via form-submit-validate trigger");return this}var y=f.param(F,n);if(E){y=(y?(y+"&"+E):E)}if(j.type.toUpperCase()=="GET"){j.url+=(j.url.indexOf("?")>=0?"&":"?")+y;j.data=null}else{j.data=y}var H=[];if(j.resetForm){H.push(function(){o.resetForm()})}if(j.clearForm){H.push(function(){o.clearForm(j.includeHidden)})}if(!j.dataType&&j.target){var l=j.success||function(){};H.push(function(q){var k=j.replaceTarget?"replaceWith":"html";f(j.target)[k](q).each(l,arguments)})}else{if(j.success){H.push(j.success)}}j.success=function(K,q,L){var J=j.context||this;for(var I=0,k=H.length;I<k;I++){H[I].apply(J,[K,q,L||o,o])}};if(j.error){var z=j.error;j.error=function(J,k,q){var I=j.context||this;z.apply(I,[J,k,q,o])}}if(j.complete){var h=j.complete;j.complete=function(I,k){var q=j.context||this;h.apply(q,[I,k,o])}}var D=f("input[type=file]:enabled",this).filter(function(){return f(this).val()!==""});var p=D.length>0;var B="multipart/form-data";var x=(o.attr("enctype")==B||o.attr("encoding")==B);var w=c.fileapi&&c.formdata;d("fileAPI :"+w);var r=(p||x)&&!w;var v;if(j.iframe!==false&&(j.iframe||r)){if(j.closeKeepAlive){f.get(j.closeKeepAlive,function(){v=G(F)})}else{v=G(F)}}else{if((p||x)&&w){v=t(F)}else{v=f.ajax(j)}}o.removeData("jqxhr").data("jqxhr",v);for(var A=0;A<s.length;A++){s[A]=null}this.trigger("form-submit-notify",[this,j]);return this;function g(K){var L=f.param(K,j.traditional).split("&");var q=L.length;var k=[];var J,I;for(J=0;J<q;J++){L[J]=L[J].replace(/\+/g," ");I=L[J].split("=");k.push([decodeURIComponent(I[0]),decodeURIComponent(I[1])])}return k}function t(q){var k=new FormData();for(var I=0;I<q.length;I++){k.append(q[I].name,q[I].value)}if(j.extraData){var L=g(j.extraData);for(I=0;I<L.length;I++){if(L[I]){k.append(L[I][0],L[I][1])}}}j.data=null;var K=f.extend(true,{},f.ajaxSettings,j,{contentType:false,processData:false,cache:false,type:i||"POST"});if(j.uploadProgress){K.xhr=function(){var M=f.ajaxSettings.xhr();if(M.upload){M.upload.addEventListener("progress",function(Q){var P=0;var N=Q.loaded||Q.position;var O=Q.total;if(Q.lengthComputable){P=Math.ceil(N/O*100)}j.uploadProgress(Q,N,O,P)},false)}return M}}K.data=null;var J=K.beforeSend;K.beforeSend=function(N,M){if(j.formData){M.data=j.formData}else{M.data=k}if(J){J.call(this,N,M)}};return f.ajax(K)}function G(af){var L=o[0],K,ab,V,ad,Y,N,Q,O,P,Z,ac,T;var ai=f.Deferred();ai.abort=function(aj){O.abort(aj)};if(af){for(ab=0;ab<s.length;ab++){K=f(s[ab]);if(e){K.prop("disabled",false)}else{K.removeAttr("disabled")}}}V=f.extend(true,{},f.ajaxSettings,j);V.context=V.context||V;Y="jqFormIO"+(new Date().getTime());if(V.iframeTarget){N=f(V.iframeTarget);Z=N.attr2("name");if(!Z){N.attr2("name",Y)}else{Y=Z}}else{N=f('<iframe name="'+Y+'" src="'+V.iframeSrc+'" />');N.css({position:"absolute",top:"-1000px",left:"-1000px"})}Q=N[0];O={aborted:0,responseText:null,responseXML:null,status:0,statusText:"n/a",getAllResponseHeaders:function(){},getResponseHeader:function(){},setRequestHeader:function(){},abort:function(aj){var ak=(aj==="timeout"?"timeout":"aborted");d("aborting upload... "+ak);this.aborted=1;try{if(Q.contentWindow.document.execCommand){Q.contentWindow.document.execCommand("Stop")}}catch(al){}N.attr("src",V.iframeSrc);O.error=ak;if(V.error){V.error.call(V.context,O,ak,aj)}if(ad){f.event.trigger("ajaxError",[O,V,ak])}if(V.complete){V.complete.call(V.context,O,ak)}}};ad=V.global;if(ad&&0===f.active++){f.event.trigger("ajaxStart")}if(ad){f.event.trigger("ajaxSend",[O,V])}if(V.beforeSend&&V.beforeSend.call(V.context,O,V)===false){if(V.global){f.active--}ai.reject();return ai}if(O.aborted){ai.reject();return ai}P=L.clk;if(P){Z=P.name;if(Z&&!P.disabled){V.extraData=V.extraData||{};V.extraData[Z]=P.value;if(P.type=="image"){V.extraData[Z+".x"]=L.clk_x;V.extraData[Z+".y"]=L.clk_y}}}var U=1;var R=2;function S(al){var ak=null;try{if(al.contentWindow){ak=al.contentWindow.document}}catch(aj){d("cannot get iframe.contentWindow document: "+aj)}if(ak){return ak}try{ak=al.contentDocument?al.contentDocument:al.document}catch(aj){d("cannot get iframe.contentDocument: "+aj);ak=al.document}return ak}var J=f("meta[name=csrf-token]").attr("content");var I=f("meta[name=csrf-param]").attr("content");if(I&&J){V.extraData=V.extraData||{};V.extraData[I]=J}function aa(){var al=o.attr2("target"),aj=o.attr2("action");L.setAttribute("target",Y);if(!i||/post/i.test(i)){L.setAttribute("method","POST")}if(aj!=V.url){L.setAttribute("action",V.url)}if(!V.skipEncodingOverride&&(!i||/post/i.test(i))){o.attr({encoding:"multipart/form-data",enctype:"multipart/form-data"})}if(V.timeout){T=setTimeout(function(){ac=true;X(U)},V.timeout)}function am(){try{var aq=S(Q).readyState;d("state = "+aq);if(aq&&aq.toLowerCase()=="uninitialized"){setTimeout(am,50)}}catch(ar){d("Server abort: ",ar," (",ar.name,")");X(R);if(T){clearTimeout(T)}T=undefined}}var ak=[];try{if(V.extraData){for(var ap in V.extraData){if(V.extraData.hasOwnProperty(ap)){if(f.isPlainObject(V.extraData[ap])&&V.extraData[ap].hasOwnProperty("name")&&V.extraData[ap].hasOwnProperty("value")){ak.push(f('<input type="hidden" name="'+V.extraData[ap].name+'">').val(V.extraData[ap].value).appendTo(L)[0])}else{ak.push(f('<input type="hidden" name="'+ap+'">').val(V.extraData[ap]).appendTo(L)[0])}}}}if(!V.iframeTarget){N.appendTo("body")}if(Q.attachEvent){Q.attachEvent("onload",X)}else{Q.addEventListener("load",X,false)}setTimeout(am,15);try{L.submit()}catch(an){var ao=document.createElement("form").submit;ao.apply(L)}}finally{L.setAttribute("action",aj);if(al){L.setAttribute("target",al)}else{o.removeAttr("target")}f(ak).remove()}}if(V.forceSync){aa()}else{setTimeout(aa,10)}var ag,ah,ae=50,M;function X(ap){if(O.aborted||M){return}ah=S(Q);if(!ah){d("cannot access response document");ap=R}if(ap===U&&O){O.abort("timeout");ai.reject(O,"timeout");return}else{if(ap==R&&O){O.abort("server abort");ai.reject(O,"error","server abort");return}}if(!ah||ah.location.href==V.iframeSrc){if(!ac){return}}if(Q.detachEvent){Q.detachEvent("onload",X)}else{Q.removeEventListener("load",X,false)}var an="success",ar;try{if(ac){throw"timeout"}var am=V.dataType=="xml"||ah.XMLDocument||f.isXMLDoc(ah);d("isXml="+am);if(!am&&window.opera&&(ah.body===null||!ah.body.innerHTML)){if(--ae){d("requeing onLoad callback, DOM not available");setTimeout(X,250);return}}var at=ah.body?ah.body:ah.documentElement;O.responseText=at?at.innerHTML:null;O.responseXML=ah.XMLDocument?ah.XMLDocument:ah;if(am){V.dataType="xml"}O.getResponseHeader=function(aw){var av={"content-type":V.dataType};return av[aw.toLowerCase()]};if(at){O.status=Number(at.getAttribute("status"))||O.status;O.statusText=at.getAttribute("statusText")||O.statusText}var aj=(V.dataType||"").toLowerCase();var aq=/(json|script|text)/.test(aj);if(aq||V.textarea){var ao=ah.getElementsByTagName("textarea")[0];if(ao){O.responseText=ao.value;O.status=Number(ao.getAttribute("status"))||O.status;O.statusText=ao.getAttribute("statusText")||O.statusText}else{if(aq){var ak=ah.getElementsByTagName("pre")[0];var au=ah.getElementsByTagName("body")[0];if(ak){O.responseText=ak.textContent?ak.textContent:ak.innerText}else{if(au){O.responseText=au.textContent?au.textContent:au.innerText}}}}}else{if(aj=="xml"&&!O.responseXML&&O.responseText){O.responseXML=W(O.responseText)}}try{ag=k(O,aj,V)}catch(al){an="parsererror";O.error=ar=(al||an)}}catch(al){d("error caught: ",al);an="error";O.error=ar=(al||an)}if(O.aborted){d("upload aborted");an=null}if(O.status){an=(O.status>=200&&O.status<300||O.status===304)?"success":"error"}if(an==="success"){if(V.success){V.success.call(V.context,ag,"success",O)}ai.resolve(O.responseText,"success",O);if(ad){f.event.trigger("ajaxSuccess",[O,V])}}else{if(an){if(ar===undefined){ar=O.statusText}if(V.error){V.error.call(V.context,O,an,ar)}ai.reject(O,"error",ar);if(ad){f.event.trigger("ajaxError",[O,V,ar])}}}if(ad){f.event.trigger("ajaxComplete",[O,V])}if(ad&&!--f.active){f.event.trigger("ajaxStop")}if(V.complete){V.complete.call(V.context,O,an)}M=true;if(V.timeout){clearTimeout(T)}setTimeout(function(){if(!V.iframeTarget){N.remove()}else{N.attr("src",V.iframeSrc)}O.responseXML=null},100)}var W=f.parseXML||function(aj,ak){if(window.ActiveXObject){ak=new ActiveXObject("Microsoft.XMLDOM");ak.async="false";ak.loadXML(aj)}else{ak=(new DOMParser()).parseFromString(aj,"text/xml")}return(ak&&ak.documentElement&&ak.documentElement.nodeName!="parsererror")?ak:null};var q=f.parseJSON||function(aj){return window["eval"]("("+aj+")")};var k=function(ao,am,al){var ak=ao.getResponseHeader("content-type")||"",aj=am==="xml"||!am&&ak.indexOf("xml")>=0,an=aj?ao.responseXML:ao.responseText;if(aj&&an.documentElement.nodeName==="parsererror"){if(f.error){f.error("parsererror")}}if(al&&al.dataFilter){an=al.dataFilter(an,am)}if(typeof an==="string"){if(am==="json"||!am&&ak.indexOf("json")>=0){an=q(an)}else{if(am==="script"||!am&&ak.indexOf("javascript")>=0){f.globalEval(an)}}}return an};return ai}};f.fn.ajaxForm=function(g){g=g||{};g.delegation=g.delegation&&f.isFunction(f.fn.on);if(!g.delegation&&this.length===0){var h={s:this.selector,c:this.context};if(!f.isReady&&h.s){d("DOM not ready, queuing ajaxForm");f(function(){f(h.s,h.c).ajaxForm(g)});return this}d("terminating; zero elements found by selector"+(f.isReady?"":" (DOM not ready)"));return this}if(g.delegation){f(document).off("submit.form-plugin",this.selector,b).off("click.form-plugin",this.selector,a).on("submit.form-plugin",this.selector,g,b).on("click.form-plugin",this.selector,g,a);return this}return this.ajaxFormUnbind().bind("submit.form-plugin",g,b).bind("click.form-plugin",g,a)};function b(h){var g=h.data;if(!h.isDefaultPrevented()){h.preventDefault();f(h.target).ajaxSubmit(g)}}function a(k){var j=k.target;var h=f(j);if(!(h.is("[type=submit],[type=image]"))){var g=h.closest("[type=submit]");if(g.length===0){return}j=g[0]}var i=this;i.clk=j;if(j.type=="image"){if(k.offsetX!==undefined){i.clk_x=k.offsetX;i.clk_y=k.offsetY}else{if(typeof f.fn.offset=="function"){var l=h.offset();i.clk_x=k.pageX-l.left;i.clk_y=k.pageY-l.top}else{i.clk_x=k.pageX-j.offsetLeft;i.clk_y=k.pageY-j.offsetTop}}}setTimeout(function(){i.clk=i.clk_x=i.clk_y=null},100)}f.fn.ajaxFormUnbind=function(){return this.unbind("submit.form-plugin click.form-plugin")};f.fn.formToArray=function(x,g){var w=[];if(this.length===0){return w}var l=this[0];var p=x?l.getElementsByTagName("*"):l.elements;if(!p){return w}var r,q,o,y,m,t,k;for(r=0,t=p.length;r<t;r++){m=p[r];o=m.name;if(!o||m.disabled){continue}if(x&&l.clk&&m.type=="image"){if(l.clk==m){w.push({name:o,value:f(m).val(),type:m.type});w.push({name:o+".x",value:l.clk_x},{name:o+".y",value:l.clk_y})}continue}y=f.fieldValue(m,true);if(y&&y.constructor==Array){if(g){g.push(m)}for(q=0,k=y.length;q<k;q++){w.push({name:o,value:y[q]})}}else{if(c.fileapi&&m.type=="file"){if(g){g.push(m)}var h=m.files;if(h.length){for(q=0;q<h.length;q++){w.push({name:o,value:h[q],type:m.type})}}else{w.push({name:o,value:"",type:m.type})}}else{if(y!==null&&typeof y!="undefined"){if(g){g.push(m)}w.push({name:o,value:y,type:m.type,required:m.required})}}}}if(!x&&l.clk){var s=f(l.clk),u=s[0];o=u.name;if(o&&!u.disabled&&u.type=="image"){w.push({name:o,value:s.val()});w.push({name:o+".x",value:l.clk_x},{name:o+".y",value:l.clk_y})}}return w};f.fn.formSerialize=function(g){return f.param(this.formToArray(g))};f.fn.fieldSerialize=function(h){var g=[];this.each(function(){var m=this.name;if(!m){return}var k=f.fieldValue(this,h);if(k&&k.constructor==Array){for(var l=0,j=k.length;l<j;l++){g.push({name:m,value:k[l]})}}else{if(k!==null&&typeof k!="undefined"){g.push({name:this.name,value:k})}}});return f.param(g)};f.fn.fieldValue=function(m){for(var l=[],j=0,g=this.length;j<g;j++){var k=this[j];var h=f.fieldValue(k,m);if(h===null||typeof h=="undefined"||(h.constructor==Array&&!h.length)){continue}if(h.constructor==Array){f.merge(l,h)}else{l.push(h)}}return l};f.fieldValue=function(g,o){var j=g.name,u=g.type,w=g.tagName.toLowerCase();if(o===undefined){o=true}if(o&&(!j||g.disabled||u=="reset"||u=="button"||(u=="checkbox"||u=="radio")&&!g.checked||(u=="submit"||u=="image")&&g.form&&g.form.clk!=g||w=="select"&&g.selectedIndex==-1)){return null}if(w=="select"){var p=g.selectedIndex;if(p<0){return null}var r=[],h=g.options;var l=(u=="select-one");var q=(l?p+1:h.length);for(var k=(l?p:0);k<q;k++){var m=h[k];if(m.selected){var s=m.value;if(!s){s=(m.attributes&&m.attributes.value&&!(m.attributes.value.specified))?m.text:m.value}if(l){return s}r.push(s)}}return r}return f(g).val()};f.fn.clearForm=function(g){return this.each(function(){f("input,select,textarea",this).clearFields(g)})};f.fn.clearFields=f.fn.clearInputs=function(g){var h=/^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i;return this.each(function(){var j=this.type,i=this.tagName.toLowerCase();if(h.test(j)||i=="textarea"){this.value=""}else{if(j=="checkbox"||j=="radio"){this.checked=false}else{if(i=="select"){this.selectedIndex=-1}else{if(j=="file"){if(/MSIE/.test(navigator.userAgent)){f(this).replaceWith(f(this).clone(true))}else{f(this).val("")}}else{if(g){if((g===true&&/hidden/.test(j))||(typeof g=="string"&&f(this).is(g))){this.value=""}}}}}}})};f.fn.resetForm=function(){return this.each(function(){if(typeof this.reset=="function"||(typeof this.reset=="object"&&!this.reset.nodeType)){this.reset()}})};f.fn.enable=function(g){if(g===undefined){g=true}return this.each(function(){this.disabled=!g})};f.fn.selected=function(g){if(g===undefined){g=true}return this.each(function(){var h=this.type;if(h=="checkbox"||h=="radio"){this.checked=g}else{if(this.tagName.toLowerCase()=="option"){var i=f(this).parent("select");if(g&&i[0]&&i[0].type=="select-one"){i.find("option").selected(false)}this.selected=g}}})};f.fn.ajaxSubmit.debug=false;function d(){if(!f.fn.ajaxSubmit.debug){return}var g="[jquery.form] "+Array.prototype.join.call(arguments,"");if(window.console&&window.console.log){window.console.log(g)}else{if(window.opera&&window.opera.postError){window.opera.postError(g)}}}})((typeof(jQuery)!="undefined")?jQuery:window.Zepto);
\ No newline at end of file
diff -r e057f2263f4bf8d2f5c277ae09360e36aa96cbbb -r a61de575700cc4c2e648699591415a090b3ee4e8 static/scripts/packed/viz/trackster/tracks.js
--- a/static/scripts/packed/viz/trackster/tracks.js
+++ b/static/scripts/packed/viz/trackster/tracks.js
@@ -1,1 +1,1 @@
-define(["libs/underscore","viz/visualization","viz/trackster/util","viz/trackster/slotting","viz/trackster/painters","viz/trackster/filters","mvc/data","mvc/tools"],function(ab,y,l,u,L,i,X,R){var q=ab.extend;var n={};var k=function(ac,ad){n[ac.attr("id")]=ad};var m=function(ac,ae,ag,af){ag=".group";var ad={};n[ac.attr("id")]=af;ac.bind("drag",{handle:"."+ae,relative:true},function(ao,ap){var an=$(this),at=$(this).parent(),ak=at.children(".track,.group"),am=n[$(this).attr("id")],aj,ai,aq,ah,al;ai=$(this).parents(ag);if(ai.length!==0){aq=ai.position().top;ah=aq+ai.outerHeight();var ar=n[ai.attr("id")];if(ap.offsetY<aq){$(this).insertBefore(ai);ar.remove_drawable(am);ar.container.add_drawable_before(am,ar);return}else{if(ap.offsetY>ah){$(this).insertAfter(ai);ar.remove_drawable(am);ar.container.add_drawable(am);return}}}ai=null;for(al=0;al<ak.length;al++){aj=$(ak.get(al));aq=aj.position().top;ah=aq+aj.outerHeight();if(aj.is(ag)&&this!==aj.get(0)&&ap.offsetY>=aq&&ap.offsetY<=ah){if(ap.offsetY-aq<ah-ap.offsetY){aj.find(".content-div").prepend(this)}else{aj.find(".content-div").append(this)}if(am.container){am.container.remove_drawable(am)}n[aj.attr("id")].add_drawable(am);return}}for(al=0;al<ak.length;al++){aj=$(ak.get(al));if(ap.offsetY<aj.position().top&&!(aj.hasClass("reference-track")||aj.hasClass("intro"))){break}}if(al===ak.length){if(this!==ak.get(al-1)){at.append(this);n[at.attr("id")].move_drawable(am,al)}}else{if(this!==ak.get(al)){$(this).insertBefore(ak.get(al));n[at.attr("id")].move_drawable(am,(ap.deltaY>0?al-1:al))}}}).bind("dragstart",function(){ad["border-top"]=ac.css("border-top");ad["border-bottom"]=ac.css("border-bottom");$(this).css({"border-top":"1px solid blue","border-bottom":"1px solid blue"})}).bind("dragend",function(){$(this).css(ad)})};var F=20,B=100,I=12000,S=400,K=5000,x=100,o="Cannot display dataset due to an error. ",J="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",G="No data for this chrom/contig.",w="Preparing data. This can take a while for a large dataset. If the visualization is saved and closed, preparation will continue in the background.",z="Tool cannot be rerun: ",b="Loading data...",U="Ready for display",Q=10,H=20,C=["Histogram","Line","Filled","Intensity"];function V(ad,ac){if(!ac){ac=0}var ae=Math.pow(10,ac);return Math.round(ad*ae)/ae}var r=function(ad,ac,af){if(!r.id_counter){r.id_counter=0}this.id=r.id_counter++;this.view=ad;this.container=ac;this.drag_handle_class=af.drag_handle_class;this.is_overview=false;this.action_icons={};this.config=new j({params:this.config_params,onchange:this.config_onchange,saved_values:af.prefs});this.prefs=this.config.get("values");if(!this.prefs.name){this.prefs.name=af.name}if(this.config_onchange){this.config.on("change:values",this.config_onchange,this)}this.container_div=this.build_container_div();this.header_div=this.build_header_div();if(this.header_div){this.container_div.append(this.header_div);this.icons_div=$("<div/>").css("float","left").hide().appendTo(this.header_div);this.build_action_icons(this.action_icons_def);this.header_div.append($("<div style='clear: both'/>"));this.header_div.dblclick(function(ag){ag.stopPropagation()});var ae=this;this.container_div.hover(function(){ae.icons_div.show()},function(){ae.icons_div.hide()});$("<div style='clear: both'/>").appendTo(this.container_div)}};r.prototype.action_icons_def=[{name:"toggle_icon",title:"Hide/show content",css_class:"toggle",on_click_fn:function(ac){if(ac.prefs.content_visible){ac.action_icons.toggle_icon.addClass("toggle-expand").removeClass("toggle");ac.hide_contents();ac.prefs.content_visible=false}else{ac.action_icons.toggle_icon.addClass("toggle").removeClass("toggle-expand");ac.prefs.content_visible=true;ac.show_contents()}}},{name:"settings_icon",title:"Edit settings",css_class:"settings-icon",on_click_fn:function(ad){var ac=new a({model:ad.config});ac.render()}},{name:"remove_icon",title:"Remove",css_class:"remove-icon",on_click_fn:function(ac){$(".tooltip").remove();ac.remove()}}];q(r.prototype,{config_params:[{key:"name",label:"Name",type:"text",default_value:""},{key:"content_visible",type:"bool",default_value:true,hidden:true}],config_onchange:function(){this.track.set_name(this.track.config.get("values").name)},init:function(){},changed:function(){this.view.changed()},can_draw:function(){if(this.enabled&&this.prefs.content_visible){return true}return false},request_draw:function(){},_draw:function(ac){},to_dict:function(){},set_name:function(ac){this.old_name=this.prefs.name;this.prefs.name=ac;this.name_div.text(this.prefs.name)},revert_name:function(){if(this.old_name){this.prefs.name=this.old_name;this.name_div.text(this.prefs.name)}},remove:function(){this.changed();this.container.remove_drawable(this);var ac=this.view;this.container_div.hide(0,function(){$(this).remove();ac.update_intro_div()})},build_container_div:function(){},build_header_div:function(){},add_action_icon:function(ad,ai,ah,ag,ac,af){var ae=this;this.action_icons[ad]=$("<a/>").attr("title",ai).addClass("icon-button").addClass(ah).tooltip().click(function(){ag(ae)}).appendTo(this.icons_div);if(af){this.action_icons[ad].hide()}},build_action_icons:function(ac){var ae;for(var ad=0;ad<ac.length;ad++){ae=ac[ad];this.add_action_icon(ae.name,ae.title,ae.css_class,ae.on_click_fn,ae.prepend,ae.hide)}},update_icons:function(){},hide_contents:function(){},show_contents:function(){},get_drawables:function(){}});var A=function(ad,ac,ae){r.call(this,ad,ac,ae);this.obj_type=ae.obj_type;this.drawables=[]};q(A.prototype,r.prototype,{unpack_drawables:function(ae){this.drawables=[];var ad;for(var ac=0;ac<ae.length;ac++){ad=p(ae[ac],this.view,this);this.add_drawable(ad)}},init:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac].init()}},_draw:function(ac){for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad]._draw(ac)}},to_dict:function(){var ad=[];for(var ac=0;ac<this.drawables.length;ac++){ad.push(this.drawables[ac].to_dict())}return{prefs:this.prefs,obj_type:this.obj_type,drawables:ad}},add_drawable:function(ac){this.drawables.push(ac);ac.container=this;this.changed()},add_drawable_before:function(ae,ac){this.changed();var ad=this.drawables.indexOf(ac);if(ad!==-1){this.drawables.splice(ad,0,ae);return true}return false},replace_drawable:function(ae,ac,ad){var af=this.drawables.indexOf(ae);if(af!==-1){this.drawables[af]=ac;if(ad){ae.container_div.replaceWith(ac.container_div)}this.changed()}return af},remove_drawable:function(ad){var ac=this.drawables.indexOf(ad);if(ac!==-1){this.drawables.splice(ac,1);ad.container=null;this.changed();return true}return false},move_drawable:function(ad,ae){var ac=this.drawables.indexOf(ad);if(ac!==-1){this.drawables.splice(ac,1);this.drawables.splice(ae,0,ad);this.changed();return true}return false},get_drawables:function(){return this.drawables},get_tracks:function(af){var ac=this.drawables.slice(0),ad=[],ae;while(ac.length!==0){ae=ac.shift();if(ae instanceof af){ad.push(ae)}else{if(ae.drawables){ac=ac.concat(ae.drawables)}}}return ad}});var P=function(ad,ac,af){q(af,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});A.call(this,ad,ac,af);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);k(this.container_div,this);k(this.content_div,this);m(this.container_div,this.drag_handle_class,".group",this);this.filters_manager=new i.FiltersManager(this);this.header_div.after(this.filters_manager.parent_div);this.saved_filters_managers=[];if("drawables" in af){this.unpack_drawables(af.drawables)}if("filters" in af){var ae=this.filters_manager;this.filters_manager=new i.FiltersManager(this,af.filters);ae.parent_div.replaceWith(this.filters_manager.parent_div);if(af.filters.visible){this.setup_multitrack_filtering()}}};q(P.prototype,r.prototype,A.prototype,{action_icons_def:[r.prototype.action_icons_def[0],r.prototype.action_icons_def[1],{name:"composite_icon",title:"Show composite track",css_class:"layers-stack",on_click_fn:function(ac){$(".tooltip").remove();ac.show_composite_track()}},{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ac){if(ac.filters_manager.visible()){ac.filters_manager.clear_filters();ac._restore_filter_managers()}else{ac.setup_multitrack_filtering();ac.request_draw({clear_tile_cache:true})}ac.filters_manager.toggle()}},r.prototype.action_icons_def[2]],build_container_div:function(){var ac=$("<div/>").addClass("group").attr("id","group_"+this.id);if(this.container){this.container.content_div.append(ac)}return ac},build_header_div:function(){var ac=$("<div/>").addClass("track-header");ac.append($("<div/>").addClass(this.drag_handle_class));this.name_div=$("<div/>").addClass("track-name").text(this.prefs.name).appendTo(ac);return ac},hide_contents:function(){this.tiles_div.hide()},show_contents:function(){this.tiles_div.show();this.request_draw()},update_icons:function(){var ae=this.drawables.length;if(ae===0){this.action_icons.composite_icon.hide();this.action_icons.filters_icon.hide()}else{if(ae===1){if(this.drawables[0] instanceof f){this.action_icons.composite_icon.show()}this.action_icons.filters_icon.hide()}else{var al,ak,ai,ao=true,ag=this.drawables[0].get_type(),ac=0;for(al=0;al<ae;al++){ai=this.drawables[al];if(ai.get_type()!==ag){can_composite=false;break}if(ai instanceof d){ac++}}if(ao||ac===1){this.action_icons.composite_icon.show()}else{this.action_icons.composite_icon.hide();$(".tooltip").remove()}if(ac>1&&ac===this.drawables.length){var ap={},ad;ai=this.drawables[0];for(ak=0;ak<ai.filters_manager.filters.length;ak++){ad=ai.filters_manager.filters[ak];ap[ad.name]=[ad]}for(al=1;al<this.drawables.length;al++){ai=this.drawables[al];for(ak=0;ak<ai.filters_manager.filters.length;ak++){ad=ai.filters_manager.filters[ak];if(ad.name in ap){ap[ad.name].push(ad)}}}this.filters_manager.remove_all();var af,ah,aj,am;for(var an in ap){af=ap[an];if(af.length===ac){ah=new i.NumberFilter({name:af[0].name,index:af[0].index});this.filters_manager.add_filter(ah)}}if(this.filters_manager.filters.length>0){this.action_icons.filters_icon.show()}else{this.action_icons.filters_icon.hide()}}else{this.action_icons.filters_icon.hide()}}}},_restore_filter_managers:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac].filters_manager=this.saved_filters_managers[ac]}this.saved_filters_managers=[]},setup_multitrack_filtering:function(){if(this.filters_manager.filters.length>0){this.saved_filters_managers=[];for(var ac=0;ac<this.drawables.length;ac++){drawable=this.drawables[ac];this.saved_filters_managers.push(drawable.filters_manager);drawable.filters_manager=this.filters_manager}}this.filters_manager.init_filters()},show_composite_track:function(){var ad=new f(this.view,this.view,{name:this.prefs.name,drawables:this.drawables});var ac=this.container.replace_drawable(this,ad,true);ad.request_draw()},add_drawable:function(ac){A.prototype.add_drawable.call(this,ac);this.update_icons()},remove_drawable:function(ac){A.prototype.remove_drawable.call(this,ac);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var ac=q(A.prototype.to_dict.call(this),{filters:this.filters_manager.to_dict()});if(this.filters_manager.visible()){this.setup_multitrack_filtering()}return ac},request_draw:function(ac){ab.each(this.drawables,function(ad){ad.request_draw(ac)})}});var Y=Backbone.View.extend({initialize:function(ac){q(ac,{obj_type:"View"});A.call(this,"View",ac.container,ac);this.chrom=null;this.vis_id=ac.vis_id;this.dbkey=ac.dbkey;this.label_tracks=[];this.tracks_to_be_redrawn=[];this.max_low=0;this.max_high=0;this.zoom_factor=3;this.min_separation=30;this.has_changes=false;this.load_chroms_deferred=null;this.render();this.canvas_manager=new y.CanvasManager(this.container.get(0).ownerDocument);this.reset();this.config=new j({track:this,params:[{key:"a_color",label:"A Color",type:"color",default_value:"#FF0000"},{key:"c_color",label:"C Color",type:"color",default_value:"#00FF00"},{key:"g_color",label:"G Color",type:"color",default_value:"#0000FF"},{key:"t_color",label:"T Color",type:"color",default_value:"#FF00FF"},{key:"n_color",label:"N Color",type:"color",default_value:"#AAAAAA"}],saved_values:ac.prefs,onchange:function(){track.request_redraw({clear_tile_cache:true})}})},render:function(){this.requested_redraw=false;var ae=this.container,ac=this;this.top_container=$("<div/>").addClass("top-container").appendTo(ae);this.browser_content_div=$("<div/>").addClass("content").css("position","relative").appendTo(ae);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(ae);this.top_labeltrack=$("<div/>").addClass("top-labeltrack").appendTo(this.top_container);this.viewport_container=$("<div/>").addClass("viewport-container").attr("id","viewport-container").appendTo(this.browser_content_div);this.content_div=this.viewport_container;k(this.viewport_container,ac);this.intro_div=$("<div/>").addClass("intro").appendTo(this.viewport_container).hide();var af=$("<div/>").text("Add Datasets to Visualization").addClass("action-button").appendTo(this.intro_div).click(function(){y.select_datasets(galaxy_config.root+"visualization/list_current_history_datasets",galaxy_config.root+"api/datasets",{"f-dbkey":ac.dbkey},function(ag){ab.each(ag,function(ah){ac.add_drawable(p(ah,ac,ac))})})});this.nav_labeltrack=$("<div/>").addClass("nav-labeltrack").appendTo(this.bottom_container);this.nav_container=$("<div/>").addClass("trackster-nav-container").prependTo(this.top_container);this.nav=$("<div/>").addClass("trackster-nav").appendTo(this.nav_container);this.overview=$("<div/>").addClass("overview").appendTo(this.bottom_container);this.overview_viewport=$("<div/>").addClass("overview-viewport").appendTo(this.overview);this.overview_close=$("<a/>").attr("title","Close overview").addClass("icon-button overview-close tooltip").hide().appendTo(this.overview_viewport);this.overview_highlight=$("<div/>").addClass("overview-highlight").hide().appendTo(this.overview_viewport);this.overview_box_background=$("<div/>").addClass("overview-boxback").appendTo(this.overview_viewport);this.overview_box=$("<div/>").addClass("overview-box").appendTo(this.overview_viewport);this.default_overview_height=this.overview_box.height();this.nav_controls=$("<div/>").addClass("nav-controls").appendTo(this.nav);this.chrom_select=$("<select/>").attr({name:"chrom"}).css("width","15em").append("<option value=''>Loading</option>").appendTo(this.nav_controls);var ad=function(ag){if(ag.type==="focusout"||(ag.keyCode||ag.which)===13||(ag.keyCode||ag.which)===27){if((ag.keyCode||ag.which)!==27){ac.go_to($(this).val())}$(this).hide();$(this).val("");ac.location_span.show();ac.chrom_select.show()}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",ad).appendTo(this.nav_controls);this.location_span=$("<span/>").addClass("location").attr("original-title","Click to change location").tooltip({placement:"bottom"}).appendTo(this.nav_controls);this.location_span.click(function(){ac.location_span.hide();ac.chrom_select.hide();ac.nav_input.val(ac.chrom+":"+ac.low+"-"+ac.high);ac.nav_input.css("display","inline-block");ac.nav_input.select();ac.nav_input.focus();ac.nav_input.autocomplete({source:function(ai,ag){var aj=[],ah=$.map(ac.get_tracks(d),function(ak){return ak.data_manager.search_features(ai.term).success(function(al){aj=aj.concat(al)})});$.when.apply($,ah).done(function(){ag($.map(aj,function(ak){return{label:ak[0],value:ak[1]}}))})}})});if(this.vis_id!==undefined){this.hidden_input=$("<input/>").attr("type","hidden").val(this.vis_id).appendTo(this.nav_controls)}this.zo_link=$("<a/>").attr("id","zoom-out").attr("title","Zoom out").tooltip({placement:"bottom"}).click(function(){ac.zoom_out();ac.request_redraw()}).appendTo(this.nav_controls);this.zi_link=$("<a/>").attr("id","zoom-in").attr("title","Zoom in").tooltip({placement:"bottom"}).click(function(){ac.zoom_in();ac.request_redraw()}).appendTo(this.nav_controls);this.load_chroms_deferred=this.load_chroms({low:0});this.chrom_select.bind("change",function(){ac.change_chrom(ac.chrom_select.val())});this.browser_content_div.click(function(ag){$(this).find("input").trigger("blur")});this.browser_content_div.bind("dblclick",function(ag){ac.zoom_in(ag.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(ag,ah){this.current_x=ah.offsetX}).bind("drag",function(ag,ai){var aj=ai.offsetX-this.current_x;this.current_x=ai.offsetX;var ah=Math.round(aj/ac.viewport_container.width()*(ac.max_high-ac.max_low));ac.move_delta(-ah)});this.overview_close.click(function(){ac.reset_overview()});this.viewport_container.bind("draginit",function(ag,ah){if(ag.clientX>ac.viewport_container.width()-16){return false}}).bind("dragstart",function(ag,ah){ah.original_low=ac.low;ah.current_height=ag.clientY;ah.current_x=ah.offsetX}).bind("drag",function(ai,ak){var ag=$(this);var al=ak.offsetX-ak.current_x;var ah=ag.scrollTop()-(ai.clientY-ak.current_height);ag.scrollTop(ah);ak.current_height=ai.clientY;ak.current_x=ak.offsetX;var aj=Math.round(al/ac.viewport_container.width()*(ac.high-ac.low));ac.move_delta(aj)}).bind("mousewheel",function(ai,ak,ah,ag){if(ah){ah*=50;var aj=Math.round(-ah/ac.viewport_container.width()*(ac.high-ac.low));ac.move_delta(aj)}});this.top_labeltrack.bind("dragstart",function(ag,ah){return $("<div />").css({height:ac.browser_content_div.height()+ac.top_labeltrack.height()+ac.nav_labeltrack.height()+1,top:"0px",position:"absolute","background-color":"#ccf",opacity:0.5,"z-index":1000}).appendTo($(this))}).bind("drag",function(ak,al){$(al.proxy).css({left:Math.min(ak.pageX,al.startX)-ac.container.offset().left,width:Math.abs(ak.pageX-al.startX)});var ah=Math.min(ak.pageX,al.startX)-ac.container.offset().left,ag=Math.max(ak.pageX,al.startX)-ac.container.offset().left,aj=(ac.high-ac.low),ai=ac.viewport_container.width();ac.update_location(Math.round(ah/ai*aj)+ac.low,Math.round(ag/ai*aj)+ac.low)}).bind("dragend",function(al,am){var ah=Math.min(al.pageX,am.startX),ag=Math.max(al.pageX,am.startX),aj=(ac.high-ac.low),ai=ac.viewport_container.width(),ak=ac.low;ac.low=Math.round(ah/ai*aj)+ak;ac.high=Math.round(ag/ai*aj)+ak;$(am.proxy).remove();ac.request_redraw()});this.add_label_track(new W(this,{content_div:this.top_labeltrack}));this.add_label_track(new W(this,{content_div:this.nav_labeltrack}));$(window).bind("resize",function(){if(this.resize_timer){clearTimeout(this.resize_timer)}this.resize_timer=setTimeout(function(){ac.resize_window()},500)});$(document).bind("redraw",function(){ac.redraw()});this.reset();$(window).trigger("resize")},get_base_color:function(ac){return this.config.get("values")[ac.toLowerCase()+"_color"]||this.config.get("values").n_color}});q(Y.prototype,A.prototype,{changed:function(){this.has_changes=true},update_intro_div:function(){if(this.drawables.length===0){this.intro_div.show()}else{this.intro_div.hide()}},trigger_navigate:function(ad,af,ac,ag){if(this.timer){clearTimeout(this.timer)}if(ag){var ae=this;this.timer=setTimeout(function(){ae.trigger("navigate",ad+":"+af+"-"+ac)},500)}else{view.trigger("navigate",ad+":"+af+"-"+ac)}},update_location:function(ac,ae){this.location_span.text(commatize(ac)+" - "+commatize(ae));this.nav_input.val(this.chrom+":"+commatize(ac)+"-"+commatize(ae));var ad=view.chrom_select.val();if(ad!==""){this.trigger_navigate(ad,view.low,view.high,true)}},load_chroms:function(ae){ae.num=x;var ac=this,ad=$.Deferred();$.ajax({url:galaxy_config.root+"api/genomes/"+this.dbkey,data:ae,dataType:"json",success:function(ag){if(ag.chrom_info.length===0){return}if(ag.reference){var ah=new D(ac);ac.add_label_track(ah);ac.reference_track=ah}ac.chrom_data=ag.chrom_info;var ak='<option value="">Select Chrom/Contig</option>';for(var aj=0,af=ac.chrom_data.length;aj<af;aj++){var ai=ac.chrom_data[aj].chrom;ak+='<option value="'+ai+'">'+ai+"</option>"}if(ag.prev_chroms){ak+='<option value="previous">Previous '+x+"</option>"}if(ag.next_chroms){ak+='<option value="next">Next '+x+"</option>"}ac.chrom_select.html(ak);ac.chrom_start_index=ag.start_index;ad.resolve(ag.chrom_info)},error:function(){alert("Could not load chroms for this dbkey:",ac.dbkey)}});return ad},change_chrom:function(ah,ad,aj){var ae=this;if(!ae.chrom_data){ae.load_chroms_deferred.then(function(){ae.change_chrom(ah,ad,aj)});return}if(!ah||ah==="None"){return}if(ah==="previous"){ae.load_chroms({low:this.chrom_start_index-x});return}if(ah==="next"){ae.load_chroms({low:this.chrom_start_index+x});return}var ai=$.grep(ae.chrom_data,function(ak,al){return ak.chrom===ah})[0];if(ai===undefined){ae.load_chroms({chrom:ah},function(){ae.change_chrom(ah,ad,aj)});return}else{if(ah!==ae.chrom){ae.chrom=ah;ae.chrom_select.val(ae.chrom);ae.max_high=ai.len-1;ae.reset();for(var ag=0,ac=ae.drawables.length;ag<ac;ag++){var af=ae.drawables[ag];if(af.init){af.init()}}if(ae.reference_track){ae.reference_track.init()}}if(ad&&aj){ae.low=Math.max(ad,0);ae.high=Math.min(aj,ae.max_high)}else{ae.low=0;ae.high=ae.max_high}ae.reset_overview();ae.request_redraw()}},go_to:function(ag){ag=ag.replace(/,/g,"");ag=ag.replace(/:|\-/g," ");var ad=ag.split(/\s+/),af=ad[0],ae=(ad[1]?parseInt(ad[1],10):null),ac=(ad[2]?parseInt(ad[2],10):null);if(!ac){ae=ae-15;ac=ae+15}this.change_chrom(af,ae,ac)},move_fraction:function(ae){var ac=this;var ad=ac.high-ac.low;this.move_delta(ae*ad)},move_delta:function(af){var ac=this;var ae=ac.high-ac.low;if(ac.low-af<ac.max_low){ac.low=ac.max_low;ac.high=ac.max_low+ae}else{if(ac.high-af>ac.max_high){ac.high=ac.max_high;ac.low=ac.max_high-ae}else{ac.high-=af;ac.low-=af}}ac.request_redraw({data_fetch:false});if(this.redraw_on_move_fn){clearTimeout(this.redraw_on_move_fn)}this.redraw_on_move_fn=setTimeout(function(){ac.request_redraw()},200);var ad=ac.chrom_select.val();this.trigger_navigate(ad,ac.low,ac.high,true)},add_drawable:function(ac){A.prototype.add_drawable.call(this,ac);ac.init();this.changed();this.update_intro_div()},add_label_track:function(ac){ac.view=this;ac.init();this.label_tracks.push(ac)},remove_drawable:function(ae,ad){A.prototype.remove_drawable.call(this,ae);if(ad){var ac=this;ae.container_div.hide(0,function(){$(this).remove();ac.update_intro_div()})}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},request_redraw:function(ad,ae){var ac=this,af=(ae?[ae]:ac.drawables);ab.each(af,function(ag){var ah=ab.find(ac.tracks_to_be_redrawn,function(ai){return ai[0]===ag});if(ah){ah[1]=ad}else{ac.tracks_to_be_redrawn.push([ag,ad])}});if(!this.requested_redraw){requestAnimationFrame(function(){ac._redraw()});this.requested_redraw=true}},_redraw:function(){this.requested_redraw=false;var ac=this.low,ag=this.high;if(ac<this.max_low){ac=this.max_low}if(ag>this.max_high){ag=this.max_high}var ad=this.high-this.low;if(this.high!==0&&ad<this.min_separation){ag=ac+this.min_separation}this.low=Math.floor(ac);this.high=Math.ceil(ag);this.update_location(this.low,this.high);this.resolution_px_b=this.viewport_container.width()/(this.high-this.low);var af=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ah=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ae=13;this.overview_box.css({left:af,width:Math.max(ae,ah)}).show();if(ah<ae){this.overview_box.css("left",af-(ae-ah)/2)}if(this.overview_highlight){this.overview_highlight.css({left:af,width:ah})}ab.each(this.tracks_to_be_redrawn,function(ak){var ai=ak[0],aj=ak[1];if(ai){ai._draw(aj)}});this.tracks_to_be_redrawn=[];ab.each(this.label_tracks,function(ai){ai._draw()})},zoom_in:function(ad,ae){if(this.max_high===0||this.high-this.low<=this.min_separation){return}var af=this.high-this.low,ag=af/2+this.low,ac=(af/this.zoom_factor)/2;if(ad){ag=ad/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(ag-ac);this.high=Math.round(ag+ac);this.changed();this.request_redraw()},zoom_out:function(){if(this.max_high===0){return}var ad=this.high-this.low,ae=ad/2+this.low,ac=(ad*this.zoom_factor)/2;this.low=Math.round(ae-ac);this.high=Math.round(ae+ac);this.changed();this.request_redraw()},resize_window:function(){this.viewport_container.height(this.container.height()-this.top_container.height()-this.bottom_container.height());this.request_redraw()},set_overview:function(ae){if(this.overview_drawable){if(this.overview_drawable.dataset.id===ae.dataset.id){return}this.overview_viewport.find(".track").remove()}var ad=ae.copy({content_div:this.overview_viewport}),ac=this;ad.header_div.hide();ad.is_overview=true;ac.overview_drawable=ad;this.overview_drawable.postdraw_actions=function(){ac.overview_highlight.show().height(ac.overview_drawable.content_div.height());ac.overview_viewport.height(ac.overview_drawable.content_div.height()+ac.overview_box.outerHeight());ac.overview_close.show();ac.resize_window()};ac.overview_drawable.request_draw();this.changed()},reset_overview:function(){$(".tooltip").remove();this.overview_viewport.find(".track-tile").remove();this.overview_viewport.height(this.default_overview_height);this.overview_box.height(this.default_overview_height);this.overview_close.hide();this.overview_highlight.hide();view.resize_window();view.overview_drawable=null}});var s=R.Tool.extend({defaults:{track:null},initialize:function(ac){var ad=true;if(ac.tool_state!==undefined&&ac.tool_state.hidden!==undefined){ad=ac.tool_state.hidden}this.set("hidden",ad);this.remove_inputs(["data","hidden_data","conditional"])},state_dict:function(ac){return ab.extend(this.get_inputs_dict(),{hidden:!this.is_visible()})}});var v=Backbone.View.extend({events:{"change input":"update_value"},render:function(){var ae=this.$el.addClass("param-row"),af=this.model;var ac=$("<div>").addClass("param-label").text(af.get("label")).appendTo(ae);var ad=$("<div/>").addClass("param-input").html(af.get("html")).appendTo(ae);ad.find(":input").val(af.get("value"));$("<div style='clear: both;'/>").appendTo(ae)},update_value:function(ac){this.model.set_value($(ac.target).val())}});var aa=Backbone.View.extend({initialize:function(ac){this.model.on("change:hidden",this.set_visible,this)},render:function(){var ad=this;tool=this.model,parent_div=this.$el.addClass("dynamic-tool").hide();parent_div.bind("drag",function(ah){ah.stopPropagation()}).click(function(ah){ah.stopPropagation()}).bind("dblclick",function(ah){ah.stopPropagation()}).keydown(function(ah){ah.stopPropagation()});var ae=$("<div class='tool-name'>").appendTo(parent_div).text(tool.get("name"));tool.get("inputs").each(function(ai){var ah=new v({model:ai});ah.render();parent_div.append(ah.$el)});parent_div.find("input").click(function(){$(this).select()});var af=$("<div>").addClass("param-row").appendTo(parent_div);var ag=$("<input type='submit'>").attr("value","Run on complete dataset").appendTo(af);var ac=$("<input type='submit'>").attr("value","Run on visible region").css("margin-left","3em").appendTo(af);ac.click(function(){ad.run_on_region()});ag.click(function(){ad.run_on_dataset()});if(tool.is_visible()){this.$el.show()}},set_visible:function(){if(this.model.is_visible()){this.$el.show()}else{this.$el.hide()}},update_params:function(){for(var ac=0;ac<this.params.length;ac++){this.params[ac].update_value()}},run_on_dataset:function(){var ac=this.model;this.run({target_dataset_id:this.model.get("track").dataset.id,action:"rerun",tool_id:ac.id},null,function(ad){Galaxy.modal.show({title:ac.get("name")+" is Running",body:ac.get("name")+" is running on the complete dataset. Tool outputs are in dataset's history.",buttons:{Close:function(){Galaxy.modal.hide()}}})})},run_on_region:function(){var ad=this.model.get("track"),ag=this.model,ai=new y.GenomeRegion({chrom:ad.view.chrom,start:ad.view.low,end:ad.view.high}),aj={target_dataset_id:ad.dataset.id,action:"rerun",tool_id:ag.id,regions:[ai.toJSON()]},ah=ad,al=aj.tool_id+ah.tool_region_and_parameters_str(ai),ac;if(ah.container===view){var ak=new P(view,view,{name:ad.prefs.name});var af=ah.container.replace_drawable(ah,ak,false);ak.container_div.insertBefore(ah.view.content_div.children()[af]);ak.add_drawable(ah);ah.container_div.appendTo(ak.content_div);ac=ak}else{ac=ah.container}var ae=new ah.constructor(view,ac,{name:al,hda_ldda:"hda"});ae.init_for_tool_data();ae.change_mode(ah.mode);ae.set_filters_manager(ah.filters_manager.copy(ae));ae.update_icons();ac.add_drawable(ae);ae.tiles_div.text("Starting job.");this.run(aj,ae,function(am){ae.set_dataset(new X.Dataset(am));ae.tiles_div.text("Running job.");ae.init()})},run:function(ac,ae,af){ac.inputs=this.model.get_inputs_dict();var ad=new l.ServerStateDeferred({ajax_settings:{url:galaxy_config.root+"api/tools",data:JSON.stringify(ac),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(ag){return ag!=="pending"}});$.when(ad.go()).then(function(ag){if(ag==="no converter"){ae.container_div.addClass("error");ae.content_div.text(J)}else{if(ag.error){ae.container_div.addClass("error");ae.content_div.text(z+ag.message)}else{af(ag)}}})}});var E=function(ac,ad){L.Scaler.call(this,ad);this.filter=ac};E.prototype.gen_val=function(ac){if(this.filter.high===Number.MAX_VALUE||this.filter.low===-Number.MAX_VALUE||this.filter.low===this.filter.high){return this.default_val}return((parseFloat(ac[this.filter.index])-this.filter.low)/(this.filter.high-this.filter.low))};var j=Backbone.Model.extend({initialize:function(ad){var ac={};ab.each(ad.params,function(ae){ac[ae.key]=ae.default_value});if(ad.saved_values){ab.each(this.get("params"),function(ae){if(ae.key in ad.saved_values){ac[ae.key]=ad.saved_values[ae.key]}})}this.set("values",ac)},set_param_default_value:function(ad,ac){var ae=ab.find(this.get("params"),function(af){return af.key===ad});if(ae){ae.default_value=ac}},set_param_value:function(ac,ad){var ae=ab.find(this.get("params"),function(af){return af.key===ac});if(ae){if(typeof ad==="string"||ad instanceof String){if(ad.trim()===""){ad=ae.default_value}else{if(ae.type==="float"){ad=parseFloat(ad)}else{if(ae.type==="int"){ad=parseInt(ad,10)}}}}}if(this.get("values")[ac]!==ad){this.get("values")[ac]=ad;this.trigger("change:values");return true}else{return false}}});var a=Backbone.View.extend({render:function(){var aj=this.model;var ac=$("<div/>").keydown(function(ak){ak.stopPropagation()});var ai;function ah(ao,ak){for(var at=0;at<ao.length;at++){ai=ao[at];if(ai.hidden){continue}var am="param_"+at;var ax=aj.get("values")[ai.key];var az=$("<div class='form-row' />").appendTo(ak);az.append($("<label />").attr("for",am).text(ai.label+":"));if(ai.type==="bool"){az.append($('<input type="checkbox" />').attr("id",am).attr("name",am).attr("checked",ax))}else{if(ai.type==="text"){az.append($('<input type="text"/>').attr("id",am).val(ax).click(function(){$(this).select()}))}else{if(ai.type==="select"){var av=$("<select />").attr("id",am);for(var aq=0;aq<ai.options.length;aq++){$("<option/>").text(ai.options[aq].label).attr("value",ai.options[aq].value).appendTo(av)}av.val(ax);az.append(av)}else{if(ai.type==="color"){var ay=$("<div/>").appendTo(az),au=$("<input />").attr("id",am).attr("name",am).val(ax).css("float","left").appendTo(ay).click(function(aB){$(".tooltip").removeClass("in");var aA=$(this).siblings(".tooltip").addClass("in");aA.css({left:$(this).position().left+$(this).width()+5,top:$(this).position().top+Galaxy.modal.scrollTop()-($(aA).height()/2)+($(this).height()/2)}).show();aA.click(function(aC){aC.stopPropagation()});$(document).bind("click.color-picker",function(){aA.hide();$(document).unbind("click.color-picker")});aB.stopPropagation()}),ar=$("<a href='javascript:void(0)'/>").addClass("icon-button arrow-circle").appendTo(ay).attr("title","Set new random color").tooltip(),aw=$("<div class='tooltip right' style='position: absolute;' />").appendTo(ay).hide(),an=$("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(aw),al=$("<div class='tooltip-arrow'></div>").appendTo(aw),ap=$.farbtastic(an,{width:100,height:100,callback:au,color:ax});ay.append($("<div/>").css("clear","both"));(function(aA){ar.click(function(){aA.setColor(l.get_random_color())})})(ap)}else{az.append($("<input />").attr("id",am).attr("name",am).val(ax))}}}}if(ai.help){az.append($("<div class='help'/>").text(ai.help))}}}ah(aj.get("params"),ac);var ad=this,ag=function(){Galaxy.modal.hide();$(window).unbind("keypress.check_enter_esc")},ae=function(){ad.update_from_form($(Galaxy.modal.el));Galaxy.modal.hide();$(window).unbind("keypress.check_enter_esc")},af=function(ak){if((ak.keyCode||ak.which)===27){ag()}else{if((ak.keyCode||ak.which)===13){ae()}}};$(window).bind("keypress.check_enter_esc",af);Galaxy.modal.show({title:"Configure",body:ac,buttons:{Cancel:ag,Ok:ae}})},update_from_form:function(ac){var ad=this.model;var ae=false;ab.each(ad.get("params"),function(ah,af){if(!ah.hidden){var ai="param_"+af;var ag=ac.find("#"+ai).val();if(ah.type==="bool"){ag=ac.find("#"+ai).is(":checked")}ae=ad.set_param_value(ah.key,ag)||ae}})}});var c=function(ac,af,ag,ad,ae){this.track=ac;this.region=af;this.low=af.get("start");this.high=af.get("end");this.w_scale=ag;this.canvas=ad;this.html_elt=$("<div class='track-tile'/>").append(ad);this.data=ae;this.stale=false};c.prototype.predisplay_actions=function(){};var M=function(ac,af,ag,ad,ae){c.call(this,ac,af,ag,ad,ae)};M.prototype.predisplay_actions=function(){};var O=function(af,am,ao,ae,ah,ai,ap,ad,al){c.call(this,af,am,ao,ae,ah);this.mode=ai;this.all_slotted=ad;this.feature_mapper=al;this.has_icons=false;if(ap){this.has_icons=true;var aj=this;ae=this.html_elt.children()[0],message_div=$("<div/>").addClass("tile-message").css({height:F,width:ae.width}).prependTo(this.html_elt);var ak=new y.GenomeRegion({chrom:af.view.chrom,start:this.low,end:this.high}),an=ah.length,ag=$("<a/>").addClass("icon more-down").attr("title","For speed, only the first "+an+" features in this region were obtained from server. Click to get more data including depth").tooltip().appendTo(message_div),ac=$("<a/>").addClass("icon more-across").attr("title","For speed, only the first "+an+" features in this region were obtained from server. Click to get more data excluding depth").tooltip().appendTo(message_div);ag.click(function(){aj.stale=true;af.data_manager.get_more_data(ak,af.mode,1/aj.w_scale,{},af.data_manager.DEEP_DATA_REQ);$(".tooltip").hide();af.request_draw()}).dblclick(function(aq){aq.stopPropagation()});ac.click(function(){aj.stale=true;af.data_manager.get_more_data(ak,af.mode,1/aj.w_scale,{},af.data_manager.BROAD_DATA_REQ);$(".tooltip").hide();af.request_draw()}).dblclick(function(aq){aq.stopPropagation()})}};q(O.prototype,c.prototype);O.prototype.predisplay_actions=function(){var ad=this,ac={};if(ad.mode!=="Pack"){return}$(this.html_elt).hover(function(){this.hovered=true;$(this).mousemove()},function(){this.hovered=false;$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()}).mousemove(function(ao){if(!this.hovered){return}var aj=$(this).offset(),an=ao.pageX-aj.left,am=ao.pageY-aj.top,at=ad.feature_mapper.get_feature_data(an,am),ak=(at?at[0]:null);$(this).parents(".track-content").children(".overlay").children(".feature-popup").each(function(){if(!ak||$(this).attr("id")!==ak.toString()){$(this).remove()}});if(at){var af=ac[ak];if(!af){var ap={name:at[3],start:at[1],end:at[2],strand:at[4]},ai=ad.track.filters_manager.filters,ah;for(var al=0;al<ai.length;al++){ah=ai[al];ap[ah.name]=at[ah.index]}af=$("<div/>").attr("id",ak).addClass("feature-popup");var au=$("<table/>"),ar,aq,av;for(ar in ap){aq=ap[ar];av=$("<tr/>").appendTo(au);$("<th/>").appendTo(av).text(ar);$("<td/>").attr("align","left").appendTo(av).text(typeof(aq)==="number"?V(aq,2):aq)}af.append($("<div class='feature-popup-inner'>").append(au));ac[ak]=af}af.appendTo($(this).parents(".track-content").children(".overlay"));var ag=an+parseInt(ad.html_elt.css("left"),10)-af.width()/2,ae=am+parseInt(ad.html_elt.css("top"),10)+7;af.css("left",ag+"px").css("top",ae+"px")}else{if(!ao.isPropagationStopped()){ao.stopPropagation();$(this).siblings().each(function(){$(this).trigger(ao)})}}}).mouseleave(function(){$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()})};var g=function(ad,ac,ae){q(ae,{drag_handle_class:"draghandle"});r.call(this,ad,ac,ae);this.dataset=null;if(ae.dataset){this.dataset=(ae.dataset instanceof Backbone.Model?ae.dataset:X.Dataset.findOrCreate(ae.dataset))}this.dataset_check_type="converted_datasets_state";this.data_url_extra_params={};this.data_query_wait=("data_query_wait" in ae?ae.data_query_wait:K);this.data_manager=("data_manager" in ae?ae.data_manager:new y.GenomeDataManager({dataset:this.dataset,genome:new y.Genome({key:ad.dbkey,chroms_info:{chrom_info:ad.chrom_data}}),data_mode_compatible:this.data_and_mode_compatible,can_subset:this.can_subset}));this.min_height_px=16;this.max_height_px=800;this.visible_height_px=this.prefs.height;this.content_div=$("<div class='track-content'>").appendTo(this.container_div);if(this.container){this.container.content_div.append(this.container_div);if(!("resize" in ae)||ae.resize){this.add_resize_handle()}}};q(g.prototype,r.prototype,{action_icons_def:[{name:"mode_icon",title:"Set display mode",css_class:"chevron-expand",on_click_fn:function(){}},r.prototype.action_icons_def[0],{name:"overview_icon",title:"Set as overview",css_class:"overview-icon",on_click_fn:function(ac){ac.view.set_overview(ac)}},r.prototype.action_icons_def[1],{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ac){if(ac.filters_manager.visible()){ac.filters_manager.clear_filters()}else{ac.filters_manager.init_filters()}ac.filters_manager.toggle()}},{name:"tools_icon",title:"Tool",css_class:"hammer",on_click_fn:function(ac){ac.tool.toggle();if(ac.tool.is_visible()){ac.set_name(ac.name+ac.tool_region_and_parameters_str())}else{ac.revert_name()}$(".tooltip").remove()}},{name:"param_space_viz_icon",title:"Tool parameter space visualization",css_class:"arrow-split",on_click_fn:function(ac){var af='<strong>Tool</strong>: <%= track.tool.name %><br/><strong>Dataset</strong>: <%= track.name %><br/><strong>Region(s)</strong>: <select name="regions"><option value="cur">current viewing area</option><option value="bookmarks">bookmarks</option><option value="both">current viewing area and bookmarks</option></select>',ae=ab.template(af,{track:ac});var ah=function(){Galaxy.modal.hide();$(window).unbind("keypress.check_enter_esc")},ad=function(){var aj=$('select[name="regions"] option:selected').val(),al,ai=new y.GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),ak=ab.map($(".bookmark"),function(am){return new y.GenomeRegion({from_str:$(am).children(".position").text()})});if(aj==="cur"){al=[ai]}else{if(aj==="bookmarks"){al=ak}else{al=[ai].concat(ak)}}Galaxy.modal.hide();window.location.href=galaxy_config.root+"visualization/sweepster?"+$.param({dataset_id:ac.dataset.id,hda_ldda:ac.dataset.get("hda_ldda"),regions:JSON.stringify(new Backbone.Collection(al).toJSON())})},ag=function(ai){if((ai.keyCode||ai.which)===27){ah()}else{if((ai.keyCode||ai.which)===13){ad()}}};Galaxy.modal.show({title:"Visualize tool parameter space and output from different parameter settings?",body:ae,buttons:{No:ah,Yes:ad}})}},r.prototype.action_icons_def[2]],can_draw:function(){return this.dataset&&r.prototype.can_draw.call(this)},build_container_div:function(){return $("<div/>").addClass("track").attr("id","track_"+this.id).css("position","relative")},build_header_div:function(){var ac=$("<div class='track-header'/>");if(this.view.editor){this.drag_div=$("<div/>").addClass(this.drag_handle_class).appendTo(ac)}this.name_div=$("<div/>").addClass("track-name").appendTo(ac).text(this.prefs.name).attr("id",this.prefs.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase());return ac},set_dataset:function(ac){this.dataset=ac;this.data_manager.set("dataset",ac)},on_resize:function(){this.request_draw({clear_tile_cache:true})},add_resize_handle:function(){var ac=this;var af=false;var ae=false;var ad=$("<div class='track-resize'>");$(ac.container_div).hover(function(){if(ac.prefs.content_visible){af=true;ad.show()}},function(){af=false;if(!ae){ad.hide()}});ad.hide().bind("dragstart",function(ag,ah){ae=true;ah.original_height=$(ac.content_div).height()}).bind("drag",function(ah,ai){var ag=Math.min(Math.max(ai.original_height+ai.deltaY,ac.min_height_px),ac.max_height_px);$(ac.tiles_div).css("height",ag);ac.visible_height_px=(ac.max_height_px===ag?0:ag);ac.on_resize()}).bind("dragend",function(ag,ah){ac.tile_cache.clear();ae=false;if(!af){ad.hide()}ac.config.get("values").height=ac.visible_height_px;ac.changed()}).appendTo(ac.container_div)},set_display_modes:function(af,ai){this.display_modes=af;this.mode=(ai?ai:(this.config&&this.config.get("values").mode?this.config.get("values").mode:this.display_modes[0]));this.action_icons.mode_icon.attr("title","Set display mode (now: "+this.mode+")");var ad=this,ag={};for(var ae=0,ac=ad.display_modes.length;ae<ac;ae++){var ah=ad.display_modes[ae];ag[ah]=function(aj){return function(){ad.change_mode(aj);ad.icons_div.show();ad.container_div.mouseleave(function(){ad.icons_div.hide()})}}(ah)}make_popupmenu(this.action_icons.mode_icon,ag)},build_action_icons:function(){r.prototype.build_action_icons.call(this,this.action_icons_def);if(this.display_modes!==undefined){this.set_display_modes(this.display_modes)}},hide_contents:function(){this.tiles_div.hide();this.container_div.find(".yaxislabel, .track-resize").hide()},show_contents:function(){this.tiles_div.show();this.container_div.find(".yaxislabel, .track-resize").show();this.request_draw()},get_type:function(){if(this instanceof W){return"LabelTrack"}else{if(this instanceof D){return"ReferenceTrack"}else{if(this instanceof h){return"LineTrack"}else{if(this instanceof T){return"ReadTrack"}else{if(this instanceof Z){return"VariantTrack"}else{if(this instanceof f){return"CompositeTrack"}else{if(this instanceof d){return"FeatureTrack"}}}}}}}return""},init:function(ae){var ad=this;ad.enabled=false;ad.tile_cache.clear();ad.data_manager.clear();ad.tiles_div.css("height","auto");ad.tiles_div.text("").children().remove();ad.container_div.removeClass("nodata error pending");if(!ad.dataset.id){return}var ac=$.Deferred(),af={hda_ldda:ad.dataset.get("hda_ldda"),data_type:this.dataset_check_type,chrom:ad.view.chrom,retry:ae};$.getJSON(this.dataset.url(),af,function(ag){if(!ag||ag==="error"||ag.kind==="error"){ad.container_div.addClass("error");ad.tiles_div.text(o);if(ag.message){ad.tiles_div.append($("<a href='javascript:void(0);'></a>").text("View error").click(function(){Galaxy.modal.show({title:"Trackster Error",body:"<pre>"+ag.message+"</pre>",buttons:{Close:function(){Galaxy.modal.hide()}}})}));ad.tiles_div.append($("<span/>").text(" "));ad.tiles_div.append($("<a href='javascript:void(0);'></a>").text("Try again").click(function(){ad.init(true)}))}}else{if(ag==="no converter"){ad.container_div.addClass("error");ad.tiles_div.text(J)}else{if(ag==="no data"||(ag.data!==undefined&&(ag.data===null||ag.data.length===0))){ad.container_div.addClass("nodata");ad.tiles_div.text(G)}else{if(ag==="pending"){ad.container_div.addClass("pending");ad.tiles_div.html(w);setTimeout(function(){ad.init()},ad.data_query_wait)}else{if(ag==="data"||ag.status==="data"){if(ag.valid_chroms){ad.valid_chroms=ag.valid_chroms;ad.update_icons()}ad.tiles_div.text(U);if(ad.view.chrom){ad.tiles_div.text("");ad.tiles_div.css("height",ad.visible_height_px+"px");ad.enabled=true;$.when.apply($,ad.predraw_init()).done(function(){ac.resolve();ad.container_div.removeClass("nodata error pending");ad.request_draw()})}else{ac.resolve()}}}}}}});this.update_icons();return ac},predraw_init:function(){var ac=this;return $.getJSON(ac.dataset.url(),{data_type:"data",stats:true,chrom:ac.view.chrom,low:0,high:ac.view.max_high,hda_ldda:ac.dataset.get("hda_ldda")},function(ad){ac.container_div.addClass("line-track");var af=ad.data;if(af&&af.min&&af.max){var ae=af.min,ag=af.max;ae=Math.floor(Math.min(0,Math.max(ae,af.mean-2*af.sd)));ag=Math.ceil(Math.max(0,Math.min(ag,af.mean+2*af.sd)));ac.config.set_param_default_value("min_value",ae);ac.config.set_param_default_value("max_value",ag);ac.prefs.min_value=ae;ac.prefs.max_value=ag}})},get_drawables:function(){return this}});var N=function(ae,ad,ag){g.call(this,ae,ad,ag);var ac=this;m(ac.container_div,ac.drag_handle_class,".group",ac);this.filters_manager=new i.FiltersManager(this,("filters" in ag?ag.filters:null));this.data_manager.set("filters_manager",this.filters_manager);this.filters_available=false;this.tool=(ag.tool?new s(ab.extend(ag.tool,{track:this,tool_state:ag.tool_state})):null);this.tile_cache=new y.Cache(Q);this.left_offset=0;if(this.header_div){this.set_filters_manager(this.filters_manager);if(this.tool){var af=new aa({model:this.tool});af.render();this.dynamic_tool_div=af.$el;this.header_div.after(this.dynamic_tool_div)}}this.tiles_div=$("<div/>").addClass("tiles").appendTo(this.content_div);if(!this.prefs.content_visible){this.tiles_div.hide()}this.overlay_div=$("<div/>").addClass("overlay").appendTo(this.content_div);if(ag.mode){this.change_mode(ag.mode)}};q(N.prototype,r.prototype,g.prototype,{action_icons_def:g.prototype.action_icons_def.concat([{name:"show_more_rows_icon",title:"To minimize track height, not all feature rows are displayed. Click to display more rows.",css_class:"exclamation",on_click_fn:function(ac){$(".tooltip").remove();ac.slotters[ac.view.resolution_px_b].max_rows*=2;ac.request_draw({clear_tile_cache:true})},hide:true}]),copy:function(ac){var ad=this.to_dict();q(ad,{data_manager:this.data_manager});var ae=new this.constructor(this.view,ac,ad);ae.change_mode(this.mode);ae.enabled=this.enabled;return ae},set_filters_manager:function(ac){this.filters_manager=ac;this.header_div.after(this.filters_manager.parent_div)},to_dict:function(){return{track_type:this.get_type(),dataset:{id:this.dataset.id,hda_ldda:this.dataset.get("hda_ldda")},prefs:this.prefs,mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},set_min_max:function(){var ac=this;return $.getJSON(ac.dataset.url(),{data_type:"data",stats:true,chrom:ac.view.chrom,low:0,high:ac.view.max_high,hda_ldda:ac.dataset.get("hda_ldda")},function(ad){var af=ad.data;if(isNaN(parseFloat(ac.prefs.min_value))||isNaN(parseFloat(ac.prefs.max_value))){var ae=af.min,ag=af.max;ae=Math.floor(Math.min(0,Math.max(ae,af.mean-2*af.sd)));ag=Math.ceil(Math.max(0,Math.min(ag,af.mean+2*af.sd)));ac.prefs.min_value=ae;ac.prefs.max_value=ag}})},change_mode:function(ad){var ac=this;ac.mode=ad;ac.config.get("values").mode=ad;if(ad==="Auto"){this.data_manager.clear()}ac.request_draw({clear_tile_cache:true});this.action_icons.mode_icon.attr("title","Set display mode (now: "+ac.mode+")");return ac},update_icons:function(){var ac=this;if(ac.filters_available){ac.action_icons.filters_icon.show()}else{ac.action_icons.filters_icon.hide()}if(ac.tool){ac.action_icons.tools_icon.show();ac.action_icons.param_space_viz_icon.show()}else{ac.action_icons.tools_icon.hide();ac.action_icons.param_space_viz_icon.hide()}},_gen_tile_cache_key:function(ad,ac){return ad+"_"+ac},request_draw:function(ac){if(ac&&ac.clear_tile_cache){this.tile_cache.clear()}this.view.request_redraw(ac,this)},before_draw:function(){this.max_height_px=0},_draw:function(aq){if(!this.can_draw()){return}var an=aq&&aq.clear_after,al=this.view.low,ag=this.view.high,aj=ag-al,ad=this.view.container.width(),ap=this.view.resolution_px_b,af=1/ap;if(this.is_overview){al=this.view.max_low;ag=this.view.max_high;ap=ad/(view.max_high-view.max_low);af=1/ap}this.before_draw();this.tiles_div.children().addClass("remove");var ac=Math.floor(al/(af*S)),ak,am,ah,ai=[],ao=[];while((ac*S*af)<ag){ak=Math.floor(ac*S*af);am=new y.GenomeRegion({chrom:this.view.chrom,start:ak,end:Math.min(ak+Math.ceil(S*af),this.view.max_high)});ah=this.draw_helper(am,ap,aq);ai.push(ah);$.when(ah).then(function(ar){ao.push(ar)});ac+=1}if(!an){this.tiles_div.children(".remove").removeClass("remove").remove()}var ae=this;$.when.apply($,ai).then(function(){ae.tiles_div.children(".remove").remove();ao=ab.filter(ao,function(ar){return ar!==null});if(ao.length!==0){ae.postdraw_actions(ao,ad,ap,an)}})},_add_yaxis_label:function(af,ah){var ad=this,ag=(af==="max"?"top":"bottom"),ai=(af==="max"?"max":"min"),ac=(af==="max"?"max_value":"min_value"),ae=this.container_div.find(".yaxislabel."+ag);ah=ah||function(){ad.request_draw({clear_tile_cache:true})};if(ae.length!==0){ae.text(ad.prefs[ac])}else{ae=$("<div/>").text(ad.prefs[ac]).make_text_editable({num_cols:12,on_finish:function(aj){$(".tooltip").remove();ad.config.set_param_value(ac,aj);ah()},help_text:"Set "+ai+" value"}).addClass("yaxislabel "+ag).css("color",this.prefs.label_color);this.container_div.prepend(ae)}},postdraw_actions:function(af,ag,ai,ac){var ae=ab.filter(af,function(aj){return(aj instanceof M)});if(ae.length>0){this.max_height_px=0;var ad=this;ab.each(af,function(aj){if(!(aj instanceof M)){aj.html_elt.remove();ad.draw_helper(aj.region,ai,{force:true,mode:"Coverage"})}});ad._add_yaxis_label("max")}else{this.container_div.find(".yaxislabel").remove();var ah=ab.find(af,function(aj){return aj.has_icons});if(ah){ab.each(af,function(aj){if(!aj.has_icons){aj.html_elt.css("padding-top",F)}})}}},get_mode:function(ac){return this.mode},update_auto_mode:function(ac){},_get_drawables:function(){return[this]},draw_helper:function(al,an,ao){if(!ao){ao={}}var ad=ao.force,ai=ao.mode||this.mode,af=1/an,ae=this,ag=this._get_drawables(),am=this._gen_tile_cache_key(an,al),ah=function(ap){return(ap&&"track" in ap)};var aj=(ad?undefined:ae.tile_cache.get_elt(am));if(aj){if(ah(aj)){ae.show_tile(aj,an)}return aj}if(ao.data_fetch===false){return null}var ak=function(){var ap=(ab.find(C,function(ar){return ar===ai})?"Coverage":ai);var aq=ab.map(ag,function(ar){return ar.data_manager.get_data(al,ap,af,ae.data_url_extra_params)});if(view.reference_track){aq.push(view.reference_track.data_manager.get_data(al,ai,af,view.reference_track.data_url_extra_params))}return aq};var ac=$.Deferred();ae.tile_cache.set_elt(am,ac);$.when.apply($,ak()).then(function(){var ap=ak(),av=ap,aB;if(view.reference_track){aB=view.reference_track.data_manager.subset_entry(ap.pop(),al)}var aw=[],at=[];ab.each(ag,function(aG,aD){var aF=aG.mode,aE=av[aD];if(aF==="Auto"){aF=aG.get_mode(aE);aG.update_auto_mode(aF)}aw.push(aF);at.push(aG.get_canvas_height(aE,aF,an,aq))});var au=ae.view.canvas_manager.new_canvas(),ax=al.get("start"),aC=al.get("end"),ar=0,aq=Math.ceil((aC-ax)*an)+ae.left_offset,az=ab.max(at),ay;au.width=aq;au.height=(ao.height||az);var aA=au.getContext("2d");aA.translate(ae.left_offset,0);if(ag.length>1){aA.globalAlpha=0.5;aA.globalCompositeOperation="source-over"}ab.each(ag,function(aE,aD){ay=aE.draw_tile(av[aD],aA,aw[aD],al,an,aB)});if(ay!==undefined){ae.tile_cache.set_elt(am,ay);ae.show_tile(ay,an)}ac.resolve(ay)});return ac},get_canvas_height:function(ac,ae,af,ad){return this.visible_height_px},_draw_line_track_tile:function(ac,ae,ah,ag,ai){var af=ae.canvas,ad=new L.LinePainter(ac.data,ag.get("start"),ag.get("end"),this.prefs,ah);ad.draw(ae,af.width,af.height,ai);return new M(this,ag,ai,af,ac.data)},draw_tile:function(ac,ad,ag,af,ah,ae){},show_tile:function(ae,ah){var ad=this,ac=ae.html_elt;ae.predisplay_actions();var ag=(ae.low-(this.is_overview?this.view.max_low:this.view.low))*ah;if(this.left_offset){ag-=this.left_offset}ac.css({position:"absolute",top:0,left:ag});if(ac.hasClass("remove")){ac.removeClass("remove")}else{this.tiles_div.append(ac)}ac.css("height","auto");this.max_height_px=Math.max(this.max_height_px,ac.height());ac.parent().children().css("height",this.max_height_px+"px");var af=this.max_height_px;if(this.visible_height_px!==0){af=Math.min(this.max_height_px,this.visible_height_px)}this.tiles_div.css("height",af+"px")},tool_region_and_parameters_str:function(af){var ac=this,ae=(af!==undefined?af.toString():"all"),ad=ab.values(ac.tool.get_inputs_dict()).join(", ");return" - region=["+ae+"], parameters=["+ad+"]"},data_and_mode_compatible:function(ac,ad){if(ad==="Auto"){return true}else{if(ad==="Coverage"){return ac.dataset_type==="bigwig"}else{if(ac.dataset_type==="bigwig"||ac.extra_info==="no_detail"){return false}else{return true}}}},can_subset:function(ac){if(ac.message||ac.extra_info==="no_detail"){return false}else{if(ac.dataset_type==="bigwig"){return(ac.data[1][0]-ac.data[0][0]===1)}}return true},init_for_tool_data:function(){this.data_manager.set("data_type","raw_data");this.data_query_wait=1000;this.dataset_check_type="state"}});var W=function(ad,ac){var ae={resize:false};g.call(this,ad,ac,ae);this.container_div.addClass("label-track")};q(W.prototype,g.prototype,{build_header_div:function(){},init:function(){this.enabled=true},predraw_init:function(){},_draw:function(ag){var ae=this.view,af=ae.high-ae.low,aj=Math.floor(Math.pow(10,Math.floor(Math.log(af)/Math.log(10)))),ac=Math.floor(ae.low/aj)*aj,ah=this.view.container.width(),ad=$("<div style='position: relative; height: 1.3em;'></div>");while(ac<ae.high){var ai=(ac-ae.low)/af*ah;ad.append($("<div class='label'>"+commatize(ac)+"</div>").css({position:"absolute",left:ai-1}));ac+=aj}this.content_div.children(":first").remove();this.content_div.append(ad)}});var f=function(ad,ac,ag){N.call(this,ad,ac,ag);this.drawables=[];if("drawables" in ag){var af;for(var ae=0;ae<ag.drawables.length;ae++){af=ag.drawables[ae];this.drawables[ae]=p(af,ad,null);if(af.left_offset>this.left_offset){this.left_offset=af.left_offset}}this.enabled=true}ab.each(this.drawables,function(ah){if(ah instanceof d||ah instanceof T){ah.change_mode("Coverage")}});this.update_icons();this.obj_type="CompositeTrack"};q(f.prototype,N.prototype,{display_modes:C,action_icons_def:[{name:"composite_icon",title:"Show individual tracks",css_class:"layers-stack",on_click_fn:function(ac){$(".tooltip").remove();ac.show_group()}}].concat(N.prototype.action_icons_def),to_dict:A.prototype.to_dict,add_drawable:A.prototype.add_drawable,unpack_drawables:A.prototype.unpack_drawables,change_mode:function(ac){N.prototype.change_mode.call(this,ac);for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad].change_mode(ac)}},init:function(){var ae=[];for(var ad=0;ad<this.drawables.length;ad++){ae.push(this.drawables[ad].init())}var ac=this;$.when.apply($,ae).then(function(){ac.enabled=true;ac.request_draw()})},update_icons:function(){this.action_icons.filters_icon.hide();this.action_icons.tools_icon.hide();this.action_icons.param_space_viz_icon.hide()},can_draw:r.prototype.can_draw,_get_drawables:function(){return this.drawables},show_group:function(){var af=new P(this.view,this.container,{name:this.prefs.name}),ac;for(var ae=0;ae<this.drawables.length;ae++){ac=this.drawables[ae];ac.update_icons();af.add_drawable(ac);ac.container=af;af.content_div.append(ac.container_div)}var ad=this.container.replace_drawable(this,af,true);af.request_draw({clear_tile_cache:true})},before_draw:function(){N.prototype.before_draw.call(this);var ad=ab.min(ab.map(this.drawables,function(ae){return ae.prefs.min_value})),ac=ab.max(ab.map(this.drawables,function(ae){return ae.prefs.max_value}));this.prefs.min_value=ad;this.prefs.max_value=ac;ab.each(this.drawables,function(ae){ae.prefs.min_value=ad;ae.prefs.max_value=ac})},update_all_min_max:function(){var ac=this;ab.each(this.drawables,function(ad){ad.prefs.min_value=ac.prefs.min_value;ad.prefs.max_value=ac.prefs.max_value});this.request_draw({clear_tile_cache:true})},postdraw_actions:function(ai,ac,al,ah){N.prototype.postdraw_actions.call(this,ai,ac,al,ah);var ag=-1,ae;for(ae=0;ae<ai.length;ae++){var aj=ai[ae].html_elt.find("canvas").height();if(aj>ag){ag=aj}}for(ae=0;ae<ai.length;ae++){var af=ai[ae];if(af.html_elt.find("canvas").height()!==ag){this.draw_helper(af.region,al,{force:true,height:ag});af.html_elt.remove()}}var ad=this,ak=function(){ad.update_all_min_max()};this._add_yaxis_label("min",ak);this._add_yaxis_label("max",ak)}});var D=function(ac){N.call(this,ac,{content_div:ac.top_labeltrack},{resize:false});this.left_offset=ac.canvas_manager.char_width_px;this.container_div.addClass("reference-track");this.data_url=galaxy_config.root+"api/genomes/"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new y.GenomeReferenceDataManager({data_url:this.data_url,can_subset:this.can_subset});this.hide_contents()};q(D.prototype,r.prototype,N.prototype,{config_params:ab.union(r.prototype.config_params,[{key:"height",type:"int",default_value:13,hidden:true}]),build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},predraw_init:function(){},can_draw:r.prototype.can_draw,draw_helper:function(ad,ae,ac){if(ae>this.view.canvas_manager.char_width_px){this.tiles_div.show();return N.prototype.draw_helper.call(this,ad,ae,ac)}else{this.tiles_div.hide();return null}},can_subset:function(ac){return true},draw_tile:function(ae,ak,af,ah,al){var ad=this.data_manager.subset_entry(ae,ah),aj=ad.data;var ac=ak.canvas;ak.font=ak.canvas.manager.default_font;ak.textAlign="center";for(var ag=0,ai=aj.length;ag<ai;ag++){ak.fillStyle=this.view.get_base_color(aj[ag]);ak.fillText(aj[ag],Math.floor(ag*al),10)}return new c(this,ah,al,ac,ad)}});var h=function(ad,ac,ae){this.mode="Histogram";N.call(this,ad,ac,ae)};q(h.prototype,r.prototype,N.prototype,{display_modes:C,config_params:ab.union(r.prototype.config_params,[{key:"color",label:"Color",type:"color",default_value:l.get_random_color()},{key:"min_value",label:"Min Value",type:"float",default_value:undefined},{key:"max_value",label:"Max Value",type:"float",default_value:undefined},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:30,hidden:true}]),config_onchange:function(){this.set_name(this.prefs.name);this.request_draw({clear_tile_cache:true})},before_draw:function(){},draw_tile:function(ac,ad,af,ae,ag){return this._draw_line_track_tile(ac,ad,af,ae,ag)},can_subset:function(ac){return(ac.data[1][0]-ac.data[0][0]===1)},postdraw_actions:function(ad,ae,af,ac){this._add_yaxis_label("max");this._add_yaxis_label("min")}});var t=function(ad,ac,ae){this.mode="Heatmap";N.call(this,ad,ac,ae)};q(t.prototype,r.prototype,N.prototype,{display_modes:["Heatmap"],config_params:ab.union(r.prototype.config_params,[{key:"pos_color",label:"Positive Color",type:"color",default_value:"#FF8C00"},{key:"neg_color",label:"Negative Color",type:"color",default_value:"#4169E1"},{key:"min_value",label:"Min Value",type:"float",default_value:-1},{key:"max_value",label:"Max Value",type:"float",default_value:1},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:500,hidden:true}]),config_onchange:function(){this.set_name(this.prefs.name);this.request_draw({clear_tile_cache:true})},draw_tile:function(ac,ae,ah,ag,ai){var af=ae.canvas,ad=new L.DiagonalHeatmapPainter(ac.data,ag.get("start"),ag.get("end"),this.prefs,ah);ad.draw(ae,af.width,af.height,ai);return new c(this,ag,ai,af,ac.data)}});var d=function(ad,ac,ae){N.call(this,ad,ac,ae);this.container_div.addClass("feature-track");this.summary_draw_height=30;this.slotters={};this.start_end_dct={};this.left_offset=200;this.set_painter_from_config()};q(d.prototype,r.prototype,N.prototype,{display_modes:["Auto","Coverage","Dense","Squish","Pack"],config_params:ab.union(r.prototype.config_params,[{key:"block_color",label:"Block color",type:"color",default_value:l.get_random_color()},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:l.get_random_color()},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true,help:"Show the number of items in each bin when drawing summary histogram"},{key:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"connector_style",label:"Connector style",type:"select",default_value:"fishbones",options:[{label:"Line with arrows",value:"fishbone"},{label:"Arcs",value:"arcs"}]},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:0,hidden:true}]),config_onchange:function(){this.set_name(this.prefs.name);this.set_painter_from_config();this.request_draw({clear_tile_cache:true})},set_painter_from_config:function(){if(this.config.get("values").connector_style==="arcs"){this.painter=L.ArcLinkedFeaturePainter}else{this.painter=L.LinkedFeaturePainter}},postdraw_actions:function(am,ae,an,al){N.prototype.postdraw_actions.call(this,am,ae,an,al);var ag=this,ah;if(ag.filters_manager){var af=ag.filters_manager.filters,aj;for(aj=0;aj<af.length;aj++){af[aj].update_ui_elt()}var ai=false,ak,ad;for(ah=0;ah<am.length;ah++){if(am[ah].data.length){ak=am[ah].data[0];for(aj=0;aj<af.length;aj++){ad=af[aj];if(ad.applies_to(ak)&&ad.min!==ad.max){ai=true;break}}}}if(ag.filters_available!==ai){ag.filters_available=ai;if(!ag.filters_available){ag.filters_manager.hide()}ag.update_icons()}}if(am[0] instanceof O){var ac=true;for(ah=0;ah<am.length;ah++){if(!am[ah].all_slotted){ac=false;break}}if(!ac){this.action_icons.show_more_rows_icon.show()}else{this.action_icons.show_more_rows_icon.hide()}}else{this.action_icons.show_more_rows_icon.hide()}},update_auto_mode:function(ac){if(this.mode==="Auto"){if(ac==="no_detail"){ac="feature spans"}this.action_icons.mode_icon.attr("title","Set display mode (now: Auto/"+ac+")")}},incremental_slots:function(ag,ac,af){var ad=this.view.canvas_manager.dummy_context,ae=this.slotters[ag];if(!ae||(ae.mode!==af)){ae=new (u.FeatureSlotter)(ag,af,B,function(ah){return ad.measureText(ah)});this.slotters[ag]=ae}return ae.slot_features(ac)},get_mode:function(ac){if(ac.extra_info==="no_detail"||this.is_overview){mode="no_detail"}else{if(this.view.high-this.view.low>I){mode="Squish"}else{mode="Pack"}}return mode},get_canvas_height:function(ac,ag,ah,ad){if(ag==="Coverage"||ac.dataset_type==="bigwig"){return this.summary_draw_height}else{var af=this.incremental_slots(ah,ac.data,ag);var ae=new (this.painter)(null,null,null,this.prefs,ag);return Math.max(this.min_height_px,ae.get_required_height(af,ad))}},draw_tile:function(am,aq,ao,af,aj,ae){var ap=this,ad=aq.canvas,ax=af.get("start"),ac=af.get("end"),ag=this.left_offset;if(am.dataset_type==="bigwig"){return this._draw_line_track_tile(am,aq,ao,af,aj)}var ai=[],an=this.slotters[aj].slots;all_slotted=true;if(am.data){var ak=this.filters_manager.filters;for(var ar=0,au=am.data.length;ar<au;ar++){var ah=am.data[ar];var at=false;var al;for(var aw=0,aB=ak.length;aw<aB;aw++){al=ak[aw];al.update_attrs(ah);if(!al.keep(ah)){at=true;break}}if(!at){ai.push(ah);if(!(ah[0] in an)){all_slotted=false}}}}var aA=(this.filters_manager.alpha_filter?new E(this.filters_manager.alpha_filter):null),ay=(this.filters_manager.height_filter?new E(this.filters_manager.height_filter):null),az=new (this.painter)(ai,ax,ac,this.prefs,ao,aA,ay,ae,function(aC){return ap.view.get_base_color(aC)});var av=null;aq.fillStyle=this.prefs.block_color;aq.font=aq.canvas.manager.default_font;aq.textAlign="right";if(am.data){av=az.draw(aq,ad.width,ad.height,aj,an);av.translation=-ag}return new O(ap,af,aj,ad,am.data,ao,am.message,all_slotted,av)}});var Z=function(ad,ac,ae){N.call(this,ad,ac,ae);this.painter=L.VariantPainter;this.summary_draw_height=30;this.left_offset=30};q(Z.prototype,r.prototype,N.prototype,{display_modes:["Auto","Coverage","Dense","Squish","Pack"],config_params:ab.union(r.prototype.config_params,[{key:"color",label:"Histogram color",type:"color",default_value:l.get_random_color()},{key:"show_sample_data",label:"Show sample data",type:"bool",default_value:true},{key:"show_labels",label:"Show summary and sample labels",type:"bool",default_value:true},{key:"summary_height",label:"Locus summary height",type:"float",default_value:20},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:0,hidden:true}]),config_onchange:function(){this.set_name(this.prefs.name);this.request_draw({clear_tile_cache:true})},draw_tile:function(ac,af,ah,ag,ai){if(ac.dataset_type==="bigwig"){return this._draw_line_track_tile(ac,af,"Histogram",ag,ai)}else{var ae=this.view,ad=new (this.painter)(ac.data,ag.get("start"),ag.get("end"),this.prefs,ah,function(aj){return ae.get_base_color(aj)});ad.draw(af,af.canvas.width,af.canvas.height,ai);return new c(this,ag,ai,af.canvas,ac.data)}},get_canvas_height:function(ac,ag,ah,ae){if(ac.dataset_type==="bigwig"){return this.summary_draw_height}else{var ad=(this.dataset.get_metadata("sample_names")?this.dataset.get_metadata("sample_names").length:0);if(ad===0&&ac.data.length!==0){ad=ac.data[0][7].match(/,/g);if(ad===null){ad=1}else{ad=ad.length+1}}var af=new (this.painter)(null,null,null,this.prefs,ag);return af.get_required_height(ad)}},predraw_init:function(){var ac=[g.prototype.predraw_init.call(this)];if(!this.dataset.get_metadata("sample_names")){ac.push(this.dataset.fetch())}return ac},postdraw_actions:function(ag,ah,aj,ad){N.prototype.postdraw_actions.call(this,ag,ah,aj,ad);var af=ab.filter(ag,function(ak){return(ak instanceof M)});var ae=this.dataset.get_metadata("sample_names");if(af.length===0&&this.prefs.show_labels&&ae&&ae.length>1){var ac;if(this.container_div.find(".yaxislabel.variant").length===0){ac=this.prefs.summary_height/2;this.tiles_div.prepend($("<div/>").text("Summary").addClass("yaxislabel variant top").css({"font-size":ac+"px",top:(this.prefs.summary_height-ac)/2+"px"}));if(this.prefs.show_sample_data){var ai=ae.join("<br/>");this.tiles_div.prepend($("<div/>").html(ai).addClass("yaxislabel variant top sample").css({top:this.prefs.summary_height+2,}))}}ac=(this.mode==="Squish"?5:10)+"px";$(this.tiles_div).find(".sample").css({"font-size":ac,"line-height":ac});$(this.tiles_div).find(".yaxislabel").css("color",this.prefs.label_color)}else{this.container_div.find(".yaxislabel.variant").remove()}}});var T=function(ad,ac,ae){d.call(this,ad,ac,ae);this.painter=(ad.reference_track?L.RefBasedReadPainter:L.ReadPainter);this.update_icons()};q(T.prototype,r.prototype,N.prototype,d.prototype,{config_params:ab.union(r.prototype.config_params,[{key:"block_color",label:"Block and sense strand color",type:"color",default_value:l.get_random_color()},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:l.get_random_color()},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_differences",label:"Show differences only",type:"bool",default_value:true},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"height",type:"int",default_value:0,hidden:true}]),config_onchange:function(){this.set_name(this.prefs.name);this.request_draw({clear_tile_cache:true})}});var e={CompositeTrack:f,DrawableGroup:P,DiagonalHeatmapTrack:t,FeatureTrack:d,LineTrack:h,ReadTrack:T,VariantTrack:Z,VcfTrack:Z};var p=function(ae,ad,ac){if("copy" in ae){return ae.copy(ac)}else{var af=ae.obj_type;if(!af){af=ae.track_type}return new e[af](ad,ac,ae)}};return{TracksterView:Y,DrawableGroup:P,LineTrack:h,FeatureTrack:d,DiagonalHeatmapTrack:t,ReadTrack:T,VariantTrack:Z,CompositeTrack:f,object_from_template:p}});>>>>>>> other
+define(["libs/underscore","viz/visualization","viz/trackster/util","viz/trackster/slotting","viz/trackster/painters","viz/trackster/filters","mvc/data","mvc/tools"],function(ab,y,l,u,L,i,X,R){var q=ab.extend;var n={};var k=function(ac,ad){n[ac.attr("id")]=ad};var m=function(ac,ae,ag,af){ag=".group";var ad={};n[ac.attr("id")]=af;ac.bind("drag",{handle:"."+ae,relative:true},function(ao,ap){var an=$(this),at=$(this).parent(),ak=at.children(".track,.group"),am=n[$(this).attr("id")],aj,ai,aq,ah,al;ai=$(this).parents(ag);if(ai.length!==0){aq=ai.position().top;ah=aq+ai.outerHeight();var ar=n[ai.attr("id")];if(ap.offsetY<aq){$(this).insertBefore(ai);ar.remove_drawable(am);ar.container.add_drawable_before(am,ar);return}else{if(ap.offsetY>ah){$(this).insertAfter(ai);ar.remove_drawable(am);ar.container.add_drawable(am);return}}}ai=null;for(al=0;al<ak.length;al++){aj=$(ak.get(al));aq=aj.position().top;ah=aq+aj.outerHeight();if(aj.is(ag)&&this!==aj.get(0)&&ap.offsetY>=aq&&ap.offsetY<=ah){if(ap.offsetY-aq<ah-ap.offsetY){aj.find(".content-div").prepend(this)}else{aj.find(".content-div").append(this)}if(am.container){am.container.remove_drawable(am)}n[aj.attr("id")].add_drawable(am);return}}for(al=0;al<ak.length;al++){aj=$(ak.get(al));if(ap.offsetY<aj.position().top&&!(aj.hasClass("reference-track")||aj.hasClass("intro"))){break}}if(al===ak.length){if(this!==ak.get(al-1)){at.append(this);n[at.attr("id")].move_drawable(am,al)}}else{if(this!==ak.get(al)){$(this).insertBefore(ak.get(al));n[at.attr("id")].move_drawable(am,(ap.deltaY>0?al-1:al))}}}).bind("dragstart",function(){ad["border-top"]=ac.css("border-top");ad["border-bottom"]=ac.css("border-bottom");$(this).css({"border-top":"1px solid blue","border-bottom":"1px solid blue"})}).bind("dragend",function(){$(this).css(ad)})};var F=20,B=100,I=12000,S=400,K=5000,x=100,o="Cannot display dataset due to an error. ",J="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",G="No data for this chrom/contig.",w="Preparing data. This can take a while for a large dataset. If the visualization is saved and closed, preparation will continue in the background.",z="Tool cannot be rerun: ",b="Loading data...",U="Ready for display",Q=10,H=20,C=["Histogram","Line","Filled","Intensity"];function V(ad,ac){if(!ac){ac=0}var ae=Math.pow(10,ac);return Math.round(ad*ae)/ae}var r=function(ad,ac,af){if(!r.id_counter){r.id_counter=0}this.id=r.id_counter++;this.view=ad;this.container=ac;this.drag_handle_class=af.drag_handle_class;this.is_overview=false;this.action_icons={};this.config=new j({params:this.config_params,onchange:this.config_onchange,saved_values:af.prefs});this.prefs=this.config.get("values");if(!this.prefs.name){this.prefs.name=af.name}if(this.config_onchange){this.config.on("change:values",this.config_onchange,this)}this.container_div=this.build_container_div();this.header_div=this.build_header_div();if(this.header_div){this.container_div.append(this.header_div);this.icons_div=$("<div/>").css("float","left").hide().appendTo(this.header_div);this.build_action_icons(this.action_icons_def);this.header_div.append($("<div style='clear: both'/>"));this.header_div.dblclick(function(ag){ag.stopPropagation()});var ae=this;this.container_div.hover(function(){ae.icons_div.show()},function(){ae.icons_div.hide()});$("<div style='clear: both'/>").appendTo(this.container_div)}};r.prototype.action_icons_def=[{name:"toggle_icon",title:"Hide/show content",css_class:"toggle",on_click_fn:function(ac){if(ac.prefs.content_visible){ac.action_icons.toggle_icon.addClass("toggle-expand").removeClass("toggle");ac.hide_contents();ac.prefs.content_visible=false}else{ac.action_icons.toggle_icon.addClass("toggle").removeClass("toggle-expand");ac.prefs.content_visible=true;ac.show_contents()}}},{name:"settings_icon",title:"Edit settings",css_class:"gear",on_click_fn:function(ad){var ac=new a({model:ad.config});ac.render()}},{name:"remove_icon",title:"Remove",css_class:"remove-icon",on_click_fn:function(ac){$(".tooltip").remove();ac.remove()}}];q(r.prototype,{config_params:[{key:"name",label:"Name",type:"text",default_value:""},{key:"content_visible",type:"bool",default_value:true,hidden:true}],config_onchange:function(){this.track.set_name(this.track.config.get("values").name)},init:function(){},changed:function(){this.view.changed()},can_draw:function(){if(this.enabled&&this.prefs.content_visible){return true}return false},request_draw:function(){},_draw:function(ac){},to_dict:function(){},set_name:function(ac){this.old_name=this.prefs.name;this.prefs.name=ac;this.name_div.text(this.prefs.name)},revert_name:function(){if(this.old_name){this.prefs.name=this.old_name;this.name_div.text(this.prefs.name)}},remove:function(){this.changed();this.container.remove_drawable(this);var ac=this.view;this.container_div.hide(0,function(){$(this).remove();ac.update_intro_div()})},build_container_div:function(){},build_header_div:function(){},add_action_icon:function(ad,ai,ah,ag,ac,af){var ae=this;this.action_icons[ad]=$("<a/>").attr("title",ai).addClass("icon-button").addClass(ah).tooltip().click(function(){ag(ae)}).appendTo(this.icons_div);if(af){this.action_icons[ad].hide()}},build_action_icons:function(ac){var ae;for(var ad=0;ad<ac.length;ad++){ae=ac[ad];this.add_action_icon(ae.name,ae.title,ae.css_class,ae.on_click_fn,ae.prepend,ae.hide)}},update_icons:function(){},hide_contents:function(){},show_contents:function(){},get_drawables:function(){}});var A=function(ad,ac,ae){r.call(this,ad,ac,ae);this.obj_type=ae.obj_type;this.drawables=[]};q(A.prototype,r.prototype,{unpack_drawables:function(ae){this.drawables=[];var ad;for(var ac=0;ac<ae.length;ac++){ad=p(ae[ac],this.view,this);this.add_drawable(ad)}},init:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac].init()}},_draw:function(ac){for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad]._draw(ac)}},to_dict:function(){var ad=[];for(var ac=0;ac<this.drawables.length;ac++){ad.push(this.drawables[ac].to_dict())}return{prefs:this.prefs,obj_type:this.obj_type,drawables:ad}},add_drawable:function(ac){this.drawables.push(ac);ac.container=this;this.changed()},add_drawable_before:function(ae,ac){this.changed();var ad=this.drawables.indexOf(ac);if(ad!==-1){this.drawables.splice(ad,0,ae);return true}return false},replace_drawable:function(ae,ac,ad){var af=this.drawables.indexOf(ae);if(af!==-1){this.drawables[af]=ac;if(ad){ae.container_div.replaceWith(ac.container_div)}this.changed()}return af},remove_drawable:function(ad){var ac=this.drawables.indexOf(ad);if(ac!==-1){this.drawables.splice(ac,1);ad.container=null;this.changed();return true}return false},move_drawable:function(ad,ae){var ac=this.drawables.indexOf(ad);if(ac!==-1){this.drawables.splice(ac,1);this.drawables.splice(ae,0,ad);this.changed();return true}return false},get_drawables:function(){return this.drawables},get_tracks:function(af){var ac=this.drawables.slice(0),ad=[],ae;while(ac.length!==0){ae=ac.shift();if(ae instanceof af){ad.push(ae)}else{if(ae.drawables){ac=ac.concat(ae.drawables)}}}return ad}});var P=function(ad,ac,af){q(af,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});A.call(this,ad,ac,af);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);k(this.container_div,this);k(this.content_div,this);m(this.container_div,this.drag_handle_class,".group",this);this.filters_manager=new i.FiltersManager(this);this.header_div.after(this.filters_manager.parent_div);this.saved_filters_managers=[];if("drawables" in af){this.unpack_drawables(af.drawables)}if("filters" in af){var ae=this.filters_manager;this.filters_manager=new i.FiltersManager(this,af.filters);ae.parent_div.replaceWith(this.filters_manager.parent_div);if(af.filters.visible){this.setup_multitrack_filtering()}}};q(P.prototype,r.prototype,A.prototype,{action_icons_def:[r.prototype.action_icons_def[0],r.prototype.action_icons_def[1],{name:"composite_icon",title:"Show composite track",css_class:"layers-stack",on_click_fn:function(ac){$(".tooltip").remove();ac.show_composite_track()}},{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ac){if(ac.filters_manager.visible()){ac.filters_manager.clear_filters();ac._restore_filter_managers()}else{ac.setup_multitrack_filtering();ac.request_draw({clear_tile_cache:true})}ac.filters_manager.toggle()}},r.prototype.action_icons_def[2]],build_container_div:function(){var ac=$("<div/>").addClass("group").attr("id","group_"+this.id);if(this.container){this.container.content_div.append(ac)}return ac},build_header_div:function(){var ac=$("<div/>").addClass("track-header");ac.append($("<div/>").addClass(this.drag_handle_class));this.name_div=$("<div/>").addClass("track-name").text(this.prefs.name).appendTo(ac);return ac},hide_contents:function(){this.tiles_div.hide()},show_contents:function(){this.tiles_div.show();this.request_draw()},update_icons:function(){var ae=this.drawables.length;if(ae===0){this.action_icons.composite_icon.hide();this.action_icons.filters_icon.hide()}else{if(ae===1){if(this.drawables[0] instanceof f){this.action_icons.composite_icon.show()}this.action_icons.filters_icon.hide()}else{var al,ak,ai,ao=true,ag=this.drawables[0].get_type(),ac=0;for(al=0;al<ae;al++){ai=this.drawables[al];if(ai.get_type()!==ag){can_composite=false;break}if(ai instanceof d){ac++}}if(ao||ac===1){this.action_icons.composite_icon.show()}else{this.action_icons.composite_icon.hide();$(".tooltip").remove()}if(ac>1&&ac===this.drawables.length){var ap={},ad;ai=this.drawables[0];for(ak=0;ak<ai.filters_manager.filters.length;ak++){ad=ai.filters_manager.filters[ak];ap[ad.name]=[ad]}for(al=1;al<this.drawables.length;al++){ai=this.drawables[al];for(ak=0;ak<ai.filters_manager.filters.length;ak++){ad=ai.filters_manager.filters[ak];if(ad.name in ap){ap[ad.name].push(ad)}}}this.filters_manager.remove_all();var af,ah,aj,am;for(var an in ap){af=ap[an];if(af.length===ac){ah=new i.NumberFilter({name:af[0].name,index:af[0].index});this.filters_manager.add_filter(ah)}}if(this.filters_manager.filters.length>0){this.action_icons.filters_icon.show()}else{this.action_icons.filters_icon.hide()}}else{this.action_icons.filters_icon.hide()}}}},_restore_filter_managers:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac].filters_manager=this.saved_filters_managers[ac]}this.saved_filters_managers=[]},setup_multitrack_filtering:function(){if(this.filters_manager.filters.length>0){this.saved_filters_managers=[];for(var ac=0;ac<this.drawables.length;ac++){drawable=this.drawables[ac];this.saved_filters_managers.push(drawable.filters_manager);drawable.filters_manager=this.filters_manager}}this.filters_manager.init_filters()},show_composite_track:function(){var ad=new f(this.view,this.view,{name:this.prefs.name,drawables:this.drawables});var ac=this.container.replace_drawable(this,ad,true);ad.request_draw()},add_drawable:function(ac){A.prototype.add_drawable.call(this,ac);this.update_icons()},remove_drawable:function(ac){A.prototype.remove_drawable.call(this,ac);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var ac=q(A.prototype.to_dict.call(this),{filters:this.filters_manager.to_dict()});if(this.filters_manager.visible()){this.setup_multitrack_filtering()}return ac},request_draw:function(ac){ab.each(this.drawables,function(ad){ad.request_draw(ac)})}});var Y=Backbone.View.extend({initialize:function(ac){q(ac,{obj_type:"View"});A.call(this,"View",ac.container,ac);this.chrom=null;this.vis_id=ac.vis_id;this.dbkey=ac.dbkey;this.label_tracks=[];this.tracks_to_be_redrawn=[];this.max_low=0;this.max_high=0;this.zoom_factor=3;this.min_separation=30;this.has_changes=false;this.load_chroms_deferred=null;this.render();this.canvas_manager=new y.CanvasManager(this.container.get(0).ownerDocument);this.reset();this.config=new j({track:this,params:[{key:"a_color",label:"A Color",type:"color",default_value:"#FF0000"},{key:"c_color",label:"C Color",type:"color",default_value:"#00FF00"},{key:"g_color",label:"G Color",type:"color",default_value:"#0000FF"},{key:"t_color",label:"T Color",type:"color",default_value:"#FF00FF"},{key:"n_color",label:"N Color",type:"color",default_value:"#AAAAAA"}],saved_values:ac.prefs,onchange:function(){track.request_redraw({clear_tile_cache:true})}})},render:function(){this.requested_redraw=false;var ae=this.container,ac=this;this.top_container=$("<div/>").addClass("top-container").appendTo(ae);this.browser_content_div=$("<div/>").addClass("content").css("position","relative").appendTo(ae);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(ae);this.top_labeltrack=$("<div/>").addClass("top-labeltrack").appendTo(this.top_container);this.viewport_container=$("<div/>").addClass("viewport-container").attr("id","viewport-container").appendTo(this.browser_content_div);this.content_div=this.viewport_container;k(this.viewport_container,ac);this.intro_div=$("<div/>").addClass("intro").appendTo(this.viewport_container).hide();var af=$("<div/>").text("Add Datasets to Visualization").addClass("action-button").appendTo(this.intro_div).click(function(){y.select_datasets(galaxy_config.root+"visualization/list_current_history_datasets",galaxy_config.root+"api/datasets",{"f-dbkey":ac.dbkey},function(ag){ab.each(ag,function(ah){ac.add_drawable(p(ah,ac,ac))})})});this.nav_labeltrack=$("<div/>").addClass("nav-labeltrack").appendTo(this.bottom_container);this.nav_container=$("<div/>").addClass("trackster-nav-container").prependTo(this.top_container);this.nav=$("<div/>").addClass("trackster-nav").appendTo(this.nav_container);this.overview=$("<div/>").addClass("overview").appendTo(this.bottom_container);this.overview_viewport=$("<div/>").addClass("overview-viewport").appendTo(this.overview);this.overview_close=$("<a/>").attr("title","Close overview").addClass("icon-button overview-close tooltip").hide().appendTo(this.overview_viewport);this.overview_highlight=$("<div/>").addClass("overview-highlight").hide().appendTo(this.overview_viewport);this.overview_box_background=$("<div/>").addClass("overview-boxback").appendTo(this.overview_viewport);this.overview_box=$("<div/>").addClass("overview-box").appendTo(this.overview_viewport);this.default_overview_height=this.overview_box.height();this.nav_controls=$("<div/>").addClass("nav-controls").appendTo(this.nav);this.chrom_select=$("<select/>").attr({name:"chrom"}).css("width","15em").append("<option value=''>Loading</option>").appendTo(this.nav_controls);var ad=function(ag){if(ag.type==="focusout"||(ag.keyCode||ag.which)===13||(ag.keyCode||ag.which)===27){if((ag.keyCode||ag.which)!==27){ac.go_to($(this).val())}$(this).hide();$(this).val("");ac.location_span.show();ac.chrom_select.show()}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",ad).appendTo(this.nav_controls);this.location_span=$("<span/>").addClass("location").attr("original-title","Click to change location").tooltip({placement:"bottom"}).appendTo(this.nav_controls);this.location_span.click(function(){ac.location_span.hide();ac.chrom_select.hide();ac.nav_input.val(ac.chrom+":"+ac.low+"-"+ac.high);ac.nav_input.css("display","inline-block");ac.nav_input.select();ac.nav_input.focus();ac.nav_input.autocomplete({source:function(ai,ag){var aj=[],ah=$.map(ac.get_tracks(d),function(ak){return ak.data_manager.search_features(ai.term).success(function(al){aj=aj.concat(al)})});$.when.apply($,ah).done(function(){ag($.map(aj,function(ak){return{label:ak[0],value:ak[1]}}))})}})});if(this.vis_id!==undefined){this.hidden_input=$("<input/>").attr("type","hidden").val(this.vis_id).appendTo(this.nav_controls)}this.zo_link=$("<a/>").attr("id","zoom-out").attr("title","Zoom out").tooltip({placement:"bottom"}).click(function(){ac.zoom_out()}).appendTo(this.nav_controls);this.zi_link=$("<a/>").attr("id","zoom-in").attr("title","Zoom in").tooltip({placement:"bottom"}).click(function(){ac.zoom_in()}).appendTo(this.nav_controls);this.load_chroms_deferred=this.load_chroms({low:0});this.chrom_select.bind("change",function(){ac.change_chrom(ac.chrom_select.val())});this.browser_content_div.click(function(ag){$(this).find("input").trigger("blur")});this.browser_content_div.bind("dblclick",function(ag){ac.zoom_in(ag.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(ag,ah){this.current_x=ah.offsetX}).bind("drag",function(ag,ai){var aj=ai.offsetX-this.current_x;this.current_x=ai.offsetX;var ah=Math.round(aj/ac.viewport_container.width()*(ac.max_high-ac.max_low));ac.move_delta(-ah)});this.overview_close.click(function(){ac.reset_overview()});this.viewport_container.bind("draginit",function(ag,ah){if(ag.clientX>ac.viewport_container.width()-16){return false}}).bind("dragstart",function(ag,ah){ah.original_low=ac.low;ah.current_height=ag.clientY;ah.current_x=ah.offsetX}).bind("drag",function(ai,ak){var ag=$(this);var al=ak.offsetX-ak.current_x;var ah=ag.scrollTop()-(ai.clientY-ak.current_height);ag.scrollTop(ah);ak.current_height=ai.clientY;ak.current_x=ak.offsetX;var aj=Math.round(al/ac.viewport_container.width()*(ac.high-ac.low));ac.move_delta(aj)}).bind("mousewheel",function(ai,ak,ah,ag){if(ah){ah*=50;var aj=Math.round(-ah/ac.viewport_container.width()*(ac.high-ac.low));ac.move_delta(aj)}});this.top_labeltrack.bind("dragstart",function(ag,ah){return $("<div/>").addClass("zoom-area").css("height",ac.browser_content_div.height()+ac.top_labeltrack.height()+ac.nav_labeltrack.height()+1).appendTo($(this))}).bind("drag",function(ak,al){$(al.proxy).css({left:Math.min(ak.pageX,al.startX)-ac.container.offset().left,width:Math.abs(ak.pageX-al.startX)});var ah=Math.min(ak.pageX,al.startX)-ac.container.offset().left,ag=Math.max(ak.pageX,al.startX)-ac.container.offset().left,aj=(ac.high-ac.low),ai=ac.viewport_container.width();ac.update_location(Math.round(ah/ai*aj)+ac.low,Math.round(ag/ai*aj)+ac.low)}).bind("dragend",function(al,am){var ah=Math.min(al.pageX,am.startX),ag=Math.max(al.pageX,am.startX),aj=(ac.high-ac.low),ai=ac.viewport_container.width(),ak=ac.low;ac.low=Math.round(ah/ai*aj)+ak;ac.high=Math.round(ag/ai*aj)+ak;$(am.proxy).remove();ac.request_redraw()});this.add_label_track(new W(this,{content_div:this.top_labeltrack}));this.add_label_track(new W(this,{content_div:this.nav_labeltrack}));$(window).bind("resize",function(){if(this.resize_timer){clearTimeout(this.resize_timer)}this.resize_timer=setTimeout(function(){ac.resize_window()},500)});$(document).bind("redraw",function(){ac.redraw()});this.reset();$(window).trigger("resize")},get_base_color:function(ac){return this.config.get("values")[ac.toLowerCase()+"_color"]||this.config.get("values").n_color}});q(Y.prototype,A.prototype,{changed:function(){this.has_changes=true},update_intro_div:function(){if(this.drawables.length===0){this.intro_div.show()}else{this.intro_div.hide()}},trigger_navigate:function(ad,af,ac,ag){if(this.timer){clearTimeout(this.timer)}if(ag){var ae=this;this.timer=setTimeout(function(){ae.trigger("navigate",ad+":"+af+"-"+ac)},500)}else{view.trigger("navigate",ad+":"+af+"-"+ac)}},update_location:function(ac,ae){this.location_span.text(commatize(ac)+" - "+commatize(ae));this.nav_input.val(this.chrom+":"+commatize(ac)+"-"+commatize(ae));var ad=view.chrom_select.val();if(ad!==""){this.trigger_navigate(ad,view.low,view.high,true)}},load_chroms:function(ae){ae.num=x;var ac=this,ad=$.Deferred();$.ajax({url:galaxy_config.root+"api/genomes/"+this.dbkey,data:ae,dataType:"json",success:function(ag){if(ag.chrom_info.length===0){return}if(ag.reference){var ah=new D(ac);ac.add_label_track(ah);ac.reference_track=ah}ac.chrom_data=ag.chrom_info;var ak='<option value="">Select Chrom/Contig</option>';for(var aj=0,af=ac.chrom_data.length;aj<af;aj++){var ai=ac.chrom_data[aj].chrom;ak+='<option value="'+ai+'">'+ai+"</option>"}if(ag.prev_chroms){ak+='<option value="previous">Previous '+x+"</option>"}if(ag.next_chroms){ak+='<option value="next">Next '+x+"</option>"}ac.chrom_select.html(ak);ac.chrom_start_index=ag.start_index;ad.resolve(ag.chrom_info)},error:function(){alert("Could not load chroms for this dbkey: "+ac.dbkey)}});return ad},change_chrom:function(ah,ad,aj){var ae=this;if(!ae.chrom_data){ae.load_chroms_deferred.then(function(){ae.change_chrom(ah,ad,aj)});return}if(!ah||ah==="None"){return}if(ah==="previous"){ae.load_chroms({low:this.chrom_start_index-x});return}if(ah==="next"){ae.load_chroms({low:this.chrom_start_index+x});return}var ai=$.grep(ae.chrom_data,function(ak,al){return ak.chrom===ah})[0];if(ai===undefined){ae.load_chroms({chrom:ah},function(){ae.change_chrom(ah,ad,aj)});return}else{if(ah!==ae.chrom){ae.chrom=ah;ae.chrom_select.val(ae.chrom);ae.max_high=ai.len-1;ae.reset();for(var ag=0,ac=ae.drawables.length;ag<ac;ag++){var af=ae.drawables[ag];if(af.init){af.init()}}if(ae.reference_track){ae.reference_track.init()}}if(ad&&aj){ae.low=Math.max(ad,0);ae.high=Math.min(aj,ae.max_high)}else{ae.low=0;ae.high=ae.max_high}ae.reset_overview();ae.request_redraw()}},go_to:function(ag){ag=ag.replace(/,/g,"");ag=ag.replace(/:|\-/g," ");var ad=ag.split(/\s+/),af=ad[0],ae=(ad[1]?parseInt(ad[1],10):null),ac=(ad[2]?parseInt(ad[2],10):null);if(!ac){ae=ae-15;ac=ae+15}this.change_chrom(af,ae,ac)},move_fraction:function(ae){var ac=this;var ad=ac.high-ac.low;this.move_delta(ae*ad)},move_delta:function(af){var ac=this;var ae=ac.high-ac.low;if(ac.low-af<ac.max_low){ac.low=ac.max_low;ac.high=ac.max_low+ae}else{if(ac.high-af>ac.max_high){ac.high=ac.max_high;ac.low=ac.max_high-ae}else{ac.high-=af;ac.low-=af}}ac.request_redraw({data_fetch:false});if(this.redraw_on_move_fn){clearTimeout(this.redraw_on_move_fn)}this.redraw_on_move_fn=setTimeout(function(){ac.request_redraw()},200);var ad=ac.chrom_select.val();this.trigger_navigate(ad,ac.low,ac.high,true)},add_drawable:function(ac){A.prototype.add_drawable.call(this,ac);ac.init();this.changed();this.update_intro_div()},add_label_track:function(ac){ac.view=this;ac.init();this.label_tracks.push(ac)},remove_drawable:function(ae,ad){A.prototype.remove_drawable.call(this,ae);if(ad){var ac=this;ae.container_div.hide(0,function(){$(this).remove();ac.update_intro_div()})}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},request_redraw:function(ad,ae){var ac=this,af=(ae?[ae]:ac.drawables);ab.each(af,function(ag){var ah=ab.find(ac.tracks_to_be_redrawn,function(ai){return ai[0]===ag});if(ah){ah[1]=ad}else{ac.tracks_to_be_redrawn.push([ag,ad])}});if(!this.requested_redraw){requestAnimationFrame(function(){ac._redraw()});this.requested_redraw=true}},_redraw:function(){this.requested_redraw=false;var ac=this.low,ag=this.high;if(ac<this.max_low){ac=this.max_low}if(ag>this.max_high){ag=this.max_high}var ad=this.high-this.low;if(this.high!==0&&ad<this.min_separation){ag=ac+this.min_separation}this.low=Math.floor(ac);this.high=Math.ceil(ag);this.update_location(this.low,this.high);this.resolution_px_b=this.viewport_container.width()/(this.high-this.low);var af=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ah=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ae=13;this.overview_box.css({left:af,width:Math.max(ae,ah)}).show();if(ah<ae){this.overview_box.css("left",af-(ae-ah)/2)}if(this.overview_highlight){this.overview_highlight.css({left:af,width:ah})}ab.each(this.tracks_to_be_redrawn,function(ak){var ai=ak[0],aj=ak[1];if(ai){ai._draw(aj)}});this.tracks_to_be_redrawn=[];ab.each(this.label_tracks,function(ai){ai._draw()})},zoom_in:function(ad,ae){if(this.max_high===0||this.high-this.low<=this.min_separation){return}var af=this.high-this.low,ag=af/2+this.low,ac=(af/this.zoom_factor)/2;if(ad){ag=ad/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(ag-ac);this.high=Math.round(ag+ac);this.changed();this.request_redraw()},zoom_out:function(){if(this.max_high===0){return}var ad=this.high-this.low,ae=ad/2+this.low,ac=(ad*this.zoom_factor)/2;this.low=Math.round(ae-ac);this.high=Math.round(ae+ac);this.changed();this.request_redraw()},resize_window:function(){this.viewport_container.height(this.container.height()-this.top_container.height()-this.bottom_container.height());this.request_redraw()},set_overview:function(ae){if(this.overview_drawable){if(this.overview_drawable.dataset.id===ae.dataset.id){return}this.overview_viewport.find(".track").remove()}var ad=ae.copy({content_div:this.overview_viewport}),ac=this;ad.header_div.hide();ad.is_overview=true;ac.overview_drawable=ad;this.overview_drawable.postdraw_actions=function(){ac.overview_highlight.show().height(ac.overview_drawable.content_div.height());ac.overview_viewport.height(ac.overview_drawable.content_div.height()+ac.overview_box.outerHeight());ac.overview_close.show();ac.resize_window()};ac.overview_drawable.request_draw();this.changed()},reset_overview:function(){$(".tooltip").remove();this.overview_viewport.find(".track-tile").remove();this.overview_viewport.height(this.default_overview_height);this.overview_box.height(this.default_overview_height);this.overview_close.hide();this.overview_highlight.hide();view.resize_window();view.overview_drawable=null}});var s=R.Tool.extend({defaults:{track:null},initialize:function(ac){var ad=true;if(ac.tool_state!==undefined&&ac.tool_state.hidden!==undefined){ad=ac.tool_state.hidden}this.set("hidden",ad);this.remove_inputs(["data","hidden_data","conditional"])},state_dict:function(ac){return ab.extend(this.get_inputs_dict(),{hidden:!this.is_visible()})}});var v=Backbone.View.extend({events:{"change input":"update_value"},render:function(){var ae=this.$el.addClass("param-row"),af=this.model;var ac=$("<div>").addClass("param-label").text(af.get("label")).appendTo(ae);var ad=$("<div/>").addClass("param-input").html(af.get("html")).appendTo(ae);ad.find(":input").val(af.get("value"));$("<div style='clear: both;'/>").appendTo(ae)},update_value:function(ac){this.model.set_value($(ac.target).val())}});var aa=Backbone.View.extend({initialize:function(ac){this.model.on("change:hidden",this.set_visible,this)},render:function(){var ad=this;tool=this.model,parent_div=this.$el.addClass("dynamic-tool").hide();parent_div.bind("drag",function(ah){ah.stopPropagation()}).click(function(ah){ah.stopPropagation()}).bind("dblclick",function(ah){ah.stopPropagation()}).keydown(function(ah){ah.stopPropagation()});var ae=$("<div class='tool-name'>").appendTo(parent_div).text(tool.get("name"));tool.get("inputs").each(function(ai){var ah=new v({model:ai});ah.render();parent_div.append(ah.$el)});parent_div.find("input").click(function(){$(this).select()});var af=$("<div>").addClass("param-row").appendTo(parent_div);var ag=$("<input type='submit'>").attr("value","Run on complete dataset").appendTo(af);var ac=$("<input type='submit'>").attr("value","Run on visible region").css("margin-left","3em").appendTo(af);ac.click(function(){ad.run_on_region()});ag.click(function(){ad.run_on_dataset()});if(tool.is_visible()){this.$el.show()}},set_visible:function(){if(this.model.is_visible()){this.$el.show()}else{this.$el.hide()}},update_params:function(){for(var ac=0;ac<this.params.length;ac++){this.params[ac].update_value()}},run_on_dataset:function(){var ac=this.model;this.run({target_dataset_id:this.model.get("track").dataset.id,action:"rerun",tool_id:ac.id},null,function(ad){Galaxy.modal.show({title:ac.get("name")+" is Running",body:ac.get("name")+" is running on the complete dataset. Tool outputs are in dataset's history.",buttons:{Close:function(){Galaxy.modal.hide()}}})})},run_on_region:function(){var ad=this.model.get("track"),ag=this.model,ai=new y.GenomeRegion({chrom:ad.view.chrom,start:ad.view.low,end:ad.view.high}),aj={target_dataset_id:ad.dataset.id,action:"rerun",tool_id:ag.id,regions:[ai.toJSON()]},ah=ad,al=aj.tool_id+ah.tool_region_and_parameters_str(ai),ac;if(ah.container===view){var ak=new P(view,view,{name:ad.prefs.name});var af=ah.container.replace_drawable(ah,ak,false);ak.container_div.insertBefore(ah.view.content_div.children()[af]);ak.add_drawable(ah);ah.container_div.appendTo(ak.content_div);ac=ak}else{ac=ah.container}var ae=new ah.constructor(view,ac,{name:al,hda_ldda:"hda"});ae.init_for_tool_data();ae.change_mode(ah.mode);ae.set_filters_manager(ah.filters_manager.copy(ae));ae.update_icons();ac.add_drawable(ae);ae.tiles_div.text("Starting job.");this.run(aj,ae,function(am){ae.set_dataset(new X.Dataset(am));ae.tiles_div.text("Running job.");ae.init()})},run:function(ac,ae,af){ac.inputs=this.model.get_inputs_dict();var ad=new l.ServerStateDeferred({ajax_settings:{url:galaxy_config.root+"api/tools",data:JSON.stringify(ac),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(ag){return ag!=="pending"}});$.when(ad.go()).then(function(ag){if(ag==="no converter"){ae.container_div.addClass("error");ae.content_div.text(J)}else{if(ag.error){ae.container_div.addClass("error");ae.content_div.text(z+ag.message)}else{af(ag)}}})}});var E=function(ac,ad){L.Scaler.call(this,ad);this.filter=ac};E.prototype.gen_val=function(ac){if(this.filter.high===Number.MAX_VALUE||this.filter.low===-Number.MAX_VALUE||this.filter.low===this.filter.high){return this.default_val}return((parseFloat(ac[this.filter.index])-this.filter.low)/(this.filter.high-this.filter.low))};var j=Backbone.Model.extend({initialize:function(ad){var ac={};ab.each(ad.params,function(ae){ac[ae.key]=ae.default_value});if(ad.saved_values){ab.each(this.get("params"),function(ae){if(ae.key in ad.saved_values){ac[ae.key]=ad.saved_values[ae.key]}})}this.set("values",ac)},set_param_default_value:function(ad,ac){var ae=ab.find(this.get("params"),function(af){return af.key===ad});if(ae){ae.default_value=ac}},set_param_value:function(ac,ad){var ae=ab.find(this.get("params"),function(af){return af.key===ac});if(ae){if(typeof ad==="string"||ad instanceof String){if(ad.trim()===""){ad=ae.default_value}else{if(ae.type==="float"){ad=parseFloat(ad)}else{if(ae.type==="int"){ad=parseInt(ad,10)}}}}}if(this.get("values")[ac]!==ad){this.get("values")[ac]=ad;this.trigger("change:values");return true}else{return false}}});var a=Backbone.View.extend({render:function(){var aj=this.model;var ac=$("<div/>").keydown(function(ak){ak.stopPropagation()});var ai;function ah(ao,ak){for(var at=0;at<ao.length;at++){ai=ao[at];if(ai.hidden){continue}var am="param_"+at;var ax=aj.get("values")[ai.key];var az=$("<div class='form-row' />").appendTo(ak);az.append($("<label />").attr("for",am).text(ai.label+":"));if(ai.type==="bool"){az.append($('<input type="checkbox" />').attr("id",am).attr("name",am).attr("checked",ax))}else{if(ai.type==="text"){az.append($('<input type="text"/>').attr("id",am).val(ax).click(function(){$(this).select()}))}else{if(ai.type==="select"){var av=$("<select />").attr("id",am);for(var aq=0;aq<ai.options.length;aq++){$("<option/>").text(ai.options[aq].label).attr("value",ai.options[aq].value).appendTo(av)}av.val(ax);az.append(av)}else{if(ai.type==="color"){var ay=$("<div/>").appendTo(az),au=$("<input />").attr("id",am).attr("name",am).val(ax).css("float","left").appendTo(ay).click(function(aB){$(".tooltip").removeClass("in");var aA=$(this).siblings(".tooltip").addClass("in");aA.css({left:$(this).position().left+$(this).width()+5,top:$(this).position().top+Galaxy.modal.scrollTop()-($(aA).height()/2)+($(this).height()/2)}).show();aA.click(function(aC){aC.stopPropagation()});$(document).bind("click.color-picker",function(){aA.hide();$(document).unbind("click.color-picker")});aB.stopPropagation()}),ar=$("<a href='javascript:void(0)'/>").addClass("icon-button arrow-circle").appendTo(ay).attr("title","Set new random color").tooltip(),aw=$("<div class='tooltip right' style='position: absolute;' />").appendTo(ay).hide(),an=$("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(aw),al=$("<div class='tooltip-arrow'></div>").appendTo(aw),ap=$.farbtastic(an,{width:100,height:100,callback:au,color:ax});ay.append($("<div/>").css("clear","both"));(function(aA){ar.click(function(){aA.setColor(l.get_random_color())})})(ap)}else{az.append($("<input />").attr("id",am).attr("name",am).val(ax))}}}}if(ai.help){az.append($("<div class='help'/>").text(ai.help))}}}ah(aj.get("params"),ac);var ad=this,ag=function(){Galaxy.modal.hide();$(window).unbind("keypress.check_enter_esc")},ae=function(){ad.update_from_form($(Galaxy.modal.el));Galaxy.modal.hide();$(window).unbind("keypress.check_enter_esc")},af=function(ak){if((ak.keyCode||ak.which)===27){ag()}else{if((ak.keyCode||ak.which)===13){ae()}}};$(window).bind("keypress.check_enter_esc",af);Galaxy.modal.show({title:"Configure",body:ac,buttons:{Cancel:ag,Ok:ae}})},update_from_form:function(ac){var ad=this.model;var ae=false;ab.each(ad.get("params"),function(ah,af){if(!ah.hidden){var ai="param_"+af;var ag=ac.find("#"+ai).val();if(ah.type==="bool"){ag=ac.find("#"+ai).is(":checked")}ae=ad.set_param_value(ah.key,ag)||ae}})}});var c=function(ac,af,ag,ad,ae){this.track=ac;this.region=af;this.low=af.get("start");this.high=af.get("end");this.w_scale=ag;this.canvas=ad;this.html_elt=$("<div class='track-tile'/>").append(ad);this.data=ae;this.stale=false};c.prototype.predisplay_actions=function(){};var M=function(ac,af,ag,ad,ae){c.call(this,ac,af,ag,ad,ae)};M.prototype.predisplay_actions=function(){};var O=function(af,am,ao,ae,ah,ai,ap,ad,al){c.call(this,af,am,ao,ae,ah);this.mode=ai;this.all_slotted=ad;this.feature_mapper=al;this.has_icons=false;if(ap){this.has_icons=true;var aj=this;ae=this.html_elt.children()[0],message_div=$("<div/>").addClass("tile-message").css({height:F,width:ae.width}).prependTo(this.html_elt);var ak=new y.GenomeRegion({chrom:af.view.chrom,start:this.low,end:this.high}),an=ah.length,ag=$("<a/>").addClass("icon more-down").attr("title","For speed, only the first "+an+" features in this region were obtained from server. Click to get more data including depth").tooltip().appendTo(message_div),ac=$("<a/>").addClass("icon more-across").attr("title","For speed, only the first "+an+" features in this region were obtained from server. Click to get more data excluding depth").tooltip().appendTo(message_div);ag.click(function(){aj.stale=true;af.data_manager.get_more_data(ak,af.mode,1/aj.w_scale,{},af.data_manager.DEEP_DATA_REQ);$(".tooltip").hide();af.request_draw()}).dblclick(function(aq){aq.stopPropagation()});ac.click(function(){aj.stale=true;af.data_manager.get_more_data(ak,af.mode,1/aj.w_scale,{},af.data_manager.BROAD_DATA_REQ);$(".tooltip").hide();af.request_draw()}).dblclick(function(aq){aq.stopPropagation()})}};q(O.prototype,c.prototype);O.prototype.predisplay_actions=function(){var ad=this,ac={};if(ad.mode!=="Pack"){return}$(this.html_elt).hover(function(){this.hovered=true;$(this).mousemove()},function(){this.hovered=false;$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()}).mousemove(function(ao){if(!this.hovered){return}var aj=$(this).offset(),an=ao.pageX-aj.left,am=ao.pageY-aj.top,at=ad.feature_mapper.get_feature_data(an,am),ak=(at?at[0]:null);$(this).parents(".track-content").children(".overlay").children(".feature-popup").each(function(){if(!ak||$(this).attr("id")!==ak.toString()){$(this).remove()}});if(at){var af=ac[ak];if(!af){var ap={name:at[3],start:at[1],end:at[2],strand:at[4]},ai=ad.track.filters_manager.filters,ah;for(var al=0;al<ai.length;al++){ah=ai[al];ap[ah.name]=at[ah.index]}af=$("<div/>").attr("id",ak).addClass("feature-popup");var au=$("<table/>"),ar,aq,av;for(ar in ap){aq=ap[ar];av=$("<tr/>").appendTo(au);$("<th/>").appendTo(av).text(ar);$("<td/>").attr("align","left").appendTo(av).text(typeof(aq)==="number"?V(aq,2):aq)}af.append($("<div class='feature-popup-inner'>").append(au));ac[ak]=af}af.appendTo($(this).parents(".track-content").children(".overlay"));var ag=an+parseInt(ad.html_elt.css("left"),10)-af.width()/2,ae=am+parseInt(ad.html_elt.css("top"),10)+7;af.css("left",ag+"px").css("top",ae+"px")}else{if(!ao.isPropagationStopped()){ao.stopPropagation();$(this).siblings().each(function(){$(this).trigger(ao)})}}}).mouseleave(function(){$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()})};var g=function(ad,ac,ae){q(ae,{drag_handle_class:"draghandle"});r.call(this,ad,ac,ae);this.dataset=null;if(ae.dataset){this.dataset=(ae.dataset instanceof Backbone.Model?ae.dataset:X.Dataset.findOrCreate(ae.dataset))}this.dataset_check_type="converted_datasets_state";this.data_url_extra_params={};this.data_query_wait=("data_query_wait" in ae?ae.data_query_wait:K);this.data_manager=("data_manager" in ae?ae.data_manager:new y.GenomeDataManager({dataset:this.dataset,genome:new y.Genome({key:ad.dbkey,chroms_info:{chrom_info:ad.chrom_data}}),data_mode_compatible:this.data_and_mode_compatible,can_subset:this.can_subset}));this.min_height_px=16;this.max_height_px=800;this.visible_height_px=this.prefs.height;this.content_div=$("<div class='track-content'>").appendTo(this.container_div);if(this.container){this.container.content_div.append(this.container_div);if(!("resize" in ae)||ae.resize){this.add_resize_handle()}}};q(g.prototype,r.prototype,{action_icons_def:[{name:"mode_icon",title:"Set display mode",css_class:"chevron-expand",on_click_fn:function(){}},r.prototype.action_icons_def[0],{name:"overview_icon",title:"Set as overview",css_class:"application-dock-270",on_click_fn:function(ac){ac.view.set_overview(ac)}},r.prototype.action_icons_def[1],{name:"filters_icon",title:"Filters",css_class:"ui-slider-050",on_click_fn:function(ac){if(ac.filters_manager.visible()){ac.filters_manager.clear_filters()}else{ac.filters_manager.init_filters()}ac.filters_manager.toggle()}},{name:"tools_icon",title:"Tool",css_class:"hammer",on_click_fn:function(ac){ac.tool.toggle();if(ac.tool.is_visible()){ac.set_name(ac.name+ac.tool_region_and_parameters_str())}else{ac.revert_name()}$(".tooltip").remove()}},{name:"param_space_viz_icon",title:"Tool parameter space visualization",css_class:"arrow-split",on_click_fn:function(ac){var af='<strong>Tool</strong>: <%= track.tool.name %><br/><strong>Dataset</strong>: <%= track.name %><br/><strong>Region(s)</strong>: <select name="regions"><option value="cur">current viewing area</option><option value="bookmarks">bookmarks</option><option value="both">current viewing area and bookmarks</option></select>',ae=ab.template(af,{track:ac});var ah=function(){Galaxy.modal.hide();$(window).unbind("keypress.check_enter_esc")},ad=function(){var aj=$('select[name="regions"] option:selected').val(),al,ai=new y.GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),ak=ab.map($(".bookmark"),function(am){return new y.GenomeRegion({from_str:$(am).children(".position").text()})});if(aj==="cur"){al=[ai]}else{if(aj==="bookmarks"){al=ak}else{al=[ai].concat(ak)}}Galaxy.modal.hide();window.location.href=galaxy_config.root+"visualization/sweepster?"+$.param({dataset_id:ac.dataset.id,hda_ldda:ac.dataset.get("hda_ldda"),regions:JSON.stringify(new Backbone.Collection(al).toJSON())})},ag=function(ai){if((ai.keyCode||ai.which)===27){ah()}else{if((ai.keyCode||ai.which)===13){ad()}}};Galaxy.modal.show({title:"Visualize tool parameter space and output from different parameter settings?",body:ae,buttons:{No:ah,Yes:ad}})}},r.prototype.action_icons_def[2]],can_draw:function(){return this.dataset&&r.prototype.can_draw.call(this)},build_container_div:function(){return $("<div/>").addClass("track").attr("id","track_"+this.id).css("position","relative")},build_header_div:function(){var ac=$("<div class='track-header'/>");if(this.view.editor){this.drag_div=$("<div/>").addClass(this.drag_handle_class).appendTo(ac)}this.name_div=$("<div/>").addClass("track-name").appendTo(ac).text(this.prefs.name).attr("id",this.prefs.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase());return ac},set_dataset:function(ac){this.dataset=ac;this.data_manager.set("dataset",ac)},on_resize:function(){this.request_draw({clear_tile_cache:true})},add_resize_handle:function(){var ac=this;var af=false;var ae=false;var ad=$("<div class='track-resize'>");$(ac.container_div).hover(function(){if(ac.prefs.content_visible){af=true;ad.show()}},function(){af=false;if(!ae){ad.hide()}});ad.hide().bind("dragstart",function(ag,ah){ae=true;ah.original_height=$(ac.content_div).height()}).bind("drag",function(ah,ai){var ag=Math.min(Math.max(ai.original_height+ai.deltaY,ac.min_height_px),ac.max_height_px);$(ac.tiles_div).css("height",ag);ac.visible_height_px=(ac.max_height_px===ag?0:ag);ac.on_resize()}).bind("dragend",function(ag,ah){ac.tile_cache.clear();ae=false;if(!af){ad.hide()}ac.config.get("values").height=ac.visible_height_px;ac.changed()}).appendTo(ac.container_div)},set_display_modes:function(af,ai){this.display_modes=af;this.mode=(ai?ai:(this.config&&this.config.get("values").mode?this.config.get("values").mode:this.display_modes[0]));this.action_icons.mode_icon.attr("title","Set display mode (now: "+this.mode+")");var ad=this,ag={};for(var ae=0,ac=ad.display_modes.length;ae<ac;ae++){var ah=ad.display_modes[ae];ag[ah]=function(aj){return function(){ad.change_mode(aj);ad.icons_div.show();ad.container_div.mouseleave(function(){ad.icons_div.hide()})}}(ah)}make_popupmenu(this.action_icons.mode_icon,ag)},build_action_icons:function(){r.prototype.build_action_icons.call(this,this.action_icons_def);if(this.display_modes!==undefined){this.set_display_modes(this.display_modes)}},hide_contents:function(){this.tiles_div.hide();this.container_div.find(".yaxislabel, .track-resize").hide()},show_contents:function(){this.tiles_div.show();this.container_div.find(".yaxislabel, .track-resize").show();this.request_draw()},get_type:function(){if(this instanceof W){return"LabelTrack"}else{if(this instanceof D){return"ReferenceTrack"}else{if(this instanceof h){return"LineTrack"}else{if(this instanceof T){return"ReadTrack"}else{if(this instanceof Z){return"VariantTrack"}else{if(this instanceof f){return"CompositeTrack"}else{if(this instanceof d){return"FeatureTrack"}}}}}}}return""},init:function(ae){var ad=this;ad.enabled=false;ad.tile_cache.clear();ad.data_manager.clear();ad.tiles_div.css("height","auto");ad.tiles_div.text("").children().remove();ad.container_div.removeClass("nodata error pending");if(!ad.dataset.id){return}var ac=$.Deferred(),af={hda_ldda:ad.dataset.get("hda_ldda"),data_type:this.dataset_check_type,chrom:ad.view.chrom,retry:ae};$.getJSON(this.dataset.url(),af,function(ag){if(!ag||ag==="error"||ag.kind==="error"){ad.container_div.addClass("error");ad.content_div.text(o);if(ag.message){ad.content_div.append($("<a href='javascript:void(0);'></a>").text("View error").click(function(){Galaxy.modal.show({title:"Trackster Error",body:"<pre>"+ag.message+"</pre>",buttons:{Close:function(){Galaxy.modal.hide()}}})}));ad.content_div.append($("<span/>").text(" "));ad.content_div.append($("<a href='javascript:void(0);'></a>").text("Try again").click(function(){ad.init(true)}))}}else{if(ag==="no converter"){ad.container_div.addClass("error");ad.tiles_div.text(J)}else{if(ag==="no data"||(ag.data!==undefined&&(ag.data===null||ag.data.length===0))){ad.container_div.addClass("nodata");ad.tiles_div.text(G)}else{if(ag==="pending"){ad.container_div.addClass("pending");ad.tiles_div.html(w);setTimeout(function(){ad.init()},ad.data_query_wait)}else{if(ag==="data"||ag.status==="data"){if(ag.valid_chroms){ad.valid_chroms=ag.valid_chroms;ad.update_icons()}ad.tiles_div.text(U);if(ad.view.chrom){ad.tiles_div.text("");ad.tiles_div.css("height",ad.visible_height_px+"px");ad.enabled=true;$.when.apply($,ad.predraw_init()).done(function(){ac.resolve();ad.container_div.removeClass("nodata error pending");ad.request_draw()})}else{ac.resolve()}}}}}}});this.update_icons();return ac},predraw_init:function(){var ac=this;return $.getJSON(ac.dataset.url(),{data_type:"data",stats:true,chrom:ac.view.chrom,low:0,high:ac.view.max_high,hda_ldda:ac.dataset.get("hda_ldda")},function(ad){var af=ad.data;if(af&&af.min&&af.max){var ae=af.min,ag=af.max;ae=Math.floor(Math.min(0,Math.max(ae,af.mean-2*af.sd)));ag=Math.ceil(Math.max(0,Math.min(ag,af.mean+2*af.sd)));ac.config.set_param_default_value("min_value",ae);ac.config.set_param_default_value("max_value",ag);ac.prefs.min_value=ae;ac.prefs.max_value=ag}})},get_drawables:function(){return this}});var N=function(ae,ad,ag){g.call(this,ae,ad,ag);var ac=this;m(ac.container_div,ac.drag_handle_class,".group",ac);this.filters_manager=new i.FiltersManager(this,("filters" in ag?ag.filters:null));this.data_manager.set("filters_manager",this.filters_manager);this.filters_available=false;this.tool=(ag.tool?new s(ab.extend(ag.tool,{track:this,tool_state:ag.tool_state})):null);this.tile_cache=new y.Cache(Q);this.left_offset=0;if(this.header_div){this.set_filters_manager(this.filters_manager);if(this.tool){var af=new aa({model:this.tool});af.render();this.dynamic_tool_div=af.$el;this.header_div.after(this.dynamic_tool_div)}}this.tiles_div=$("<div/>").addClass("tiles").appendTo(this.content_div);if(!this.prefs.content_visible){this.tiles_div.hide()}this.overlay_div=$("<div/>").addClass("overlay").appendTo(this.content_div);if(ag.mode){this.change_mode(ag.mode)}};q(N.prototype,r.prototype,g.prototype,{action_icons_def:g.prototype.action_icons_def.concat([{name:"show_more_rows_icon",title:"To minimize track height, not all feature rows are displayed. Click to display more rows.",css_class:"exclamation",on_click_fn:function(ac){$(".tooltip").remove();ac.slotters[ac.view.resolution_px_b].max_rows*=2;ac.request_draw({clear_tile_cache:true})},hide:true}]),copy:function(ac){var ad=this.to_dict();q(ad,{data_manager:this.data_manager});var ae=new this.constructor(this.view,ac,ad);ae.change_mode(this.mode);ae.enabled=this.enabled;return ae},set_filters_manager:function(ac){this.filters_manager=ac;this.header_div.after(this.filters_manager.parent_div)},to_dict:function(){return{track_type:this.get_type(),dataset:{id:this.dataset.id,hda_ldda:this.dataset.get("hda_ldda")},prefs:this.prefs,mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},set_min_max:function(){var ac=this;return $.getJSON(ac.dataset.url(),{data_type:"data",stats:true,chrom:ac.view.chrom,low:0,high:ac.view.max_high,hda_ldda:ac.dataset.get("hda_ldda")},function(ad){var af=ad.data;if(isNaN(parseFloat(ac.prefs.min_value))||isNaN(parseFloat(ac.prefs.max_value))){var ae=af.min,ag=af.max;ae=Math.floor(Math.min(0,Math.max(ae,af.mean-2*af.sd)));ag=Math.ceil(Math.max(0,Math.min(ag,af.mean+2*af.sd)));ac.prefs.min_value=ae;ac.prefs.max_value=ag}})},change_mode:function(ad){var ac=this;ac.mode=ad;ac.config.get("values").mode=ad;if(ad==="Auto"){this.data_manager.clear()}ac.request_draw({clear_tile_cache:true});this.action_icons.mode_icon.attr("title","Set display mode (now: "+ac.mode+")");return ac},update_icons:function(){var ac=this;if(ac.filters_available){ac.action_icons.filters_icon.show()}else{ac.action_icons.filters_icon.hide()}if(ac.tool){ac.action_icons.tools_icon.show();ac.action_icons.param_space_viz_icon.show()}else{ac.action_icons.tools_icon.hide();ac.action_icons.param_space_viz_icon.hide()}},_gen_tile_cache_key:function(ad,ac){return ad+"_"+ac},request_draw:function(ac){if(ac&&ac.clear_tile_cache){this.tile_cache.clear()}this.view.request_redraw(ac,this)},before_draw:function(){this.max_height_px=0},_draw:function(aq){if(!this.can_draw()){return}var an=aq&&aq.clear_after,al=this.view.low,ag=this.view.high,aj=ag-al,ad=this.view.container.width(),ap=this.view.resolution_px_b,af=1/ap;if(this.is_overview){al=this.view.max_low;ag=this.view.max_high;ap=ad/(view.max_high-view.max_low);af=1/ap}this.before_draw();this.tiles_div.children().addClass("remove");var ac=Math.floor(al/(af*S)),ak,am,ah,ai=[],ao=[];while((ac*S*af)<ag){ak=Math.floor(ac*S*af);am=new y.GenomeRegion({chrom:this.view.chrom,start:ak,end:Math.min(ak+Math.ceil(S*af),this.view.max_high)});ah=this.draw_helper(am,ap,aq);ai.push(ah);$.when(ah).then(function(ar){ao.push(ar)});ac+=1}if(!an){this.tiles_div.children(".remove").removeClass("remove").remove()}var ae=this;$.when.apply($,ai).then(function(){ae.tiles_div.children(".remove").remove();ao=ab.filter(ao,function(ar){return ar!==null});if(ao.length!==0){ae.postdraw_actions(ao,ad,ap,an)}})},_add_yaxis_label:function(af,ah){var ad=this,ag=(af==="max"?"top":"bottom"),ai=(af==="max"?"max":"min"),ac=(af==="max"?"max_value":"min_value"),ae=this.container_div.find(".yaxislabel."+ag);ah=ah||function(){ad.request_draw({clear_tile_cache:true})};if(ae.length!==0){ae.text(ad.prefs[ac])}else{ae=$("<div/>").text(ad.prefs[ac]).make_text_editable({num_cols:12,on_finish:function(aj){$(".tooltip").remove();ad.config.set_param_value(ac,aj);ah()},help_text:"Set "+ai+" value"}).addClass("yaxislabel "+ag).css("color",this.prefs.label_color);this.container_div.prepend(ae)}},postdraw_actions:function(af,ag,ai,ac){var ae=ab.filter(af,function(aj){return(aj instanceof M)});if(ae.length>0){this.max_height_px=0;var ad=this;ab.each(af,function(aj){if(!(aj instanceof M)){aj.html_elt.remove();ad.draw_helper(aj.region,ai,{force:true,mode:"Coverage"})}});ad._add_yaxis_label("max")}else{this.container_div.find(".yaxislabel").remove();var ah=ab.find(af,function(aj){return aj.has_icons});if(ah){ab.each(af,function(aj){if(!aj.has_icons){aj.html_elt.css("padding-top",F)}})}}},get_mode:function(ac){return this.mode},update_auto_mode:function(ac){},_get_drawables:function(){return[this]},draw_helper:function(al,an,ao){if(!ao){ao={}}var ad=ao.force,ai=ao.mode||this.mode,af=1/an,ae=this,ag=this._get_drawables(),am=this._gen_tile_cache_key(an,al),ah=function(ap){return(ap&&"track" in ap)};var aj=(ad?undefined:ae.tile_cache.get_elt(am));if(aj){if(ah(aj)){ae.show_tile(aj,an)}return aj}if(ao.data_fetch===false){return null}var ak=function(){var ap=(ab.find(C,function(ar){return ar===ai})?"Coverage":ai);var aq=ab.map(ag,function(ar){return ar.data_manager.get_data(al,ap,af,ae.data_url_extra_params)});if(view.reference_track){aq.push(view.reference_track.data_manager.get_data(al,ai,af,view.reference_track.data_url_extra_params))}return aq};var ac=$.Deferred();ae.tile_cache.set_elt(am,ac);$.when.apply($,ak()).then(function(){var ap=ak(),av=ap,aB;if(view.reference_track){aB=view.reference_track.data_manager.subset_entry(ap.pop(),al)}var aw=[],at=[];ab.each(ag,function(aG,aD){var aF=aG.mode,aE=av[aD];if(aF==="Auto"){aF=aG.get_mode(aE);aG.update_auto_mode(aF)}aw.push(aF);at.push(aG.get_canvas_height(aE,aF,an,aq))});var au=ae.view.canvas_manager.new_canvas(),ax=al.get("start"),aC=al.get("end"),ar=0,aq=Math.ceil((aC-ax)*an)+ae.left_offset,az=ab.max(at),ay;au.width=aq;au.height=(ao.height||az);var aA=au.getContext("2d");aA.translate(ae.left_offset,0);if(ag.length>1){aA.globalAlpha=0.5;aA.globalCompositeOperation="source-over"}ab.each(ag,function(aE,aD){ay=aE.draw_tile(av[aD],aA,aw[aD],al,an,aB)});if(ay!==undefined){ae.tile_cache.set_elt(am,ay);ae.show_tile(ay,an)}ac.resolve(ay)});return ac},get_canvas_height:function(ac,ae,af,ad){return this.visible_height_px},_draw_line_track_tile:function(ac,ae,ah,ag,ai){var af=ae.canvas,ad=new L.LinePainter(ac.data,ag.get("start"),ag.get("end"),this.prefs,ah);ad.draw(ae,af.width,af.height,ai);return new M(this,ag,ai,af,ac.data)},draw_tile:function(ac,ad,ag,af,ah,ae){},show_tile:function(ae,ah){var ad=this,ac=ae.html_elt;ae.predisplay_actions();var ag=(ae.low-(this.is_overview?this.view.max_low:this.view.low))*ah;if(this.left_offset){ag-=this.left_offset}ac.css("left",ag);if(ac.hasClass("remove")){ac.removeClass("remove")}else{this.tiles_div.append(ac)}ac.css("height","auto");this.max_height_px=Math.max(this.max_height_px,ac.height()-2);ac.parent().children().css("height",this.max_height_px+"px");var af=this.max_height_px;if(this.visible_height_px!==0){af=Math.min(this.max_height_px,this.visible_height_px)}this.tiles_div.css("height",af+"px")},tool_region_and_parameters_str:function(af){var ac=this,ae=(af!==undefined?af.toString():"all"),ad=ab.values(ac.tool.get_inputs_dict()).join(", ");return" - region=["+ae+"], parameters=["+ad+"]"},data_and_mode_compatible:function(ac,ad){if(ad==="Auto"){return true}else{if(ad==="Coverage"){return ac.dataset_type==="bigwig"}else{if(ac.dataset_type==="bigwig"||ac.extra_info==="no_detail"){return false}else{return true}}}},can_subset:function(ac){if(ac.message||ac.extra_info==="no_detail"){return false}else{if(ac.dataset_type==="bigwig"){return(ac.data[1][0]-ac.data[0][0]===1)}}return true},init_for_tool_data:function(){this.data_manager.set("data_type","raw_data");this.data_query_wait=1000;this.dataset_check_type="state"}});var W=function(ad,ac){var ae={resize:false};g.call(this,ad,ac,ae);this.container_div.addClass("label-track")};q(W.prototype,g.prototype,{build_header_div:function(){},init:function(){this.enabled=true},predraw_init:function(){},_draw:function(ag){var ae=this.view,af=ae.high-ae.low,aj=Math.floor(Math.pow(10,Math.floor(Math.log(af)/Math.log(10)))),ac=Math.floor(ae.low/aj)*aj,ah=this.view.container.width(),ad=$("<div/>").addClass("label-container");while(ac<ae.high){var ai=(ac-ae.low)/af*ah;ad.append($("<div/>").addClass("label").text(commatize(ac)).css({left:ai}));ac+=aj}this.content_div.children(":first").remove();this.content_div.append(ad)}});var f=function(ad,ac,ag){N.call(this,ad,ac,ag);this.drawables=[];if("drawables" in ag){var af;for(var ae=0;ae<ag.drawables.length;ae++){af=ag.drawables[ae];this.drawables[ae]=p(af,ad,null);if(af.left_offset>this.left_offset){this.left_offset=af.left_offset}}this.enabled=true}ab.each(this.drawables,function(ah){if(ah instanceof d||ah instanceof T){ah.change_mode("Coverage")}});this.update_icons();this.obj_type="CompositeTrack"};q(f.prototype,N.prototype,{display_modes:C,action_icons_def:[{name:"composite_icon",title:"Show individual tracks",css_class:"layers-stack",on_click_fn:function(ac){$(".tooltip").remove();ac.show_group()}}].concat(N.prototype.action_icons_def),to_dict:A.prototype.to_dict,add_drawable:A.prototype.add_drawable,unpack_drawables:A.prototype.unpack_drawables,change_mode:function(ac){N.prototype.change_mode.call(this,ac);for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad].change_mode(ac)}},init:function(){var ae=[];for(var ad=0;ad<this.drawables.length;ad++){ae.push(this.drawables[ad].init())}var ac=this;$.when.apply($,ae).then(function(){ac.enabled=true;ac.request_draw()})},update_icons:function(){this.action_icons.filters_icon.hide();this.action_icons.tools_icon.hide();this.action_icons.param_space_viz_icon.hide()},can_draw:r.prototype.can_draw,_get_drawables:function(){return this.drawables},show_group:function(){var af=new P(this.view,this.container,{name:this.prefs.name}),ac;for(var ae=0;ae<this.drawables.length;ae++){ac=this.drawables[ae];ac.update_icons();af.add_drawable(ac);ac.container=af;af.content_div.append(ac.container_div)}var ad=this.container.replace_drawable(this,af,true);af.request_draw({clear_tile_cache:true})},before_draw:function(){N.prototype.before_draw.call(this);var ad=ab.min(ab.map(this.drawables,function(ae){return ae.prefs.min_value})),ac=ab.max(ab.map(this.drawables,function(ae){return ae.prefs.max_value}));this.prefs.min_value=ad;this.prefs.max_value=ac;ab.each(this.drawables,function(ae){ae.prefs.min_value=ad;ae.prefs.max_value=ac})},update_all_min_max:function(){var ac=this;ab.each(this.drawables,function(ad){ad.prefs.min_value=ac.prefs.min_value;ad.prefs.max_value=ac.prefs.max_value});this.request_draw({clear_tile_cache:true})},postdraw_actions:function(ai,ac,al,ah){N.prototype.postdraw_actions.call(this,ai,ac,al,ah);var ag=-1,ae;for(ae=0;ae<ai.length;ae++){var aj=ai[ae].html_elt.find("canvas").height();if(aj>ag){ag=aj}}for(ae=0;ae<ai.length;ae++){var af=ai[ae];if(af.html_elt.find("canvas").height()!==ag){this.draw_helper(af.region,al,{force:true,height:ag});af.html_elt.remove()}}var ad=this,ak=function(){ad.update_all_min_max()};this._add_yaxis_label("min",ak);this._add_yaxis_label("max",ak)}});var D=function(ac){N.call(this,ac,{content_div:ac.top_labeltrack},{resize:false});this.left_offset=ac.canvas_manager.char_width_px;this.container_div.addClass("reference-track");this.data_url=galaxy_config.root+"api/genomes/"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new y.GenomeReferenceDataManager({data_url:this.data_url,can_subset:this.can_subset});this.hide_contents()};q(D.prototype,r.prototype,N.prototype,{config_params:ab.union(r.prototype.config_params,[{key:"height",type:"int",default_value:13,hidden:true}]),build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},predraw_init:function(){},can_draw:r.prototype.can_draw,draw_helper:function(ad,ae,ac){if(ae>this.view.canvas_manager.char_width_px){this.tiles_div.show();return N.prototype.draw_helper.call(this,ad,ae,ac)}else{this.tiles_div.hide();return null}},can_subset:function(ac){return true},draw_tile:function(ae,ak,af,ah,al){var ad=this.data_manager.subset_entry(ae,ah),aj=ad.data;var ac=ak.canvas;ak.font=ak.canvas.manager.default_font;ak.textAlign="center";for(var ag=0,ai=aj.length;ag<ai;ag++){ak.fillStyle=this.view.get_base_color(aj[ag]);ak.fillText(aj[ag],Math.floor(ag*al),10)}return new c(this,ah,al,ac,ad)}});var h=function(ad,ac,ae){this.mode="Histogram";N.call(this,ad,ac,ae)};q(h.prototype,r.prototype,N.prototype,{display_modes:C,config_params:ab.union(r.prototype.config_params,[{key:"color",label:"Color",type:"color",default_value:l.get_random_color()},{key:"min_value",label:"Min Value",type:"float",default_value:undefined},{key:"max_value",label:"Max Value",type:"float",default_value:undefined},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:30,hidden:true}]),config_onchange:function(){this.set_name(this.prefs.name);this.request_draw({clear_tile_cache:true})},before_draw:function(){},draw_tile:function(ac,ad,af,ae,ag){return this._draw_line_track_tile(ac,ad,af,ae,ag)},can_subset:function(ac){return(ac.data[1][0]-ac.data[0][0]===1)},postdraw_actions:function(ad,ae,af,ac){this._add_yaxis_label("max");this._add_yaxis_label("min")}});var t=function(ad,ac,ae){this.mode="Heatmap";N.call(this,ad,ac,ae)};q(t.prototype,r.prototype,N.prototype,{display_modes:["Heatmap"],config_params:ab.union(r.prototype.config_params,[{key:"pos_color",label:"Positive Color",type:"color",default_value:"#FF8C00"},{key:"neg_color",label:"Negative Color",type:"color",default_value:"#4169E1"},{key:"min_value",label:"Min Value",type:"float",default_value:-1},{key:"max_value",label:"Max Value",type:"float",default_value:1},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:500,hidden:true}]),config_onchange:function(){this.set_name(this.prefs.name);this.request_draw({clear_tile_cache:true})},draw_tile:function(ac,ae,ah,ag,ai){var af=ae.canvas,ad=new L.DiagonalHeatmapPainter(ac.data,ag.get("start"),ag.get("end"),this.prefs,ah);ad.draw(ae,af.width,af.height,ai);return new c(this,ag,ai,af,ac.data)}});var d=function(ad,ac,ae){N.call(this,ad,ac,ae);this.container_div.addClass("feature-track");this.summary_draw_height=30;this.slotters={};this.start_end_dct={};this.left_offset=200;this.set_painter_from_config()};q(d.prototype,r.prototype,N.prototype,{display_modes:["Auto","Coverage","Dense","Squish","Pack"],config_params:ab.union(r.prototype.config_params,[{key:"block_color",label:"Block color",type:"color",default_value:l.get_random_color()},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:l.get_random_color()},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true,help:"Show the number of items in each bin when drawing summary histogram"},{key:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"connector_style",label:"Connector style",type:"select",default_value:"fishbones",options:[{label:"Line with arrows",value:"fishbone"},{label:"Arcs",value:"arcs"}]},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:0,hidden:true}]),config_onchange:function(){this.set_name(this.prefs.name);this.set_painter_from_config();this.request_draw({clear_tile_cache:true})},set_painter_from_config:function(){if(this.config.get("values").connector_style==="arcs"){this.painter=L.ArcLinkedFeaturePainter}else{this.painter=L.LinkedFeaturePainter}},postdraw_actions:function(am,ae,an,al){N.prototype.postdraw_actions.call(this,am,ae,an,al);var ag=this,ah;if(ag.filters_manager){var af=ag.filters_manager.filters,aj;for(aj=0;aj<af.length;aj++){af[aj].update_ui_elt()}var ai=false,ak,ad;for(ah=0;ah<am.length;ah++){if(am[ah].data.length){ak=am[ah].data[0];for(aj=0;aj<af.length;aj++){ad=af[aj];if(ad.applies_to(ak)&&ad.min!==ad.max){ai=true;break}}}}if(ag.filters_available!==ai){ag.filters_available=ai;if(!ag.filters_available){ag.filters_manager.hide()}ag.update_icons()}}if(am[0] instanceof O){var ac=true;for(ah=0;ah<am.length;ah++){if(!am[ah].all_slotted){ac=false;break}}if(!ac){this.action_icons.show_more_rows_icon.show()}else{this.action_icons.show_more_rows_icon.hide()}}else{this.action_icons.show_more_rows_icon.hide()}},update_auto_mode:function(ac){if(this.mode==="Auto"){if(ac==="no_detail"){ac="feature spans"}this.action_icons.mode_icon.attr("title","Set display mode (now: Auto/"+ac+")")}},incremental_slots:function(ag,ac,af){var ad=this.view.canvas_manager.dummy_context,ae=this.slotters[ag];if(!ae||(ae.mode!==af)){ae=new (u.FeatureSlotter)(ag,af,B,function(ah){return ad.measureText(ah)});this.slotters[ag]=ae}return ae.slot_features(ac)},get_mode:function(ac){if(ac.extra_info==="no_detail"||this.is_overview){mode="no_detail"}else{if(this.view.high-this.view.low>I){mode="Squish"}else{mode="Pack"}}return mode},get_canvas_height:function(ac,ag,ah,ad){if(ag==="Coverage"||ac.dataset_type==="bigwig"){return this.summary_draw_height}else{var af=this.incremental_slots(ah,ac.data,ag);var ae=new (this.painter)(null,null,null,this.prefs,ag);return Math.max(this.min_height_px,ae.get_required_height(af,ad))}},draw_tile:function(am,aq,ao,af,aj,ae){var ap=this,ad=aq.canvas,ax=af.get("start"),ac=af.get("end"),ag=this.left_offset;if(am.dataset_type==="bigwig"){return this._draw_line_track_tile(am,aq,ao,af,aj)}var ai=[],an=this.slotters[aj].slots;all_slotted=true;if(am.data){var ak=this.filters_manager.filters;for(var ar=0,au=am.data.length;ar<au;ar++){var ah=am.data[ar];var at=false;var al;for(var aw=0,aB=ak.length;aw<aB;aw++){al=ak[aw];al.update_attrs(ah);if(!al.keep(ah)){at=true;break}}if(!at){ai.push(ah);if(!(ah[0] in an)){all_slotted=false}}}}var aA=(this.filters_manager.alpha_filter?new E(this.filters_manager.alpha_filter):null),ay=(this.filters_manager.height_filter?new E(this.filters_manager.height_filter):null),az=new (this.painter)(ai,ax,ac,this.prefs,ao,aA,ay,ae,function(aC){return ap.view.get_base_color(aC)});var av=null;aq.fillStyle=this.prefs.block_color;aq.font=aq.canvas.manager.default_font;aq.textAlign="right";if(am.data){av=az.draw(aq,ad.width,ad.height,aj,an);av.translation=-ag}return new O(ap,af,aj,ad,am.data,ao,am.message,all_slotted,av)}});var Z=function(ad,ac,ae){N.call(this,ad,ac,ae);this.painter=L.VariantPainter;this.summary_draw_height=30;this.left_offset=30};q(Z.prototype,r.prototype,N.prototype,{display_modes:["Auto","Coverage","Dense","Squish","Pack"],config_params:ab.union(r.prototype.config_params,[{key:"color",label:"Histogram color",type:"color",default_value:l.get_random_color()},{key:"show_sample_data",label:"Show sample data",type:"bool",default_value:true},{key:"show_labels",label:"Show summary and sample labels",type:"bool",default_value:true},{key:"summary_height",label:"Locus summary height",type:"float",default_value:20},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:0,hidden:true}]),config_onchange:function(){this.set_name(this.prefs.name);this.request_draw({clear_tile_cache:true})},draw_tile:function(ac,af,ah,ag,ai){if(ac.dataset_type==="bigwig"){return this._draw_line_track_tile(ac,af,"Histogram",ag,ai)}else{var ae=this.view,ad=new (this.painter)(ac.data,ag.get("start"),ag.get("end"),this.prefs,ah,function(aj){return ae.get_base_color(aj)});ad.draw(af,af.canvas.width,af.canvas.height,ai);return new c(this,ag,ai,af.canvas,ac.data)}},get_canvas_height:function(ac,ag,ah,ae){if(ac.dataset_type==="bigwig"){return this.summary_draw_height}else{var ad=(this.dataset.get_metadata("sample_names")?this.dataset.get_metadata("sample_names").length:0);if(ad===0&&ac.data.length!==0){ad=ac.data[0][7].match(/,/g);if(ad===null){ad=1}else{ad=ad.length+1}}var af=new (this.painter)(null,null,null,this.prefs,ag);return af.get_required_height(ad)}},predraw_init:function(){var ac=[g.prototype.predraw_init.call(this)];if(!this.dataset.get_metadata("sample_names")){ac.push(this.dataset.fetch())}return ac},postdraw_actions:function(ag,ah,aj,ad){N.prototype.postdraw_actions.call(this,ag,ah,aj,ad);var af=ab.filter(ag,function(ak){return(ak instanceof M)});var ae=this.dataset.get_metadata("sample_names");if(af.length===0&&this.prefs.show_labels&&ae&&ae.length>1){var ac;if(this.container_div.find(".yaxislabel.variant").length===0){ac=this.prefs.summary_height/2;this.tiles_div.prepend($("<div/>").text("Summary").addClass("yaxislabel variant top").css({"font-size":ac+"px",top:(this.prefs.summary_height-ac)/2+"px"}));if(this.prefs.show_sample_data){var ai=ae.join("<br/>");this.tiles_div.prepend($("<div/>").html(ai).addClass("yaxislabel variant top sample").css({top:this.prefs.summary_height,}))}}ac=(this.mode==="Squish"?5:10)+"px";$(this.tiles_div).find(".sample").css({"font-size":ac,"line-height":ac});$(this.tiles_div).find(".yaxislabel").css("color",this.prefs.label_color)}else{this.container_div.find(".yaxislabel.variant").remove()}}});var T=function(ad,ac,ae){d.call(this,ad,ac,ae);this.painter=(ad.reference_track?L.RefBasedReadPainter:L.ReadPainter);this.update_icons()};q(T.prototype,r.prototype,N.prototype,d.prototype,{config_params:ab.union(r.prototype.config_params,[{key:"block_color",label:"Block and sense strand color",type:"color",default_value:l.get_random_color()},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:l.get_random_color()},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_differences",label:"Show differences only",type:"bool",default_value:true},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"height",type:"int",default_value:0,hidden:true}]),config_onchange:function(){this.set_name(this.prefs.name);this.request_draw({clear_tile_cache:true})}});var e={CompositeTrack:f,DrawableGroup:P,DiagonalHeatmapTrack:t,FeatureTrack:d,LineTrack:h,ReadTrack:T,VariantTrack:Z,VcfTrack:Z};var p=function(ae,ad,ac){if("copy" in ae){return ae.copy(ac)}else{var af=ae.obj_type;if(!af){af=ae.track_type}return new e[af](ad,ac,ae)}};return{TracksterView:Y,DrawableGroup:P,LineTrack:h,FeatureTrack:d,DiagonalHeatmapTrack:t,ReadTrack:T,VariantTrack:Z,CompositeTrack:f,object_from_template:p}});
\ No newline at end of file
This diff is so big that we needed to truncate the remainder.
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
15 Nov '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/e057f2263f4b/
Changeset: e057f2263f4b
User: natefoo
Date: 2013-11-15 20:19:09
Summary: Merge stable.
Affected #: 1 file
diff -r 74202eb63f37ad49e413c7bcda9d54be881469b9 -r e057f2263f4bf8d2f5c277ae09360e36aa96cbbb lib/galaxy/jobs/runners/pbs.py
--- a/lib/galaxy/jobs/runners/pbs.py
+++ b/lib/galaxy/jobs/runners/pbs.py
@@ -49,7 +49,7 @@
"""
PBS_ARGMAP = {
- 'destination' : '-d',
+ 'destination' : '-q',
'Execution_Time' : '-a',
'Account_Name' : '-A',
'Checkpoint' : '-c',
@@ -213,6 +213,8 @@
pbs_queue_name = None
pbs_server_name = self.default_pbs_server
pbs_options = []
+ if '-q' in job_destination.params and 'destination' not in job_destination.params:
+ job_destination.params['destination'] = job_destination.params.pop('-q')
if 'destination' in job_destination.params:
if '@' in job_destination.params['destination']:
# Destination includes a server
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: natefoo: Properly handle PBS' -q argument.
by commits-noreply@bitbucket.org 15 Nov '13
by commits-noreply@bitbucket.org 15 Nov '13
15 Nov '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/51b4282dce3a/
Changeset: 51b4282dce3a
Branch: stable
User: natefoo
Date: 2013-11-15 20:18:09
Summary: Properly handle PBS' -q argument.
Affected #: 1 file
diff -r 84f9600dc305cd5d47aef72f260826f89e6872eb -r 51b4282dce3a411d02b982d1cca137884d5f6c2b lib/galaxy/jobs/runners/pbs.py
--- a/lib/galaxy/jobs/runners/pbs.py
+++ b/lib/galaxy/jobs/runners/pbs.py
@@ -47,7 +47,7 @@
"""
PBS_ARGMAP = {
- 'destination' : '-d',
+ 'destination' : '-q',
'Execution_Time' : '-a',
'Account_Name' : '-A',
'Checkpoint' : '-c',
@@ -210,6 +210,8 @@
pbs_queue_name = None
pbs_server_name = self.default_pbs_server
pbs_options = []
+ if '-q' in job_destination.params and 'destination' not in job_destination.params:
+ job_destination.params['destination'] = job_destination.params.pop('-q')
if 'destination' in job_destination.params:
if '@' in job_destination.params['destination']:
# Destination includes a server
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: natefoo: Detect nginx upload injected params in the API tool runner.
by commits-noreply@bitbucket.org 15 Nov '13
by commits-noreply@bitbucket.org 15 Nov '13
15 Nov '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/74202eb63f37/
Changeset: 74202eb63f37
User: natefoo
Date: 2013-11-15 20:15:00
Summary: Detect nginx upload injected params in the API tool runner.
Affected #: 1 file
diff -r 67a956d27f6ec30b4c12d4aaa99a0e2a9249291c -r 74202eb63f37ad49e413c7bcda9d54be881469b9 lib/galaxy/webapps/galaxy/api/tools.py
--- a/lib/galaxy/webapps/galaxy/api/tools.py
+++ b/lib/galaxy/webapps/galaxy/api/tools.py
@@ -95,7 +95,7 @@
inputs = payload.get( 'inputs', {} )
# Find files coming in as multipart file data and add to inputs.
for k, v in payload.iteritems():
- if k.startswith("files_"):
+ if k.startswith("files_") or k.startswith("__files_"):
inputs[k] = v
#for inputs that are coming from the Library, copy them into the history
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: Dave Bouvier: Fix for exporting a repository with a complex repository dependency.
by commits-noreply@bitbucket.org 15 Nov '13
by commits-noreply@bitbucket.org 15 Nov '13
15 Nov '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/67a956d27f6e/
Changeset: 67a956d27f6e
User: Dave Bouvier
Date: 2013-11-15 17:14:26
Summary: Fix for exporting a repository with a complex repository dependency.
Affected #: 1 file
diff -r a973453e1e6881bc58d2378eab7178a4bdf887e9 -r 67a956d27f6ec30b4c12d4aaa99a0e2a9249291c lib/tool_shed/util/commit_util.py
--- a/lib/tool_shed/util/commit_util.py
+++ b/lib/tool_shed/util/commit_util.py
@@ -442,8 +442,6 @@
error_message += 'tag set.'
if package_altered:
package_elem[ actions_index ] = actions_elem
- if package_altered:
- root_elem[ package_index ] = package_elem
if package_altered:
root[ root_index ] = root_elem
return altered, root, error_message
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: Dave Bouvier: Fix for exporting a repository capsule.
by commits-noreply@bitbucket.org 15 Nov '13
by commits-noreply@bitbucket.org 15 Nov '13
15 Nov '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/a973453e1e68/
Changeset: a973453e1e68
User: Dave Bouvier
Date: 2013-11-15 16:50:49
Summary: Fix for exporting a repository capsule.
Affected #: 1 file
diff -r 69f348f4b3c7fac9c406b1666309f82810566802 -r a973453e1e6881bc58d2378eab7178a4bdf887e9 lib/galaxy/webapps/tool_shed/controllers/repository.py
--- a/lib/galaxy/webapps/tool_shed/controllers/repository.py
+++ b/lib/galaxy/webapps/tool_shed/controllers/repository.py
@@ -1105,7 +1105,7 @@
opened_archive = open( repositories_archive.name )
# Make sure the file is removed from disk after the contents have been downloaded.
os.unlink( repositories_archive.name )
- repositories_archive_path, file_name = os.path.split( repositories_archive )
+ repositories_archive_path, file_name = os.path.split( repositories_archive.name )
suc.remove_dir( repositories_archive_path )
return opened_archive
repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, repository_id, changeset_revision )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
3 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/3d8841746ce9/
Changeset: 3d8841746ce9
Branch: stable
User: Dave Bouvier
Date: 2013-11-12 21:36:13
Summary: Fix display of status images for installed tool shed repositories when using a proxy prefix.
Affected #: 1 file
diff -r 093626ae621f73b9cf904c935eddae98a8823839 -r 3d8841746ce9b65e19a44028dea2eac73a4eddf8 lib/tool_shed/galaxy_install/grids/admin_toolshed_grids.py
--- a/lib/tool_shed/galaxy_install/grids/admin_toolshed_grids.py
+++ b/lib/tool_shed/galaxy_install/grids/admin_toolshed_grids.py
@@ -2,6 +2,7 @@
from galaxy import model, util
from galaxy.web.framework.helpers import iff, grids
+from galaxy.web import url_for
from galaxy.model.orm import or_
import tool_shed.util.shed_util_common as suc
from tool_shed.util import tool_dependency_util
@@ -13,42 +14,42 @@
deprecated_tip_str = 'class="icon-button" title="This repository is deprecated in the Tool Shed"'
else:
deprecated_tip_str = ''
- return '<img src="/static/images/icon_error_sml.gif" %s/>' % deprecated_tip_str
+ return '<img src="%s/images/icon_error_sml.gif" %s/>' % ( url_for( '/static' ), deprecated_tip_str )
def generate_includes_workflows_img_str( include_mouse_over=False ):
if include_mouse_over:
deprecated_tip_str = 'class="icon-button" title="This repository contains exported workflows"'
else:
deprecated_tip_str = ''
- return '<img src="/static/images/fugue/gear.png" %s/>' % deprecated_tip_str
+ return '<img src="%s/images/fugue/gear.png" %s/>' % ( url_for( '/static' ), deprecated_tip_str )
def generate_latest_revision_img_str( include_mouse_over=False ):
if include_mouse_over:
latest_revision_tip_str = 'class="icon-button" title="This is the latest installable revision of this repository"'
else:
latest_revision_tip_str = ''
- return '<img src="/static/june_2007_style/blue/ok_small.png" %s/>' % latest_revision_tip_str
+ return '<img src="%s/june_2007_style/blue/ok_small.png" %s/>' % ( url_for( '/static' ), latest_revision_tip_str )
def generate_revision_updates_img_str( include_mouse_over=False ):
if include_mouse_over:
revision_updates_tip_str = 'class="icon-button" title="Updates are available in the Tool Shed for this revision"'
else:
revision_updates_tip_str = ''
- return '<img src="/static/images/icon_warning_sml.gif" %s/>' % revision_updates_tip_str
+ return '<img src="%s/images/icon_warning_sml.gif" %s/>' % ( url_for( '/static' ), revision_updates_tip_str )
def generate_revision_upgrades_img_str( include_mouse_over=False ):
if include_mouse_over:
revision_upgrades_tip_str = 'class="icon-button" title="A newer installable revision is available for this repository"'
else:
revision_upgrades_tip_str = ''
- return '<img src="/static/images/up.gif" %s/>' % revision_upgrades_tip_str
+ return '<img src="%s/images/up.gif" %s/>' % ( url_for( '/static' ), revision_upgrades_tip_str )
def generate_unknown_img_str( include_mouse_over=False ):
if include_mouse_over:
unknown_tip_str = 'class="icon-button" title="Unable to get information from the Tool Shed"'
else:
unknown_tip_str = ''
- return '<img src="/static/june_2007_style/blue/question-octagon-frame.png" %s/>' % unknown_tip_str
+ return '<img src="%s/june_2007_style/blue/question-octagon-frame.png" %s/>' % ( url_for( '/static' ), unknown_tip_str )
class InstalledRepositoryGrid( grids.Grid ):
https://bitbucket.org/galaxy/galaxy-central/commits/84f9600dc305/
Changeset: 84f9600dc305
Branch: stable
User: jmchilton
Date: 2013-11-15 15:20:06
Summary: Fix small typo in 9ce5afd (tool shed autoconf action).
Affected #: 1 file
diff -r 3d8841746ce9b65e19a44028dea2eac73a4eddf8 -r 84f9600dc305cd5d47aef72f260826f89e6872eb lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
@@ -505,7 +505,7 @@
if 'prefix=' in configure_opts:
pre_cmd = './configure %s && make && make install' % configure_opts
else:
- pre_cmd = './configure prefix=$INSTALL_DIR %s && make && make install' % configure_opts
+ pre_cmd = './configure --prefix=$INSTALL_DIR %s && make && make install' % configure_opts
cmd = install_environment.build_command( td_common_util.evaluate_template( pre_cmd, install_dir ) )
return_code = handle_command( app, tool_dependency, install_dir, cmd )
if return_code:
https://bitbucket.org/galaxy/galaxy-central/commits/69f348f4b3c7/
Changeset: 69f348f4b3c7
User: jmchilton
Date: 2013-11-15 15:20:36
Summary: Merge latest stable.
Affected #: 2 files
diff -r 1560813167c0072773738cdf57103ecc0191b327 -r 69f348f4b3c7fac9c406b1666309f82810566802 lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
@@ -655,7 +655,7 @@
if 'prefix=' in configure_opts:
pre_cmd = './configure %s && make && make install' % configure_opts
else:
- pre_cmd = './configure prefix=$INSTALL_DIR %s && make && make install' % configure_opts
+ pre_cmd = './configure --prefix=$INSTALL_DIR %s && make && make install' % configure_opts
cmd = install_environment.build_command( td_common_util.evaluate_template( pre_cmd, install_dir ) )
return_code = handle_command( app, tool_dependency, install_dir, cmd )
if return_code:
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jmchilton: Fix bug in 4f7e715 that actually allows multiple repeat values to be specified via API.
by commits-noreply@bitbucket.org 15 Nov '13
by commits-noreply@bitbucket.org 15 Nov '13
15 Nov '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/1560813167c0/
Changeset: 1560813167c0
User: jmchilton
Date: 2013-11-15 06:39:52
Summary: Fix bug in 4f7e715 that actually allows multiple repeat values to be specified via API.
Affected #: 1 file
diff -r 55e0fe991c42a3d1551ae9965d2186b6870aaba9 -r 1560813167c0072773738cdf57103ecc0191b327 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -2084,7 +2084,7 @@
rep_index = 0
while True:
rep_name = "%s_%d" % ( key, rep_index )
- if not any( [ key.startswith(rep_name) for key in incoming.keys() ] ):
+ if not any( [ incoming_key.startswith(rep_name) for incoming_key in incoming.keys() ] ):
break
if rep_index < input.max:
new_state = {}
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jmchilton: PEP-8 fixes for test/base/twilltestcase.py.
by commits-noreply@bitbucket.org 15 Nov '13
by commits-noreply@bitbucket.org 15 Nov '13
15 Nov '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/55e0fe991c42/
Changeset: 55e0fe991c42
User: jmchilton
Date: 2013-11-15 00:49:58
Summary: PEP-8 fixes for test/base/twilltestcase.py.
Still hundreds of lines to fix.
Affected #: 1 file
diff -r a231103b3d6e14578a226f9f6d5a3b68c0896854 -r 55e0fe991c42a3d1551ae9965d2186b6870aaba9 test/base/twilltestcase.py
--- a/test/base/twilltestcase.py
+++ b/test/base/twilltestcase.py
@@ -1,7 +1,20 @@
import pkg_resources
pkg_resources.require( "twill==0.9" )
-import StringIO, os, filecmp, time, unittest, urllib, logging, difflib, tarfile, zipfile, tempfile, re, shutil, subprocess
+import StringIO
+import os
+import filecmp
+import time
+import unittest
+import urllib
+import logging
+import difflib
+import tarfile
+import zipfile
+import tempfile
+import re
+import shutil
+import subprocess
import pprint
import twill
@@ -26,6 +39,7 @@
logging.getLogger( "ClientCookie.cookies" ).setLevel( logging.WARNING )
log = logging.getLogger( __name__ )
+
class TwillTestCase( unittest.TestCase ):
def setUp( self ):
@@ -46,10 +60,10 @@
self.shed_tools_dict = {}
self.keepOutdir = os.environ.get( 'GALAXY_TEST_SAVE', '' )
if self.keepOutdir > '':
- try:
- os.makedirs(self.keepOutdir)
- except:
- pass
+ try:
+ os.makedirs(self.keepOutdir)
+ except:
+ pass
self.home()
# Functions associated with files
@@ -83,7 +97,7 @@
diff_lines = get_lines_diff( diff )
if diff_lines > allowed_diff_count:
diff_slice = diff[0:40]
- #FIXME: This pdf stuff is rather special cased and has not been updated to consider lines_diff
+ #FIXME: This pdf stuff is rather special cased and has not been updated to consider lines_diff
#due to unknown desired behavior when used in conjunction with a non-zero lines_diff
#PDF forgiveness can probably be handled better by not special casing by __extension__ here
#and instead using lines_diff or a regular expression matching
@@ -109,13 +123,13 @@
break
if not valid_diff:
invalid_diff_lines += 1
- log.info('## files diff on %s and %s lines_diff=%d, found diff = %d, found pdf invalid diff = %d' % (file1,file2,allowed_diff_count,diff_lines,invalid_diff_lines))
+ log.info('## files diff on %s and %s lines_diff=%d, found diff = %d, found pdf invalid diff = %d' % (file1, file2, allowed_diff_count, diff_lines, invalid_diff_lines))
if invalid_diff_lines > allowed_diff_count:
# Print out diff_slice so we can see what failed
print "###### diff_slice ######"
raise AssertionError( "".join( diff_slice ) )
else:
- log.info('## files diff on %s and %s lines_diff=%d, found diff = %d' % (file1,file2,allowed_diff_count,diff_lines))
+ log.info('## files diff on %s and %s lines_diff=%d, found diff = %d' % (file1, file2, allowed_diff_count, diff_lines))
for line in diff_slice:
for char in line:
if ord( char ) > 128:
@@ -124,7 +138,7 @@
def files_re_match( self, file1, file2, attributes=None ):
"""Checks the contents of 2 files for differences using re.match"""
- local_file = open( file1, 'U' ).readlines() #regex file
+ local_file = open( file1, 'U' ).readlines() # regex file
history_data = open( file2, 'U' ).readlines()
assert len( local_file ) == len( history_data ), 'Data File and Regular Expression File contain a different number of lines (%s != %s)\nHistory Data (first 40 lines):\n%s' % ( len( local_file ), len( history_data ), ''.join( history_data[:40] ) )
if attributes is None:
@@ -139,11 +153,11 @@
line_diff_count += 1
diffs.append( 'Regular Expression: %s\nData file : %s' % ( local_file[i].rstrip( '\r\n' ), history_data[i].rstrip( '\r\n' ) ) )
if line_diff_count > lines_diff:
- raise AssertionError, "Regular expression did not match data file (allowed variants=%i):\n%s" % ( lines_diff, "".join( diffs ) )
+ raise AssertionError( "Regular expression did not match data file (allowed variants=%i):\n%s" % ( lines_diff, "".join( diffs ) ) )
def files_re_match_multiline( self, file1, file2, attributes=None ):
"""Checks the contents of 2 files for differences using re.match in multiline mode"""
- local_file = open( file1, 'U' ).read() #regex file
+ local_file = open( file1, 'U' ).read() # regex file
if attributes is None:
attributes = {}
if attributes.get( 'sort', False ):
@@ -157,7 +171,7 @@
def files_contains( self, file1, file2, attributes=None ):
"""Checks the contents of file2 for substrings found in file1, on a per-line basis"""
- local_file = open( file1, 'U' ).readlines() #regex file
+ local_file = open( file1, 'U' ).readlines() # regex file
#TODO: allow forcing ordering of contains
history_data = open( file2, 'U' ).read()
lines_diff = int( attributes.get( 'lines_diff', 0 ) )
@@ -167,7 +181,7 @@
if contains not in history_data:
line_diff_count += 1
if line_diff_count > lines_diff:
- raise AssertionError, "Failed to find '%s' in history data. (lines_diff=%i):\n" % ( contains, lines_diff )
+ raise AssertionError( "Failed to find '%s' in history data. (lines_diff=%i):\n" % ( contains, lines_diff ) )
def get_filename( self, filename, shed_tool_id=None ):
if shed_tool_id and self.shed_tools_dict:
@@ -189,8 +203,8 @@
so the tool-data directory of test data files is contained in the installed tool shed repository.
"""
self.visit_url( "%s/tool_runner?tool_id=upload1" % self.url )
- try:
- self.refresh_form( "file_type", ftype ) #Refresh, to support composite files
+ try:
+ self.refresh_form( "file_type", ftype ) # Refresh, to support composite files
tc.fv( "tool_form", "dbkey", dbkey )
if metadata:
for elem in metadata:
@@ -214,9 +228,9 @@
hids = self.get_hids_in_history()
for hid in hids:
try:
- valid_hid = int( hid )
+ int( hid )
except:
- raise AssertionError, "Invalid hid (%s) created when uploading file %s" % ( hid, filename )
+ raise AssertionError( "Invalid hid (%s) created when uploading file %s" % ( hid, filename ) )
# Wait for upload processing to finish (TODO: this should be done in each test case instead)
self.wait()
@@ -231,21 +245,21 @@
self.home()
except Exception, e:
errmsg = "Problem executing upload utility using url_paste: %s" % str( e )
- raise AssertionError( e )
+ raise AssertionError( errmsg )
# Make sure every history item has a valid hid
hids = self.get_hids_in_history()
for hid in hids:
try:
- valid_hid = int( hid )
+ int( hid )
except:
- raise AssertionError, "Invalid hid (%s) created when pasting %s" % ( hid, url_paste )
+ raise AssertionError( "Invalid hid (%s) created when pasting %s" % ( hid, url_paste ) )
# Wait for upload processing to finish (TODO: this should be done in each test case instead)
self.wait()
def json_from_url( self, url ):
self.visit_url( url )
return from_json_string( self.last_page() )
-
+
# Functions associated with histories
def get_history_from_api( self, encoded_history_id=None ):
if encoded_history_id is None:
@@ -255,7 +269,7 @@
def get_latest_history( self ):
return self.json_from_url( '/api/histories' )[ 0 ]
-
+
def find_hda_by_dataset_name( self, name, history=None ):
if history is None:
history = self.get_history_from_api()
@@ -269,7 +283,7 @@
self.visit_page( "history" )
page = self.last_page()
if page.find( 'error' ) > -1:
- raise AssertionError('Errors in the history for user %s' % self.user )
+ raise AssertionError( 'Errors in the history for user %s' % self.user )
def check_history_for_string( self, patt, show_deleted=False ):
"""Breaks patt on whitespace and searches for each element seperately in the history"""
@@ -320,7 +334,7 @@
# twill stores the regex match in a special stack variable
match = twill.namespaces.get_twill_glocals()[1][ '__match__' ]
json_data = from_json_string( match )
- assert check_fn( json_data ), 'failed check_fn: %s' %( check_fn.func_name )
+ assert check_fn( json_data ), 'failed check_fn: %s' % ( check_fn.func_name )
except Exception, exc:
log.error( exc, exc_info=True )
@@ -374,6 +388,7 @@
num_deleted = len( id.split( ',' ) )
self.home()
self.visit_page( "history/list?operation=delete&id=%s" % ( id ) )
+
check_str = 'Deleted %d %s' % ( num_deleted, iff( num_deleted != 1, "histories", "history" ) )
self.check_page_for_string( check_str )
self.home()
@@ -423,7 +438,7 @@
if active_datasets:
self.check_page_for_string( 'Create</a> a new empty history' )
self.check_page_for_string( 'Construct workflow</a> from current history' )
- self.check_page_for_string( 'Copy</a> current history' )
+ self.check_page_for_string( 'Copy</a> current history' )
self.check_page_for_string( 'Share</a> current history' )
self.check_page_for_string( 'Change default permissions</a> for current history' )
if histories_shared_by_others:
@@ -447,7 +462,7 @@
def rename_history( self, id, old_name, new_name ):
"""Rename an existing history"""
self.home()
- self.visit_page( "history/rename?id=%s&name=%s" %( id, new_name ) )
+ self.visit_page( "history/rename?id=%s&name=%s" % ( id, new_name ) )
check_str = 'History: %s renamed to: %s' % ( old_name, urllib.unquote( new_name ) )
self.check_page_for_string( check_str )
self.home()
@@ -476,6 +491,7 @@
for check_str in action_strings_displayed:
self.check_page_for_string( check_str )
tc.fv( 'share_restricted', 'action', action )
+
tc.submit( "share_restricted_button" )
for check_str in action_strings_displayed_after_submit:
self.check_page_for_string( check_str )
@@ -495,6 +511,7 @@
# If we have an action, then we are sharing datasets with users that do not have access permissions on them
tc.fv( 'share_restricted', 'action', action )
tc.submit( "share_restricted_button" )
+
for check_str in action_strings_displayed:
self.check_page_for_string( check_str )
self.home()
@@ -525,6 +542,7 @@
for check_str in strings_displayed:
self.check_page_for_string( check_str )
self.home()
+
def view_stored_deleted_histories( self, strings_displayed=[] ):
self.home()
self.visit_page( "history/list?f-deleted=True" )
@@ -534,12 +552,14 @@
for check_str in strings_displayed:
self.check_page_for_string( check_str )
self.home()
+
def view_shared_histories( self, strings_displayed=[] ):
self.home()
self.visit_page( "history/list_shared" )
for check_str in strings_displayed:
self.check_page_for_string( check_str )
self.home()
+
def copy_history( self, history_id, copy_choice, strings_displayed=[], strings_displayed_after_submit=[] ):
self.home()
self.visit_page( "history/copy?id=%s" % history_id )
@@ -550,6 +570,7 @@
for check_str in strings_displayed_after_submit:
self.check_page_for_string( check_str )
self.home()
+
def make_accessible_via_link( self, history_id, strings_displayed=[], strings_displayed_after_submit=[] ):
self.home()
self.visit_page( "history/list?operation=share+or+publish&id=%s" % history_id )
@@ -562,6 +583,7 @@
for check_str in strings_displayed_after_submit:
self.check_page_for_string( check_str )
self.home()
+
def disable_access_via_link( self, history_id, strings_displayed=[], strings_displayed_after_submit=[] ):
self.home()
self.visit_page( "history/list?operation=share+or+publish&id=%s" % history_id )
@@ -574,6 +596,7 @@
for check_str in strings_displayed_after_submit:
self.check_page_for_string( check_str )
self.home()
+
def import_history_via_url( self, history_id, email, strings_displayed_after_submit=[] ):
self.home()
self.visit_page( "history/imp?&id=%s" % history_id )
@@ -584,9 +607,10 @@
# Functions associated with datasets (history items) and meta data
def _get_job_stream_output( self, hda_id, stream, format ):
self.visit_page( "datasets/%s/%s" % ( self.security.encode_id( hda_id ), stream ) )
+
output = self.last_page()
if format:
- msg = "---------------------- >> begin tool %s << -----------------------\n" % stream
+ msg = "---------------------- >> begin tool %s << -----------------------\n" % stream
msg += output + "\n"
msg += "----------------------- >> end tool %s << ------------------------\n" % stream
else:
@@ -609,43 +633,48 @@
"""Looks for 'patt' in the edit page when editing a dataset"""
data_list = self.get_history_as_data_list()
self.assertTrue( data_list )
- if hid is None: # take last hid
+ if hid is None: # take last hid
elem = data_list[-1]
hid = int( elem.get('hid') )
self.assertTrue( hid )
self.visit_page( "dataset/edit?hid=%s" % hid )
for subpatt in patt.split():
tc.find(subpatt)
+
def delete_history_item( self, hda_id, strings_displayed=[] ):
"""Deletes an item from a history"""
try:
hda_id = int( hda_id )
except:
- raise AssertionError, "Invalid hda_id '%s' - must be int" % hda_id
+ raise AssertionError( "Invalid hda_id '%s' - must be int" % hda_id )
self.visit_url( "%s/datasets/%s/delete?show_deleted_on_refresh=False" % ( self.url, self.security.encode_id( hda_id ) ) )
for check_str in strings_displayed:
self.check_page_for_string( check_str )
+
def undelete_history_item( self, hda_id, strings_displayed=[] ):
"""Un-deletes a deleted item in a history"""
try:
hda_id = int( hda_id )
except:
- raise AssertionError, "Invalid hda_id '%s' - must be int" % hda_id
+ raise AssertionError( "Invalid hda_id '%s' - must be int" % hda_id )
self.visit_url( "%s/datasets/%s/undelete" % ( self.url, self.security.encode_id( hda_id ) ) )
for check_str in strings_displayed:
self.check_page_for_string( check_str )
+
def display_history_item( self, hda_id, strings_displayed=[] ):
"""Displays a history item - simulates eye icon click"""
self.visit_url( '%s/datasets/%s/display/' % ( self.url, self.security.encode_id( hda_id ) ) )
for check_str in strings_displayed:
self.check_page_for_string( check_str )
self.home()
+
def view_history( self, history_id, strings_displayed=[] ):
"""Displays a history for viewing"""
self.visit_url( '%s/history/view?id=%s' % ( self.url, self.security.encode_id( history_id ) ) )
for check_str in strings_displayed:
self.check_page_for_string( check_str )
self.home()
+
def edit_hda_attribute_info( self, hda_id, new_name='', new_info='', new_dbkey='', new_startcol='',
strings_displayed=[], strings_not_displayed=[] ):
"""Edit history_dataset_association attribute information"""
@@ -673,14 +702,16 @@
for check_str in strings_not_displayed:
try:
self.check_page_for_string( check_str )
- raise AssertionError, "String (%s) incorrectly displayed on Edit Attributes page." % check_str
+ raise AssertionError( "String (%s) incorrectly displayed on Edit Attributes page." % check_str )
except:
pass
self.home()
+
def check_hda_attribute_info( self, hda_id, strings_displayed=[] ):
"""Edit history_dataset_association attribute information"""
for check_str in strings_displayed:
self.check_page_for_string( check_str )
+
def auto_detect_metadata( self, hda_id ):
"""Auto-detect history_dataset_association metadata"""
self.home()
@@ -695,6 +726,7 @@
self.check_page_for_string( 'Attributes updated' )
#self.check_page_for_string( 'Attributes updated' )
self.home()
+
def convert_format( self, hda_id, target_type ):
"""Convert format of history_dataset_association"""
self.home()
@@ -703,8 +735,9 @@
tc.fv( 'convert_data', 'target_type', target_type )
tc.submit( 'convert_data' )
self.check_page_for_string( 'The file conversion of Convert BED to GFF on data' )
- self.wait() #wait for the format convert tool to finish before returning
+ self.wait() # wait for the format convert tool to finish before returning
self.home()
+
def change_datatype( self, hda_id, datatype ):
"""Change format of history_dataset_association"""
self.home()
@@ -714,6 +747,7 @@
tc.submit( 'change' )
self.check_page_for_string( 'Changed the type of dataset' )
self.home()
+
def copy_history_item( self, source_dataset_id=None, target_history_id=None, all_target_history_ids=[],
deleted_history_ids=[] ):
"""
@@ -730,10 +764,10 @@
for id in deleted_history_ids:
try:
self.check_page_for_string( id )
- raise AssertionError, "deleted history id %d displayed in list of target histories" % id
+ raise AssertionError( "deleted history id %d displayed in list of target histories" % id )
except:
pass
-
+
tc.fv( '1', 'target_history_id', target_history_id )
tc.submit( 'do_copy' )
check_str = '1 dataset copied to 1 history'
@@ -760,17 +794,17 @@
def makeTfname(self, fname=None):
"""safe temp name - preserve the file extension for tools that interpret it"""
- suffix = os.path.split(fname)[-1] # ignore full path
- fd,temp_prefix = tempfile.mkstemp(prefix='tmp',suffix=suffix)
+ suffix = os.path.split(fname)[-1] # ignore full path
+ fd, temp_prefix = tempfile.mkstemp(prefix='tmp', suffix=suffix)
return temp_prefix
def verify_dataset_correctness( self, filename, hid=None, wait=True, maxseconds=120, attributes=None, shed_tool_id=None ):
"""Verifies that the attributes and contents of a history item meet expectations"""
if wait:
- self.wait( maxseconds=maxseconds ) #wait for job to finish
+ self.wait( maxseconds=maxseconds ) # wait for job to finish
data_list = self.get_history_as_data_list()
self.assertTrue( data_list )
- if hid is None: # take last hid
+ if hid is None: # take last hid
elem = data_list[-1]
hid = str( elem.get('hid') )
else:
@@ -804,9 +838,9 @@
raise AssertionError( errmsg )
if filename is not None:
local_name = self.get_filename( filename, shed_tool_id=shed_tool_id )
- temp_name = self.makeTfname(fname = filename)
+ temp_name = self.makeTfname(fname=filename)
file( temp_name, 'wb' ).write( data )
-
+
# if the server's env has GALAXY_TEST_SAVE, save the output file to that dir
if self.keepOutdir:
ofn = os.path.join( self.keepOutdir, os.path.basename( local_name ) )
@@ -814,12 +848,11 @@
try:
shutil.copy( temp_name, ofn )
except Exception, exc:
- error_log_msg = ( 'TwillTestCase could not save output file %s to %s: ' % ( temp_name, ofn ) )
+ error_log_msg = ( 'TwillTestCase could not save output file %s to %s: ' % ( temp_name, ofn ) )
error_log_msg += str( exc )
log.error( error_log_msg, exc_info=True )
else:
log.debug('## GALAXY_TEST_SAVE=%s. saved %s' % ( self.keepOutdir, ofn ) )
-
try:
# have to nest try-except in try-finally to handle 2.4
try:
@@ -837,15 +870,15 @@
elif compare == 're_match_multiline':
self.files_re_match_multiline( local_name, temp_name, attributes=attributes )
elif compare == 'sim_size':
- delta = attributes.get('delta','100')
+ delta = attributes.get('delta', '100')
s1 = len(data)
s2 = os.path.getsize(local_name)
- if abs(s1-s2) > int(delta):
- raise Exception, 'Files %s=%db but %s=%db - compare (delta=%s) failed' % (temp_name,s1,local_name,s2,delta)
+ if abs(s1 - s2) > int(delta):
+ raise Exception( 'Files %s=%db but %s=%db - compare (delta=%s) failed' % (temp_name, s1, local_name, s2, delta) )
elif compare == "contains":
self.files_contains( local_name, temp_name, attributes=attributes )
else:
- raise Exception, 'Unimplemented Compare type: %s' % compare
+ raise Exception( 'Unimplemented Compare type: %s' % compare )
if extra_files:
self.verify_extra_files_content( extra_files, elem.get( 'id' ), shed_tool_id=shed_tool_id )
except AssertionError, err:
@@ -876,22 +909,22 @@
for filename in os.listdir( self.get_filename( extra_value, shed_tool_id=shed_tool_id ) ):
files_list.append( ( filename, os.path.join( extra_value, filename ), extra_attributes ) )
else:
- raise ValueError, 'unknown extra_files type: %s' % extra_type
+ raise ValueError( 'unknown extra_files type: %s' % extra_type )
for filename, filepath, attributes in files_list:
self.verify_composite_datatype_file_content( filepath, hda_id, base_name=filename, attributes=attributes, shed_tool_id=shed_tool_id )
-
+
def verify_composite_datatype_file_content( self, file_name, hda_id, base_name=None, attributes=None, shed_tool_id=None ):
local_name = self.get_filename( file_name, shed_tool_id=shed_tool_id )
if base_name is None:
base_name = os.path.split(file_name)[-1]
- temp_name = self.makeTfname(fname = base_name)
+ temp_name = self.makeTfname(fname=base_name)
self.visit_url( "%s/datasets/%s/display/%s" % ( self.url, self.security.encode_id( hda_id ), base_name ) )
data = self.last_page()
file( temp_name, 'wb' ).write( data )
if self.keepOutdir > '':
- ofn = os.path.join(self.keepOutdir,base_name)
- shutil.copy(temp_name,ofn)
- log.debug('## GALAXY_TEST_SAVE=%s. saved %s' % (self.keepOutdir,ofn))
+ ofn = os.path.join(self.keepOutdir, base_name)
+ shutil.copy(temp_name, ofn)
+ log.debug('## GALAXY_TEST_SAVE=%s. saved %s' % (self.keepOutdir, ofn))
try:
# have to nest try-except in try-finally to handle 2.4
try:
@@ -905,13 +938,13 @@
elif compare == 're_match_multiline':
self.files_re_match_multiline( local_name, temp_name, attributes=attributes )
elif compare == 'sim_size':
- delta = attributes.get('delta','100')
+ delta = attributes.get('delta', '100')
s1 = len(data)
s2 = os.path.getsize(local_name)
- if abs(s1-s2) > int(delta):
- raise Exception, 'Files %s=%db but %s=%db - compare (delta=%s) failed' % (temp_name,s1,local_name,s2,delta)
+ if abs(s1 - s2) > int(delta):
+ raise Exception( 'Files %s=%db but %s=%db - compare (delta=%s) failed' % (temp_name, s1, local_name, s2, delta) )
else:
- raise Exception, 'Unimplemented Compare type: %s' % compare
+ raise Exception( 'Unimplemented Compare type: %s' % compare )
except AssertionError, err:
errmsg = 'Composite file (%s) of History item %s different than expected, difference (using %s):\n' % ( base_name, hda_id, compare )
errmsg += str( err )
@@ -925,7 +958,7 @@
return True
def is_binary( self, filename ):
- temp = open( filename, "U" ) # why is this not filename? Where did temp_name come from
+ temp = open( filename, "U" ) # why is this not filename? Where did temp_name come from
lineno = 0
for line in temp:
lineno += 1
@@ -949,7 +982,7 @@
# Functions associated with user accounts
def create( self, cntrller='user', email='test(a)bx.psu.edu', password='testuser', username='admin-user', redirect='' ):
- # HACK: don't use panels because late_javascripts() messes up the twill browser and it
+ # HACK: don't use panels because late_javascripts() messes up the twill browser and it
# can't find form fields (and hence user can't be logged in).
self.visit_url( "%s/user/create?cntrller=%s&use_panels=False" % ( self.url, cntrller ) )
tc.fv( 'registration', 'email', email )
@@ -980,6 +1013,7 @@
except:
pass
return previously_created, username_taken, invalid_username
+
def create_user_with_info( self, email, password, username, user_info_values, user_type_fd_id='', cntrller='user',
strings_displayed=[], strings_displayed_after_submit=[] ):
# This method creates a new user with associated info
@@ -998,6 +1032,7 @@
for check_str in strings_displayed:
self.check_page_for_string( check_str)
tc.submit( "create_user_button" )
+
def edit_user_info( self, cntrller='user', id='', new_email='', new_username='', password='', new_password='',
info_values=[], strings_displayed=[], strings_displayed_after_submit=[] ):
if cntrller == 'admin':
@@ -1021,51 +1056,53 @@
tc.submit( "change_password_button" )
if info_values:
for index, ( field_name, info_value ) in enumerate( info_values ):
- field_index = index + 1
tc.fv( "user_info", field_name, info_value )
tc.submit( "edit_user_info_button" )
for check_str in strings_displayed_after_submit:
self.check_page_for_string( check_str )
self.home()
+
def user_set_default_permissions( self, cntrller='user', permissions_out=[], permissions_in=[], role_id='2' ):
- # role.id = 2 is Private Role for test2(a)bx.psu.edu
- # NOTE: Twill has a bug that requires the ~/user/permissions page to contain at least 1 option value
+ # role.id = 2 is Private Role for test2(a)bx.psu.edu
+ # NOTE: Twill has a bug that requires the ~/user/permissions page to contain at least 1 option value
# in each select list or twill throws an exception, which is: ParseError: OPTION outside of SELECT
- # Due to this bug, we'll bypass visiting the page, and simply pass the permissions on to the
+ # Due to this bug, we'll bypass visiting the page, and simply pass the permissions on to the
# /user/set_default_permissions method.
url = "user/set_default_permissions?cntrller=%s&update_roles_button=Save&id=None" % cntrller
for po in permissions_out:
key = '%s_out' % po
- url ="%s&%s=%s" % ( url, key, str( role_id ) )
+ url = "%s&%s=%s" % ( url, key, str( role_id ) )
for pi in permissions_in:
key = '%s_in' % pi
- url ="%s&%s=%s" % ( url, key, str( role_id ) )
+ url = "%s&%s=%s" % ( url, key, str( role_id ) )
self.visit_url( "%s/%s" % ( self.url, url ) )
self.check_page_for_string( 'Default new history permissions have been changed.' )
self.home()
- def history_set_default_permissions( self, permissions_out=[], permissions_in=[], role_id=3 ): # role.id = 3 is Private Role for test3(a)bx.psu.edu
- # NOTE: Twill has a bug that requires the ~/user/permissions page to contain at least 1 option value
+
+ def history_set_default_permissions( self, permissions_out=[], permissions_in=[], role_id=3 ): # role.id = 3 is Private Role for test3(a)bx.psu.edu
+ # NOTE: Twill has a bug that requires the ~/user/permissions page to contain at least 1 option value
# in each select list or twill throws an exception, which is: ParseError: OPTION outside of SELECT
- # Due to this bug, we'll bypass visiting the page, and simply pass the permissions on to the
+ # Due to this bug, we'll bypass visiting the page, and simply pass the permissions on to the
# /user/set_default_permissions method.
url = "root/history_set_default_permissions?update_roles_button=Save&id=None&dataset=True"
for po in permissions_out:
key = '%s_out' % po
- url ="%s&%s=%s" % ( url, key, str( role_id ) )
+ url = "%s&%s=%s" % ( url, key, str( role_id ) )
for pi in permissions_in:
key = '%s_in' % pi
- url ="%s&%s=%s" % ( url, key, str( role_id ) )
+ url = "%s&%s=%s" % ( url, key, str( role_id ) )
self.home()
self.visit_url( "%s/%s" % ( self.url, url ) )
self.check_page_for_string( 'Default history permissions have been changed.' )
self.home()
+
def login( self, email='test(a)bx.psu.edu', password='testuser', username='admin-user', redirect='' ):
# test(a)bx.psu.edu is configured as an admin user
previously_created, username_taken, invalid_username = \
self.create( email=email, password=password, username=username, redirect=redirect )
if previously_created:
# The acount has previously been created, so just login.
- # HACK: don't use panels because late_javascripts() messes up the twill browser and it
+ # HACK: don't use panels because late_javascripts() messes up the twill browser and it
# can't find form fields (and hence user can't be logged in).
self.visit_url( "%s/user/login?use_panels=False" % self.url )
self.submit_form( 1, 'login_button', email=email, redirect=redirect, password=password )
@@ -1075,7 +1112,7 @@
self.visit_page( "user/logout" )
self.check_page_for_string( "You have been logged out" )
self.home()
-
+
# Functions associated with browsers, cookies, HTML forms and page visits
def check_for_strings( self, strings_displayed=[], strings_not_displayed=[] ):
@@ -1087,15 +1124,15 @@
self.check_string_not_in_page( string )
def check_page_for_string( self, patt ):
- """Looks for 'patt' in the current browser page"""
+ """Looks for 'patt' in the current browser page"""
page = self.last_page()
if page.find( patt ) == -1:
fname = self.write_temp_file( page )
errmsg = "no match to '%s'\npage content written to '%s'" % ( patt, fname )
raise AssertionError( errmsg )
-
+
def check_string_count_in_page( self, patt, min_count ):
- """Checks the number of 'patt' occurrences in the current browser page"""
+ """Checks the number of 'patt' occurrences in the current browser page"""
page = self.last_page()
patt_count = page.count( patt )
# The number of occurrences of patt in the page should be at least min_count
@@ -1104,15 +1141,15 @@
fname = self.write_temp_file( page )
errmsg = "%i occurrences of '%s' found instead of %i.\npage content written to '%s' " % ( min_count, patt, patt_count, fname )
raise AssertionError( errmsg )
-
+
def check_string_not_in_page( self, patt ):
- """Checks to make sure 'patt' is NOT in the page."""
+ """Checks to make sure 'patt' is NOT in the page."""
page = self.last_page()
if page.find( patt ) != -1:
fname = self.write_temp_file( page )
errmsg = "string (%s) incorrectly displayed in page.\npage content written to '%s'" % ( patt, fname )
raise AssertionError( errmsg )
-
+
def check_page(self, strings_displayed, strings_displayed_count, strings_not_displayed):
"""Checks a page for strings displayed, not displayed and number of occurrences of a string"""
for check_str in strings_displayed:
@@ -1122,7 +1159,6 @@
for check_str in strings_not_displayed:
self.check_string_not_in_page( check_str )
-
def write_temp_file( self, content, suffix='.html' ):
fd, fname = tempfile.mkstemp( suffix=suffix, prefix='twilltestcase-' )
f = os.fdopen( fd, "w" )
@@ -1174,50 +1210,50 @@
for i, control in enumerate( f.controls ):
formcontrols.append( "control %d: %s" % ( i, str( control ) ) )
for i, control in enumerate( f.controls ):
- if not hc_prefix in str( control ):
- try:
- #check if a repeat element needs to be added
- if control.name is not None:
- if control.name not in kwd and control.name.endswith( '_add' ):
- #control name doesn't exist, could be repeat
- repeat_startswith = control.name[0:-4]
- if repeat_startswith and not [ c_name for c_name in controls.keys() if c_name.startswith( repeat_startswith ) ] and [ c_name for c_name in kwd.keys() if c_name.startswith( repeat_startswith ) ]:
- tc.browser.clicked( f, control )
- tc.submit( control.name )
+ if not hc_prefix in str( control ):
+ try:
+ #check if a repeat element needs to be added
+ if control.name is not None:
+ if control.name not in kwd and control.name.endswith( '_add' ):
+ #control name doesn't exist, could be repeat
+ repeat_startswith = control.name[0:-4]
+ if repeat_startswith and not [ c_name for c_name in controls.keys() if c_name.startswith( repeat_startswith ) ] and [ c_name for c_name in kwd.keys() if c_name.startswith( repeat_startswith ) ]:
+ tc.browser.clicked( f, control )
+ tc.submit( control.name )
+ return self.submit_form( form_no=form_no, button=button, **kwd )
+ # Check for refresh_on_change attribute, submit a change if required
+ if hasattr( control, 'attrs' ) and 'refresh_on_change' in control.attrs.keys():
+ changed = False
+ # For DataToolParameter, control.value is the HDA id, but kwd contains the filename.
+ # This loop gets the filename/label for the selected values.
+ item_labels = [ item.attrs[ 'label' ] for item in control.get_items() if item.selected ]
+ for value in kwd[ control.name ]:
+ if value not in control.value and True not in [ value in item_label for item_label in item_labels ]:
+ changed = True
+ break
+ if changed:
+ # Clear Control and set to proper value
+ control.clear()
+ # kwd[control.name] should be a singlelist
+ for elem in kwd[ control.name ]:
+ tc.fv( f.name, control.name, str( elem ) )
+ # Create a new submit control, allows form to refresh, instead of going to next page
+ control = ClientForm.SubmitControl( 'SubmitControl', '___refresh_grouping___', {'name': 'refresh_grouping'} )
+ control.add_to_form( f )
+ control.fixup()
+ # Submit for refresh
+ tc.submit( '___refresh_grouping___' )
return self.submit_form( form_no=form_no, button=button, **kwd )
- # Check for refresh_on_change attribute, submit a change if required
- if hasattr( control, 'attrs' ) and 'refresh_on_change' in control.attrs.keys():
- changed = False
- # For DataToolParameter, control.value is the HDA id, but kwd contains the filename.
- # This loop gets the filename/label for the selected values.
- item_labels = [ item.attrs[ 'label' ] for item in control.get_items() if item.selected ]
- for value in kwd[ control.name ]:
- if value not in control.value and True not in [ value in item_label for item_label in item_labels ]:
- changed = True
- break
- if changed:
- # Clear Control and set to proper value
- control.clear()
- # kwd[control.name] should be a singlelist
- for elem in kwd[ control.name ]:
- tc.fv( f.name, control.name, str( elem ) )
- # Create a new submit control, allows form to refresh, instead of going to next page
- control = ClientForm.SubmitControl( 'SubmitControl', '___refresh_grouping___', {'name':'refresh_grouping'} )
- control.add_to_form( f )
- control.fixup()
- # Submit for refresh
- tc.submit( '___refresh_grouping___' )
- return self.submit_form( form_no=form_no, button=button, **kwd )
- except Exception, e:
- log.exception( "In submit_form, continuing, but caught exception." )
- for formcontrol in formcontrols:
- log.debug( formcontrol )
- continue
- controls[ control.name ] = control
+ except Exception:
+ log.exception( "In submit_form, continuing, but caught exception." )
+ for formcontrol in formcontrols:
+ log.debug( formcontrol )
+ continue
+ controls[ control.name ] = control
# No refresh_on_change attribute found in current form, so process as usual
for control_name, control_value in kwd.items():
if control_name not in controls:
- continue # these cannot be handled safely - cause the test to barf out
+ continue # these cannot be handled safely - cause the test to barf out
if not isinstance( control_value, list ):
control_value = [ control_value ]
control = controls[ control_name ]
@@ -1247,7 +1283,7 @@
else:
for elem in control_value:
control.get( name=elem ).selected = True
- else: # control.is_of_kind( "singlelist" )
+ else: # control.is_of_kind( "singlelist" )
for elem in control_value:
try:
tc.fv( f.name, control.name, str( elem ) )
@@ -1298,15 +1334,16 @@
control.clear()
tc.fv( f.name, control.name, value )
# Create a new submit control, allows form to refresh, instead of going to next page
- control = ClientForm.SubmitControl( 'SubmitControl', '___refresh_grouping___', {'name':'refresh_grouping'} )
+ control = ClientForm.SubmitControl( 'SubmitControl', '___refresh_grouping___', {'name': 'refresh_grouping'} )
control.add_to_form( f )
control.fixup()
# Submit for refresh
tc.submit( '___refresh_grouping___' )
+
def visit_page( self, page ):
# tc.go("./%s" % page)
if not page.startswith( "/" ):
- page = "/" + page
+ page = "/" + page
tc.go( self.url + page )
tc.code( 200 )
@@ -1322,7 +1359,7 @@
if repeat_name is not None:
repeat_button = '%s_add' % repeat_name
# Must click somewhere in tool_form, to disambiguate what form
- # is being targetted.
+ # is being targetted.
tc.browser.clicked( tc.browser.get_form( 'tool_form' ), None )
# Submit the "repeat" form button to add an input)
tc.submit( repeat_button )
@@ -1336,9 +1373,9 @@
galaxy_url = urllib.quote_plus( "%s/tool_runner/index?" % self.url )
self.visit_url( "http://genome.ucsc.edu/cgi-bin/hgTables?GALAXY_URL=%s&hgta_compressType=non…" % ( galaxy_url, tool_id, track_string ) )
tc.fv( "mainForm", "hgta_doTopSubmit", "get output" )
- self.submit_form( button="get output" )#, **track_params )
+ self.submit_form( button="get output" )
tc.fv( 2, "hgta_doGalaxyQuery", "Send query to Galaxy" )
- self.submit_form( button="Send query to Galaxy" )#, **output_params ) #AssertionError: Attempting to set field 'fbQual' to value '['whole']' in form 'None' threw exception: no matching forms! control: <RadioControl(fbQual=[whole, upstreamAll, endAll])>
+ self.submit_form( button="Send query to Galaxy" )
def get_running_datasets( self ):
self.visit_url( '/api/histories' )
@@ -1363,7 +1400,7 @@
slept += sleep_amount
sleep_amount *= 2
if slept + sleep_amount > maxseconds:
- sleep_amount = maxseconds - slept # don't overshoot maxseconds
+ sleep_amount = maxseconds - slept # don't overshoot maxseconds
else:
break
assert slept < maxseconds
@@ -1373,7 +1410,7 @@
def create_new_account_as_admin( self, email='test4(a)bx.psu.edu', password='testuser',
username='regular-user4', redirect='' ):
"""Create a new account for another user"""
- # HACK: don't use panels because late_javascripts() messes up the twill browser and it
+ # HACK: don't use panels because late_javascripts() messes up the twill browser and it
# can't find form fields (and hence user can't be logged in).
self.visit_url( "%s/user/create?cntrller=admin" % self.url )
self.submit_form( 1, 'create_user_button', email=email, redirect=redirect, password=password, confirm=password, username=username )
@@ -1409,6 +1446,7 @@
tc.submit( "reset_user_password_button" )
self.check_page_for_string( "Passwords reset for 1 user." )
self.home()
+
def mark_user_deleted( self, user_id, email='' ):
"""Mark a user as deleted"""
self.home()
@@ -1416,6 +1454,7 @@
check_str = "Deleted 1 users"
self.check_page_for_string( check_str )
self.home()
+
def undelete_user( self, user_id, email='' ):
"""Undelete a user"""
self.home()
@@ -1423,6 +1462,7 @@
check_str = "Undeleted 1 users"
self.check_page_for_string( check_str )
self.home()
+
def purge_user( self, user_id, email ):
"""Purge a user account"""
self.home()
@@ -1430,6 +1470,7 @@
check_str = "Purged 1 users"
self.check_page_for_string( check_str )
self.home()
+
def manage_roles_and_groups_for_user( self, user_id, in_role_ids=[], out_role_ids=[],
in_group_ids=[], out_group_ids=[], strings_displayed=[] ):
self.home()
@@ -1448,12 +1489,13 @@
for check_str in strings_displayed:
self.check_page_for_string( check_str )
self.home()
+ # Tests associated with roles
- # Tests associated with roles
def browse_roles( self, strings_displayed=[] ):
self.visit_url( '%s/admin/roles' % self.url )
for check_str in strings_displayed:
self.check_page_for_string( check_str )
+
def create_role( self,
name='Role One',
description="This is Role One",
@@ -1488,6 +1530,7 @@
self.visit_url( "%s/admin/roles" % self.url )
self.check_page_for_string( name )
self.home()
+
def rename_role( self, role_id, name='Role One Renamed', description='This is Role One Re-described' ):
"""Rename a role"""
self.home()
@@ -1497,6 +1540,7 @@
tc.fv( "1", "description", description )
tc.submit( "rename_role_button" )
self.home()
+
def mark_role_deleted( self, role_id, role_name ):
"""Mark a role as deleted"""
self.home()
@@ -1504,6 +1548,7 @@
check_str = "Deleted 1 roles: %s" % role_name
self.check_page_for_string( check_str )
self.home()
+
def undelete_role( self, role_id, role_name ):
"""Undelete an existing role"""
self.home()
@@ -1511,6 +1556,7 @@
check_str = "Undeleted 1 roles: %s" % role_name
self.check_page_for_string( check_str )
self.home()
+
def purge_role( self, role_id, role_name ):
"""Purge an existing role"""
self.home()
@@ -1518,6 +1564,7 @@
check_str = "Purged 1 roles: %s" % role_name
self.check_page_for_string( check_str )
self.home()
+
def associate_users_and_groups_with_role( self, role_id, role_name, user_ids=[], group_ids=[] ):
self.home()
url = "%s/admin/role?id=%s&role_members_edit_button=Save" % ( self.url, role_id )
@@ -1548,10 +1595,12 @@
self.visit_url( "%s/admin/groups" % self.url )
self.check_page_for_string( name )
self.home()
+
def browse_groups( self, strings_displayed=[] ):
self.visit_url( '%s/admin/groups' % self.url )
for check_str in strings_displayed:
self.check_page_for_string( check_str )
+
def rename_group( self, group_id, name='Group One Renamed' ):
"""Rename a group"""
self.home()
@@ -1560,6 +1609,7 @@
tc.fv( "1", "name", name )
tc.submit( "rename_group_button" )
self.home()
+
def associate_users_and_roles_with_group( self, group_id, group_name, user_ids=[], role_ids=[] ):
self.home()
url = "%s/admin/manage_users_and_roles_for_group?id=%s&group_roles_users_edit_button=Save" % ( self.url, group_id )
@@ -1571,6 +1621,7 @@
check_str = "Group '%s' has been updated with %d associated roles and %d associated users" % ( group_name, len( role_ids ), len( user_ids ) )
self.check_page_for_string( check_str )
self.home()
+
def mark_group_deleted( self, group_id, group_name ):
"""Mark a group as deleted"""
self.home()
@@ -1578,6 +1629,7 @@
check_str = "Deleted 1 groups: %s" % group_name
self.check_page_for_string( check_str )
self.home()
+
def undelete_group( self, group_id, group_name ):
"""Undelete an existing group"""
self.home()
@@ -1585,6 +1637,7 @@
check_str = "Undeleted 1 groups: %s" % group_name
self.check_page_for_string( check_str )
self.home()
+
def purge_group( self, group_id, group_name ):
"""Purge an existing group"""
self.home()
@@ -1628,7 +1681,7 @@
if num_options == 0:
# Default to 2 options
num_options = 2
- for index2 in range( 1, num_options+1 ):
+ for index2 in range( 1, num_options + 1 ):
tc.submit( "addoption_0" )
# Add contents to the new options fields
for index2 in range( num_options ):
@@ -1644,6 +1697,7 @@
for check_str in strings_displayed_after_submit:
self.check_page_for_string( check_str )
self.home()
+
def edit_form( self, id, form_type='', new_form_name='', new_form_desc='', field_dicts=[], field_index=0,
strings_displayed=[], strings_not_displayed=[], strings_displayed_after_submit=[] ):
"""Edit form details; name and description"""
@@ -1771,10 +1825,10 @@
url = "request_type/request_type_permissions?id=%s&update_roles_button=Save" % ( request_type_id )
for po in permissions_out:
key = '%s_out' % po
- url ="%s&%s=%s" % ( url, key, role_ids_str )
+ url = "%s&%s=%s" % ( url, key, role_ids_str )
for pi in permissions_in:
key = '%s_in' % pi
- url ="%s&%s=%s" % ( url, key, role_ids_str )
+ url = "%s&%s=%s" % ( url, key, role_ids_str )
self.home()
self.visit_url( "%s/%s" % ( self.url, url ) )
check_str = "Permissions updated for request type '%s'" % request_type_name
@@ -2080,7 +2134,7 @@
for check_str in strings_not_displayed:
try:
self.check_page_for_string( check_str )
- raise AssertionError, "String (%s) incorrectly displayed when browing library." % check_str
+ raise AssertionError( "String (%s) incorrectly displayed when browing library." % check_str )
except:
pass
def browse_libraries_regular_user( self, strings_displayed=[], strings_not_displayed=[] ):
@@ -2090,7 +2144,7 @@
for check_str in strings_not_displayed:
try:
self.check_page_for_string( check_str )
- raise AssertionError, "String (%s) incorrectly displayed when browing library." % check_str
+ raise AssertionError( "String (%s) incorrectly displayed when browing library." % check_str )
except:
pass
def browse_library( self, cntrller, library_id, show_deleted=False, strings_displayed=[], strings_not_displayed=[] ):
@@ -2100,7 +2154,7 @@
for check_str in strings_not_displayed:
try:
self.check_page_for_string( check_str )
- raise AssertionError, "String (%s) incorrectly displayed when browing library." % check_str
+ raise AssertionError( "String (%s) incorrectly displayed when browing library." % check_str )
except:
pass
def create_library( self, name='Library One', description='This is Library One', synopsis='Synopsis for Library One' ):
@@ -2156,10 +2210,10 @@
url = "library_common/library_permissions?id=%s&cntrller=%s&update_roles_button=Save" % ( library_id, cntrller )
for po in permissions_out:
key = '%s_out' % po
- url ="%s&%s=%s" % ( url, key, role_ids_str )
+ url = "%s&%s=%s" % ( url, key, role_ids_str )
for pi in permissions_in:
key = '%s_in' % pi
- url ="%s&%s=%s" % ( url, key, role_ids_str )
+ url = "%s&%s=%s" % ( url, key, role_ids_str )
self.home()
self.visit_url( "%s/%s" % ( self.url, url ) )
check_str = "Permissions updated for library '%s'." % library_name
@@ -2208,7 +2262,7 @@
for check_str in strings_not_displayed:
try:
self.check_page_for_string( check_str )
- raise AssertionError, "String (%s) incorrectly displayed." % check_str
+ raise AssertionError( "String (%s) incorrectly displayed." % check_str )
except:
pass
if template_refresh_field_contents:
@@ -2227,7 +2281,7 @@
for check_str in strings_not_displayed_after_submit:
try:
self.check_page_for_string( check_str )
- raise AssertionError, "String (%s) incorrectly displayed." % check_str
+ raise AssertionError( "String (%s) incorrectly displayed." % check_str )
except:
pass
self.home()
@@ -2301,10 +2355,10 @@
( self.url, cntrller, library_id, folder_id, id )
for po in permissions_out:
key = '%s_out' % po
- url ="%s&%s=%s" % ( url, key, role_ids_str )
+ url = "%s&%s=%s" % ( url, key, role_ids_str )
for pi in permissions_in:
key = '%s_in' % pi
- url ="%s&%s=%s" % ( url, key, role_ids_str )
+ url = "%s&%s=%s" % ( url, key, role_ids_str )
if permissions_in or permissions_out:
url += "&update_roles_button=Save"
self.visit_url( url )
@@ -2322,7 +2376,7 @@
for check_str in strings_not_displayed:
try:
self.check_page_for_string( check_str )
- raise AssertionError, "String (%s) should not have been displayed on ldda info page." % check_str
+ raise AssertionError( "String (%s) should not have been displayed on ldda info page." % check_str )
except:
pass
self.home()
@@ -2354,7 +2408,7 @@
for check_str in strings_not_displayed:
try:
self.check_page_for_string( check_str )
- raise AssertionError, "String (%s) should not have been displayed on ldda Edit Attributes page." % check_str
+ raise AssertionError( "String (%s) should not have been displayed on ldda Edit Attributes page." % check_str )
except:
pass
self.home()
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: Dave Bouvier: Remove reference to undefined variable.
by commits-noreply@bitbucket.org 15 Nov '13
by commits-noreply@bitbucket.org 15 Nov '13
15 Nov '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/a231103b3d6e/
Changeset: a231103b3d6e
User: Dave Bouvier
Date: 2013-11-15 00:43:58
Summary: Remove reference to undefined variable.
Affected #: 1 file
diff -r 51d3b2de1ed31ad118e939c360f82362d1c10927 -r a231103b3d6e14578a226f9f6d5a3b68c0896854 test/install_and_test_tool_shed_repositories/functional_tests.py
--- a/test/install_and_test_tool_shed_repositories/functional_tests.py
+++ b/test/install_and_test_tool_shed_repositories/functional_tests.py
@@ -696,8 +696,6 @@
if os.path.exists( tool_dependency_install_path ):
log.debug( 'Uninstallation of tool dependency succeeded, but the installation path still exists on the filesystem. It is now being explicitly deleted.')
suc.remove_dir( tool_dependency_install_path )
- return success
-
def main():
# ---- Configuration ------------------------------------------------------
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: Dave Bouvier: Remove a return that was added while debugging.
by commits-noreply@bitbucket.org 14 Nov '13
by commits-noreply@bitbucket.org 14 Nov '13
14 Nov '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/51d3b2de1ed3/
Changeset: 51d3b2de1ed3
User: Dave Bouvier
Date: 2013-11-14 23:50:54
Summary: Remove a return that was added while debugging.
Affected #: 1 file
diff -r fbbc387df15a317f0e1df50ba8e76cec2750a66a -r 51d3b2de1ed31ad118e939c360f82362d1c10927 test/install_and_test_tool_shed_repositories/functional_tests.py
--- a/test/install_and_test_tool_shed_repositories/functional_tests.py
+++ b/test/install_and_test_tool_shed_repositories/functional_tests.py
@@ -580,7 +580,6 @@
'''
Update the repository metadata tool_test_results and appropriate flags using the API.
'''
- return {}
params[ 'tool_test_results' ] = test_results_dict
if '-info_only' in sys.argv or 'GALAXY_INSTALL_TEST_INFO_ONLY' in os.environ:
return {}
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
14 Nov '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/fbbc387df15a/
Changeset: fbbc387df15a
User: Dave Bouvier
Date: 2013-11-14 23:37:27
Summary: Fix broken import.
Affected #: 1 file
diff -r 255958e985f9a2e4942a439a08a1dfe3afd9d439 -r fbbc387df15a317f0e1df50ba8e76cec2750a66a test/install_and_test_tool_shed_repositories/functional_tests.py
--- a/test/install_and_test_tool_shed_repositories/functional_tests.py
+++ b/test/install_and_test_tool_shed_repositories/functional_tests.py
@@ -13,7 +13,6 @@
import random
import re
import shutil
-import simplejson
import socket
import string
import sys
@@ -54,6 +53,7 @@
eggs.require( "Cheetah" )
eggs.require( "simplejson" )
+import simplejson
import twill
# This should not be required, but it is under certain conditions, thanks to this bug: http://code.google.com/p/python-nose/issues/detail?id=284
@@ -1348,4 +1348,4 @@
print "####################################################################################"
print "# %s - running repository installation and testing script." % now
print "####################################################################################"
- sys.exit( main() )
\ No newline at end of file
+ sys.exit( main() )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: Dave Bouvier: Correct wrong method call.
by commits-noreply@bitbucket.org 14 Nov '13
by commits-noreply@bitbucket.org 14 Nov '13
14 Nov '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/255958e985f9/
Changeset: 255958e985f9
User: Dave Bouvier
Date: 2013-11-14 23:00:11
Summary: Correct wrong method call.
Affected #: 1 file
diff -r cfeb9bd79fe11f6db6600e4c3e28c106e7837a19 -r 255958e985f9a2e4942a439a08a1dfe3afd9d439 test/install_and_test_tool_shed_repositories/functional_tests.py
--- a/test/install_and_test_tool_shed_repositories/functional_tests.py
+++ b/test/install_and_test_tool_shed_repositories/functional_tests.py
@@ -367,7 +367,7 @@
for repository_dependency in repository.repository_dependencies:
if not repository_dependency.includes_tool_dependencies:
continue
- missing_tool_dependencies.extend( get_failed_tool_dependencies( repository_dependency ) )
+ missing_tool_dependencies.extend( get_missing_tool_dependencies( repository_dependency ) )
return missing_tool_dependencies
def get_repository_info_from_api( url, repository_info_dict ):
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: Dave Bouvier: Substantial refactoring of the install and test framework to address a number of weaknesses.
by commits-noreply@bitbucket.org 14 Nov '13
by commits-noreply@bitbucket.org 14 Nov '13
14 Nov '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/cfeb9bd79fe1/
Changeset: cfeb9bd79fe1
User: Dave Bouvier
Date: 2013-11-14 22:52:06
Summary: Substantial refactoring of the install and test framework to address a number of weaknesses.
Affected #: 4 files
diff -r ca7110d331571b4a3bbfdd75037053ea4c40b746 -r cfeb9bd79fe11f6db6600e4c3e28c106e7837a19 test/install_and_test_tool_shed_repositories/base/test_db_util.py
--- a/test/install_and_test_tool_shed_repositories/base/test_db_util.py
+++ b/test/install_and_test_tool_shed_repositories/base/test_db_util.py
@@ -30,6 +30,12 @@
model.ToolShedRepository.table.c.installed_changeset_revision == changeset_revision ) ) \
.one()
+def get_missing_tool_dependencies( repository ):
+ return sa_session.query( model.ToolDependency ) \
+ .filter( and_( model.ToolDependency.table.c.tool_shed_repository_id == repository_id,
+ model.ToolDependency.table.c.status != model.ToolDependency.installation_status.INSTALLED ) ) \
+ .all()
+
def get_private_role( user ):
for role in user.all_roles():
if role.name == user.email and role.description == 'Private Role for %s' % user.email:
diff -r ca7110d331571b4a3bbfdd75037053ea4c40b746 -r cfeb9bd79fe11f6db6600e4c3e28c106e7837a19 test/install_and_test_tool_shed_repositories/base/twilltestcase.py
--- a/test/install_and_test_tool_shed_repositories/base/twilltestcase.py
+++ b/test/install_and_test_tool_shed_repositories/base/twilltestcase.py
@@ -61,8 +61,7 @@
changeset_revision = repository_info_dict[ 'changeset_revision' ]
encoded_repository_id = repository_info_dict[ 'repository_id' ]
tool_shed_url = repository_info_dict[ 'tool_shed_url' ]
- preview_params = urllib.urlencode( dict( repository_id=encoded_repository_id, changeset_revision=changeset_revision ) )
- self.visit_url( '%s/repository/preview_tools_in_changeset?%s' % ( tool_shed_url, preview_params ) )
+ # Pass galaxy_url to the tool shed in order to set cookies and redirects correctly.
install_params = urllib.urlencode( dict( repository_ids=encoded_repository_id,
changeset_revisions=changeset_revision,
galaxy_url=self.url ) )
@@ -136,35 +135,17 @@
break
time.sleep( 1 )
- def uninstall_repository( self, installed_repository, deactivate_only=False ):
+ def deactivate_or_uninstall_repository( self, installed_repository, deactivate=False ):
url = '/admin_toolshed/deactivate_or_uninstall_repository?id=%s' % self.security.encode_id( installed_repository.id )
self.visit_url( url )
- if deactivate_only:
+ if deactivate:
tc.fv ( 1, "remove_from_disk", 'false' )
else:
tc.fv ( 1, "remove_from_disk", 'true' )
tc.submit( 'deactivate_or_uninstall_repository_button' )
strings_displayed = [ 'The repository named' ]
- if deactivate_only:
+ if deactivate:
strings_displayed.append( 'has been deactivated' )
else:
strings_displayed.append( 'has been uninstalled' )
self.check_for_strings( strings_displayed, strings_not_displayed=[] )
- # Get all tool dependencies that are not in an installed state and uninstall them explicitly, so that the next installation attempt
- # may succeed.
- installed_state = model.ToolDependency.installation_status.INSTALLED
- tool_dependencies = test_db_util.get_tool_dependencies_for_installed_repository( installed_repository.id, exclude_status=installed_state )
- if len( tool_dependencies ) > 0:
- encoded_tool_dependency_ids = [ self.security.encode_id( tool_dependency.id ) for tool_dependency in tool_dependencies ]
- self.uninstall_tool_dependencies( self.security.encode_id( installed_repository.id ), encoded_tool_dependency_ids )
-
- def uninstall_tool_dependencies( self, encoded_repository_id, encoded_tool_dependency_ids ):
- tool_dependency_ids = ','.join( encoded_tool_dependency_ids )
- url = '/admin_toolshed/uninstall_tool_dependencies?repository_id=%s&inst_td_ids=%s&operation=uninstall' % \
- ( encoded_repository_id, tool_dependency_ids )
- self.visit_url( url )
- html = self.last_page()
- if 'uninstall_tool_dependencies' in html:
- tc.fv( 'uninstall_tool_dependencies', 'tool_dependency_ids', tool_dependency_ids )
- tc.submit( 'uninstall_tool_dependencies_button' )
-
\ No newline at end of file
diff -r ca7110d331571b4a3bbfdd75037053ea4c40b746 -r cfeb9bd79fe11f6db6600e4c3e28c106e7837a19 test/install_and_test_tool_shed_repositories/functional/test_install_repositories.py
--- a/test/install_and_test_tool_shed_repositories/functional/test_install_repositories.py
+++ b/test/install_and_test_tool_shed_repositories/functional/test_install_repositories.py
@@ -16,7 +16,7 @@
# Install the repository through the web interface using twill.
self.install_repository( repository_info_dict )
- def do_uninstallation( self, repository_info_dict, deactivate_only=False ):
+ def do_deactivate_or_uninstall( self, repository_info_dict, deactivate=False ):
self.logout()
self.login( email='test(a)bx.psu.edu', username='test' )
admin_user = test_db_util.get_user( 'test(a)bx.psu.edu' )
@@ -27,7 +27,7 @@
repository_info_dict[ 'changeset_revision' ] )
admin_user_private_role = test_db_util.get_private_role( admin_user )
# Uninstall the repository through the web interface using twill.
- self.uninstall_repository( repository, deactivate_only )
+ self.deactivate_or_uninstall_repository( repository, deactivate )
def generate_install_method( repository_dict=None ):
"""Generate abstract test cases for the defined list of repositories."""
@@ -52,11 +52,11 @@
namespace[ 'install_repository_%s' % repository_dict[ 'name' ] ] = test_method
# The new.classobj function returns a new class object, with name name, derived
# from baseclasses (which should be a tuple of classes) and with namespace dict.
- new_class_obj = new.classobj( name, baseclasses, namespace )
+ new_class_obj = new.classobj( str( name ), baseclasses, namespace )
G[ name ] = new_class_obj
-def generate_uninstall_method( repository_dict=None, deactivate_only=False ):
- """Generate abstract test cases for the defined list of repositories."""
+def generate_deactivate_or_uninstall_method( repository_dict=None, deactivate=False ):
+ """Generate abstract test cases for the received repository_dict."""
if repository_dict is None:
return
# Push all the toolbox tests to module level
@@ -69,14 +69,15 @@
name = "TestUninstallRepository_%s_%s" % ( repository_dict[ 'name' ], repository_dict[ 'changeset_revision' ] )
baseclasses = ( InstallTestRepositories, )
namespace = dict()
- def make_uninstall_method( repository_dict ):
+ def make_deactivate_or_uninstall_method( repository_dict ):
def test_install_repository( self ):
- self.do_uninstallation( repository_dict, deactivate_only )
+ self.do_deactivate_or_uninstall( repository_dict, deactivate )
return test_install_repository
- test_method = make_uninstall_method( repository_dict )
- test_method.__doc__ = "Uninstall the repository %s." % repository_dict[ 'name' ]
- namespace[ 'uninstall_repository_%s_%s' % ( repository_dict[ 'name' ], repository_dict[ 'changeset_revision' ] ) ] = test_method
+ test_method = make_deactivate_or_uninstall_method( repository_dict )
+ test_method.__doc__ = "Deactivate or uninstall the repository %s." % repository_dict[ 'name' ]
+ namespace[ 'uninstall_repository_%s_%s' % ( str( repository_dict[ 'name' ] ), repository_dict[ 'changeset_revision' ] ) ] = test_method
# The new.classobj function returns a new class object, with name name, derived
# from baseclasses (which should be a tuple of classes) and with namespace dict.
- new_class_obj = new.classobj( name, baseclasses, namespace )
- G[ name ] = new_class_obj
\ No newline at end of file
+ new_class_obj = new.classobj( str( name ), baseclasses, namespace )
+ G[ name ] = new_class_obj
+
diff -r ca7110d331571b4a3bbfdd75037053ea4c40b746 -r cfeb9bd79fe11f6db6600e4c3e28c106e7837a19 test/install_and_test_tool_shed_repositories/functional_tests.py
--- a/test/install_and_test_tool_shed_repositories/functional_tests.py
+++ b/test/install_and_test_tool_shed_repositories/functional_tests.py
@@ -4,7 +4,25 @@
# order to run functional tests on repository tools after installation. The install_and_test_tool_shed_repositories.sh
# will execute this script with the appropriate parameters.
-import os, sys, shutil, tempfile, re, string, urllib, platform
+import atexit
+import httplib
+import logging
+import os
+import os.path
+import platform
+import random
+import re
+import shutil
+import simplejson
+import socket
+import string
+import sys
+import tempfile
+import time
+import threading
+import unittest
+import urllib
+import urllib2
from time import strftime
# Assume we are run from the galaxy root directory, add lib to the python path
@@ -36,6 +54,8 @@
eggs.require( "Cheetah" )
eggs.require( "simplejson" )
+import twill
+
# This should not be required, but it is under certain conditions, thanks to this bug: http://code.google.com/p/python-nose/issues/detail?id=284
eggs.require( "pysqlite" )
@@ -43,20 +63,17 @@
import install_and_test_tool_shed_repositories.base.test_db_util as test_db_util
import functional.test_toolbox as test_toolbox
-import atexit, logging, os, os.path, sys, tempfile, simplejson
-import twill, unittest, time
-import sys, threading, random
-import httplib, socket
from paste import httpserver
# This is for the galaxy application.
import galaxy.app
from galaxy.app import UniverseApplication
from galaxy.web import buildapp
-from galaxy.util import parse_xml
+from galaxy.util import parse_xml, asbool
from galaxy.util.json import from_json_string, to_json_string
-from tool_shed.util.shed_util_common import url_join
+import tool_shed.util.shed_util_common as suc
+from tool_shed.util import tool_dependency_util
import nose.core
import nose.config
@@ -243,27 +260,29 @@
return passed_tests
return []
-def execute_uninstall_method( app, deactivate_only=False ):
- # Clean out any generated tests.
+def deactivate_repository( app, repository_info_dict ):
+ # Clean out any generated tests. This is necessary for Twill.
remove_generated_tests( app )
sa_session = app.model.context.current
- repositories_to_uninstall = sa_session.query( app.model.ToolShedRepository ).all()
- for repository in repositories_to_uninstall:
- if repository.status in [ app.model.ToolShedRepository.installation_status.UNINSTALLED,
- app.model.ToolShedRepository.installation_status.DEACTIVATED ]:
- continue
- if repository.status not in [ app.model.ToolShedRepository.installation_status.ERROR,
- app.model.ToolShedRepository.installation_status.INSTALLED ]:
- repository.status = app.model.ToolShedRepository.installation_status.ERROR
- sa_session.add( repository )
- sa_session.flush()
- name = str( repository.name )
- owner = str( repository.owner )
- changeset_revision = str( repository.installed_changeset_revision )
- log.debug( 'Changeset revision %s of %s repository %s queued for uninstallation.', changeset_revision, repository.status, name )
- repository_dict = dict( name=name, owner=owner, changeset_revision=changeset_revision )
+ # The dict contains the only repository the app should have installed at this point.
+ repository = test_db_util.get_installed_repository_by_name_owner_changeset_revision( repository_info_dict[ 'name' ],
+ repository_info_dict[ 'owner' ],
+ repository_info_dict[ 'changeset_revision' ] )
+ # We have to do this through Twill, in order to maintain app.toolbox and shed_tool_conf.xml in a state that is valid for future tests.
+ for required_repository in repository.repository_dependencies:
+ repository_dict = dict( name=required_repository.name,
+ owner=required_repository.owner,
+ changeset_revision=required_repository.changeset_revision )
# Generate a test method to uninstall this repository through the embedded Galaxy application's web interface.
- test_install_repositories.generate_uninstall_method( repository_dict, deactivate_only )
+ test_install_repositories.generate_deactivate_or_uninstall_method( repository_dict, deactivate=True )
+ log.debug( 'Changeset revision %s of %s repository %s selected for deactivation.' % \
+ ( required_repository.changeset_revision, required_repository.status, required_repository.name ) )
+ repository_dict = dict( name=repository.name,
+ owner=repository.owner,
+ changeset_revision=repository.changeset_revision )
+ test_install_repositories.generate_deactivate_or_uninstall_method( repository_dict, deactivate=True )
+ log.debug( 'Changeset revision %s of %s repository %s selected for deactivation.' % \
+ ( repository.changeset_revision, repository.status, repository.name ) )
# Set up nose to run the generated uninstall method as a functional test.
test_config = nose.config.Config( env=os.environ, plugins=nose.plugins.manager.DefaultPluginManager() )
test_config.configure( sys.argv )
@@ -324,7 +343,7 @@
parts.insert( 0, 'api' )
elif 'api' not in parts:
parts.insert( 0, 'api' )
- url = url_join( base, *parts )
+ url = suc.url_join( base, *parts )
if key:
url += '?%s' % urllib.urlencode( dict( key=key ) )
else:
@@ -333,14 +352,6 @@
url += '&%s' % params
return url
-def get_failed_tool_dependencies( repository ):
- missing_dependencies = repository.missing_tool_dependencies
- for repository_dependency in repository.repository_dependencies:
- if not repository_dependency.includes_tool_dependencies:
- continue
- missing_dependencies.extend( get_failed_tool_dependencies( repository_dependency ) )
- return missing_dependencies
-
def get_latest_downloadable_changeset_revision( url, name, owner ):
api_url_parts = [ 'api', 'repositories', 'get_ordered_installable_revisions' ]
params = urllib.urlencode( dict( name=name, owner=owner ) )
@@ -351,6 +362,14 @@
else:
return '000000000000'
+def get_missing_tool_dependencies( repository ):
+ missing_tool_dependencies = repository.missing_tool_dependencies
+ for repository_dependency in repository.repository_dependencies:
+ if not repository_dependency.includes_tool_dependencies:
+ continue
+ missing_tool_dependencies.extend( get_failed_tool_dependencies( repository_dependency ) )
+ return missing_tool_dependencies
+
def get_repository_info_from_api( url, repository_info_dict ):
parts = [ 'api', 'repositories', repository_info_dict[ 'repository_id' ] ]
api_url = get_api_url( base=url, parts=parts )
@@ -459,6 +478,37 @@
return dict()
return tool_test_results
+def install_repository( repository_info_dict ):
+ """
+ The repository_info_dict looks something like:
+ {
+ "changeset_revision": "13fa22a258b5",
+ "contents_url": "/api/repositories/529fd61ab1c6cc36/contents",
+ "deleted": false,
+ "deprecated": false,
+ "description": "Convert column case.",
+ "downloadable": true,
+ "id": "529fd61ab1c6cc36",
+ "long_description": "This tool takes the specified columns and converts them to uppercase or lowercase.",
+ "malicious": false,
+ "name": "change_case",
+ "owner": "test",
+ "private": false,
+ "repository_id": "529fd61ab1c6cc36",
+ "times_downloaded": 0,
+ "tool_shed_url": "http://toolshed.local:10001",
+ "url": "/api/repository_revisions/529fd61ab1c6cc36",
+ "user_id": "529fd61ab1c6cc36"
+ }
+ """
+ data[ 'tool_shed_url' ] = repository_info_dict[ 'tool_shed_url' ]
+ data[ 'name' ] = repository_info_dict[ 'name' ]
+ data[ 'owner' ] = repository_info_dict[ 'owner' ]
+ data[ 'changeset_revision' ] = repository_info_dict[ 'changeset_revision' ]
+ data[ 'install_repository_dependencies' ] = True
+ data[ 'install_tool_dependencies' ] = True
+ submit( options.api, '%s%s' % ( galaxy_url.strip( '/' ), '/api/tool_shed_repositories/new/install_repository_revision' ), data )
+
def is_latest_downloadable_revision( url, repository_info_dict ):
latest_revision = get_latest_downloadable_changeset_revision( url, name=repository_info_dict[ 'name' ], owner=repository_info_dict[ 'owner' ] )
return str( repository_info_dict[ 'changeset_revision' ] ) == str( latest_revision )
@@ -530,11 +580,12 @@
'''
Update the repository metadata tool_test_results and appropriate flags using the API.
'''
+ return {}
params[ 'tool_test_results' ] = test_results_dict
if '-info_only' in sys.argv or 'GALAXY_INSTALL_TEST_INFO_ONLY' in os.environ:
return {}
else:
- return update( tool_shed_api_key, '%s' % ( url_join( galaxy_tool_shed_url, 'api', 'repository_revisions', metadata_id ) ), params, return_formatted=False )
+ return update( tool_shed_api_key, '%s' % ( suc.url_join( galaxy_tool_shed_url, 'api', 'repository_revisions', metadata_id ) ), params, return_formatted=False )
def remove_generated_tests( app ):
# Delete any configured tool functional tests from the test_toolbox.__dict__, otherwise nose will find them
@@ -558,6 +609,21 @@
for tool in tools_to_delete:
del app.toolbox.tools_by_id[ tool ]
+def remove_install_tests( app ):
+ # Delete any configured repository installation tests from the test_toolbox.__dict__, otherwise nose will find them
+ # and try to install the repository again while running tool functional tests.
+ tests_to_delete = []
+ global test_toolbox
+ # Push all the toolbox tests to module level
+ for key in test_install_repositories.__dict__:
+ if key.startswith( 'TestInstallRepository_' ):
+ log.info( 'Repository installation process found, deleting: %s', key )
+ # We can't delete this test just yet, we're still iterating over __dict__.
+ tests_to_delete.append( key )
+ for key in tests_to_delete:
+ # Now delete the tests found in the previous loop.
+ del test_install_repositories.__dict__[ key ]
+
def run_tests( test_config ):
loader = nose.loader.TestLoader( config=test_config )
test_config.plugins.addPlugin( ReportResults() )
@@ -585,6 +651,55 @@
for repository in repositories_by_owner[ owner ]:
print "# %s owned by %s, changeset revision %s" % ( repository[ 'name' ], repository[ 'owner' ], repository[ 'changeset_revision' ] )
+def uninstall_repository( app, repository_info_dict ):
+ # Clean out any generated tests. This is necessary for Twill.
+ remove_generated_tests( app )
+ sa_session = app.model.context.current
+ # The dict contains the only repository the app should have installed at this point.
+ repository = test_db_util.get_installed_repository_by_name_owner_changeset_revision( repository_info_dict[ 'name' ],
+ repository_info_dict[ 'owner' ],
+ repository_info_dict[ 'changeset_revision' ] )
+ # We have to do this through Twill, in order to maintain app.toolbox and shed_tool_conf.xml in a state that is valid for future tests.
+ for required_repository in repository.repository_dependencies:
+ repository_dict = dict( name=required_repository.name,
+ owner=required_repository.owner,
+ changeset_revision=required_repository.changeset_revision )
+ # Generate a test method to uninstall this repository through the embedded Galaxy application's web interface.
+ test_install_repositories.generate_deactivate_or_uninstall_method( repository_dict, deactivate=False )
+ log.debug( 'Changeset revision %s of %s repository %s selected for uninstallation.' % \
+ ( required_repository.changeset_revision, required_repository.status, required_repository.name ) )
+ repository_dict = dict( name=repository.name,
+ owner=repository.owner,
+ changeset_revision=repository.changeset_revision )
+ test_install_repositories.generate_deactivate_or_uninstall_method( repository_dict, deactivate=False )
+ log.debug( 'Changeset revision %s of %s repository %s selected for uninstallation.' % \
+ ( repository.changeset_revision, repository.status, repository.name ) )
+ # Set up nose to run the generated uninstall method as a functional test.
+ test_config = nose.config.Config( env=os.environ, plugins=nose.plugins.manager.DefaultPluginManager() )
+ test_config.configure( sys.argv )
+ # Run the uninstall method. This method uses the Galaxy web interface to uninstall the previously installed
+ # repository and delete it from disk.
+ result, _ = run_tests( test_config )
+ success = result.wasSuccessful()
+ return success
+
+def uninstall_tool_dependency( app, tool_dependency ):
+ # Clean out any generated tests. This is necessary for Twill.
+ tool_dependency_install_path = tool_dependency.installation_directory( app )
+ uninstalled, error_message = tool_dependency_util.remove_tool_dependency( app, tool_dependency )
+ if error_message:
+ log.debug( error_message )
+ sa_session = app.model.context.current
+ if not uninstalled or tool_dependency.status != app.model.ToolDependency.installation_status.UNINSTALLED:
+ tool_dependency.status = app.model.ToolDependency.installation_status.UNINSTALLED
+ sa_session.add( tool_dependency )
+ sa_session.flush()
+ if os.path.exists( tool_dependency_install_path ):
+ log.debug( 'Uninstallation of tool dependency succeeded, but the installation path still exists on the filesystem. It is now being explicitly deleted.')
+ suc.remove_dir( tool_dependency_install_path )
+ return success
+
+
def main():
# ---- Configuration ------------------------------------------------------
galaxy_test_host = os.environ.get( 'GALAXY_INSTALL_TEST_HOST', default_galaxy_test_host )
@@ -601,10 +716,7 @@
os.mkdir( galaxy_test_tmp_dir )
galaxy_test_proxy_port = None
# Allow the option to keep or delete tool dependencies when a repository has been tested.
- if 'GALAXY_INSTALL_TEST_KEEP_TOOL_DEPENDENCIES' in os.environ:
- deactivate_only = True
- else:
- deactivate_only = False
+ deactivate = asbool( os.environ.get( 'GALAXY_INSTALL_TEST_KEEP_TOOL_DEPENDENCIES', False ) )
# Set up the configuration files for the Galaxy instance.
shed_tool_data_table_conf_file = os.environ.get( 'GALAXY_INSTALL_TEST_SHED_TOOL_DATA_TABLE_CONF', os.path.join( galaxy_test_tmp_dir, 'test_shed_tool_data_table_conf.xml' ) )
galaxy_tool_data_table_conf_file = os.environ.get( 'GALAXY_INSTALL_TEST_TOOL_DATA_TABLE_CONF', tool_data_table_conf )
@@ -766,10 +878,7 @@
else:
raise Exception( "Test HTTP server did not return '200 OK' after 10 tries" )
log.info( "Embedded galaxy web server started" )
- if galaxy_test_proxy_port:
- log.info( "The embedded Galaxy application is running on %s:%s", galaxy_test_host, galaxy_test_proxy_port )
- else:
- log.info( "The embedded Galaxy application is running on %s:%s", galaxy_test_host, galaxy_test_port )
+ log.info( "The embedded Galaxy application is running on %s:%s", galaxy_test_host, galaxy_test_port )
log.info( "Repositories will be installed from the tool shed at %s", galaxy_tool_shed_url )
success = False
# If a tool_data_table_conf.test.xml file was found, add the entries from it into the app's tool data tables.
@@ -889,6 +998,7 @@
# Use the repository information dict to generate an install method that will install the repository into the embedded
# Galaxy application, with tool dependencies and repository dependencies, if any.
test_install_repositories.generate_install_method( repository_info_dict )
+ # Set the GALAXY_INSTALL_TEST_HOST variable so that Twill will have the Galaxy url to install repositories into.
os.environ[ 'GALAXY_INSTALL_TEST_HOST' ] = galaxy_test_host
# Configure nose to run the install method as a test.
test_config = nose.config.Config( env=os.environ, plugins=nose.plugins.manager.DefaultPluginManager() )
@@ -907,6 +1017,8 @@
# If the installation succeeds, configure and run functional tests for this repository. This is equivalent to
# sh run_functional_tests.sh -installed
if success:
+ # Clean out repository installation methods.
+ remove_install_tests( app )
log.debug( 'Installation of %s succeeded, running all defined functional tests.', name )
# Generate the shed_tools_dict that specifies the location of test data contained within this repository. If the repository
# does not have a test-data directory, this will return has_test_data = False, and we will set the do_not_test flag to True,
@@ -996,51 +1108,15 @@
# "reason": "The Galaxy development team has determined that this repository should not be installed and tested by the automated framework."
# }
# }
- failed_tool_dependencies = get_failed_tool_dependencies( repository )
- failed_repository_dependencies = repository.repository_dependencies_with_installation_errors
if 'missing_test_components' not in repository_status:
repository_status[ 'missing_test_components' ] = []
- if not has_test_data:
- # If the repository does not have a test-data directory, any functional tests in the tool configuration will
- # fail. Mark the repository as failed and skip installation.
- log.error( 'Test data is missing for this repository. Updating repository and skipping functional tests.' )
- # Record the lack of test data if the repository metadata defines tools.
- if 'tools' in repository.metadata:
- for tool in repository.metadata[ 'tools' ]:
- tool_id = tool[ 'id' ]
- tool_version = tool[ 'version' ]
- tool_guid = tool[ 'guid' ]
- # In keeping with the standard display layout, add the error message to the dict for each tool individually.
- missing_components = dict( tool_id=tool_id, tool_version=tool_version, tool_guid=tool_guid,
- missing_components="Repository %s is missing a test-data directory." % name )
- if missing_components not in repository_status[ 'missing_test_components' ]:
- repository_status[ 'missing_test_components' ].append( missing_components )
- else:
- continue
- # Record the status of this repository in the tool shed.
- set_do_not_test = not is_latest_downloadable_revision( galaxy_tool_shed_url, repository_info_dict )
- params[ 'tools_functionally_correct' ] = False
- params[ 'missing_test_components' ] = True
- params[ 'do_not_test' ] = str( set_do_not_test )
- register_test_result( galaxy_tool_shed_url,
- metadata_revision_id,
- repository_status,
- repository_info_dict,
- params )
- # Run the cleanup method. This removes tool functional test methods from the test_toolbox module and uninstalls the
- # repository using Twill.
- execute_uninstall_method( app, deactivate_only )
- # Set the test_toolbox.toolbox module-level variable to the new app.toolbox.
- test_toolbox.toolbox = app.toolbox
- repositories_failed.append( dict( name=name, owner=owner, changeset_revision=changeset_revision ) )
- elif failed_tool_dependencies or failed_repository_dependencies:
+ if repository.missing_tool_dependencies or repository.missing_repository_dependencies:
# If a tool dependency fails to install correctly, this should be considered an installation error,
# and functional tests should be skipped, since the tool dependency needs to be correctly installed
# for the test to be considered reliable.
- log.error( 'One or more dependencies of this repository are marked as missing.' )
- log.error( 'Updating repository and skipping functional tests.' )
+ log.error( 'The following dependencies of this repository are missing, skipping functional tests.' )
# In keeping with the standard display layout, add the error message to the dict for each tool individually.
- for dependency in failed_tool_dependencies:
+ for dependency in repository.missing_tool_dependencies:
log.error( 'Missing tool dependency %s of type %s version %s: %s' % \
( str( dependency.name ), str( dependency.type ), str( dependency.version ), str( dependency.error_message ) ) )
test_result = dict( type=dependency.type,
@@ -1048,7 +1124,7 @@
version=dependency.version,
error_message=dependency.error_message )
repository_status[ 'installation_errors' ][ 'tool_dependencies' ].append( test_result )
- for dependency in repository.repository_dependencies_with_installation_errors:
+ for dependency in repository.missing_repository_dependencies:
log.error( 'Missing repository dependency %s changeset revision %s owned by %s: %s' % \
( str( dependency.name ), str( dependency.changeset_revision ), str( dependency.owner ), str( dependency.error_message ) ) )
test_result = dict( tool_shed=dependency.tool_shed,
@@ -1066,11 +1142,22 @@
repository_status,
repository_info_dict,
params )
- # Run the cleanup method. This removes tool functional test methods from the test_toolbox module and uninstalls the
- # repository using Twill. If tool dependencies failed installation, select to uninstall instead of deavctivate,
- # to make way for the next attempt. Otherwise, default to the value determined by the environment variable
- # GALAXY_INSTALL_TEST_KEEP_TOOL_DEPENDENCIES.
- execute_uninstall_method( app, deactivate_only=deactivate_only )
+ # Since this repository is missing components, we do not want to test it. Deactivate this repository.
+ # The deactivate flag is set to True if the environment variable GALAXY_INSTALL_TEST_KEEP_TOOL_DEPENDENCIES
+ # is set to 'true'.
+ if deactivate:
+ # Recursively retrieve every missing tool dependency for this repository and its required repositories.
+ log.debug( 'Due to the above missing tool dependencies, we are now uninstalling the following tool dependencies, but not changing their repositories.' )
+ missing_tool_dependencies = get_missing_tool_dependencies( repository )
+ for missing_tool_dependency in missing_tool_dependencies:
+ uninstall_tool_dependency( app, missing_tool_dependency )
+ # We are deactivating this repository and all of its repository dependencies.
+ log.debug( 'Due to the above missing repository dependencies, we are now deactivating the following repositories.' )
+ deactivate_repository( app, repository_info_dict )
+ else:
+ # We are uninstalling this repository and all of its repository dependencies.
+ log.debug( 'Due to the above missing repository dependencies, we are now uninstalling the following repositories.' )
+ uninstall_repository( app, repository_info_dict )
# Set the test_toolbox.toolbox module-level variable to the new app.toolbox.
test_toolbox.toolbox = app.toolbox
repositories_failed_install.append( dict( name=name, owner=owner, changeset_revision=changeset_revision ) )
@@ -1142,10 +1229,18 @@
changeset_revision, name )
# Run the uninstall method. This removes tool functional test methods from the test_toolbox module and uninstalls the
# repository using Twill.
- log.debug( 'Uninstalling changeset revision %s of repository %s',
- repository_info_dict[ 'changeset_revision' ],
- repository_info_dict[ 'name' ] )
- success = execute_uninstall_method( app, deactivate_only )
+ if deactivate:
+ log.debug( 'Deactivating changeset revision %s of repository %s',
+ repository_info_dict[ 'changeset_revision' ],
+ repository_info_dict[ 'name' ] )
+ # We are deactivating this repository and all of its repository dependencies.
+ success = deactivate_repository( app, repository_info_dict )
+ else:
+ log.debug( 'Uninstalling changeset revision %s of repository %s',
+ repository_info_dict[ 'changeset_revision' ],
+ repository_info_dict[ 'name' ] )
+ # We are uninstalling this repository and all of its repository dependencies.
+ success = uninstall_repository( app, repository_info_dict )
if not success:
log.error( 'Repository %s failed to uninstall.', repository_info_dict[ 'name' ] )
# Set the test_toolbox.toolbox module-level variable to the new app.toolbox.
@@ -1172,9 +1267,14 @@
repository_info_dict,
params )
try:
- success = execute_uninstall_method( app, deactivate_only )
+ if deactivate:
+ # We are deactivating this repository and all of its repository dependencies.
+ success = deactivate_repository( app, repository_info_dict )
+ else:
+ # We are uninstalling this repository and all of its repository dependencies.
+ success = uninstall_repository( app, repository_info_dict )
except:
- log.exception( 'Encountered error attempting to uninstall %s.', repository_info_dict[ 'name' ] )
+ log.exception( 'Encountered error attempting to deactivate or uninstall %s.', repository_info_dict[ 'name' ] )
success = False
if not success:
log.error( 'Repository %s failed to uninstall.', repository_info_dict[ 'name' ] )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/ca7110d33157/
Changeset: ca7110d33157
User: Dave Bouvier
Date: 2013-11-14 22:31:34
Summary: Rebuild the list of sniffer elem classes after each one is removed from sniffer_elems, in order to keep the mapping current.
Affected #: 1 file
diff -r 51105146f487822cb1d38ba3396882d610e0282e -r ca7110d331571b4a3bbfdd75037053ea4c40b746 lib/galaxy/datatypes/registry.py
--- a/lib/galaxy/datatypes/registry.py
+++ b/lib/galaxy/datatypes/registry.py
@@ -358,6 +358,7 @@
for index, s_e_c in enumerate( sniffer_elem_classes ):
if sniffer_class == s_e_c:
del self.sniffer_elems[ index ]
+ sniffer_elem_classes = [ e.attrib[ 'type' ] for e in self.sniffer_elems ]
self.log.debug( "Removed sniffer element for datatype '%s'" % str( dtype ) )
break
for sniffer_class in self.sniff_order:
https://bitbucket.org/galaxy/galaxy-central/commits/093626ae621f/
Changeset: 093626ae621f
Branch: stable
User: greg
Date: 2013-11-14 21:51:24
Summary: Display an error message rather than raising an exception when handling invalid complex repository dependencies in the Tool Shed.
Affected #: 1 file
diff -r e54372d60f111f4be26868ba416649697b551a13 -r 093626ae621f73b9cf904c935eddae98a8823839 lib/tool_shed/util/commit_util.py
--- a/lib/tool_shed/util/commit_util.py
+++ b/lib/tool_shed/util/commit_util.py
@@ -142,14 +142,13 @@
# <repository name="package_eigen_2_0" owner="test" prior_installation_required="True" />
revised, repository_elem, error_message = handle_repository_dependency_elem( trans, sub_elem, unpopulate=unpopulate )
if error_message:
- exception_message = 'The tool_dependencies.xml file contains an invalid <repository> tag. %s' % error_message
- raise Exception( exception_message )
+ error_message = 'The tool_dependencies.xml file contains an invalid <repository> tag. %s' % error_message
if revised:
elem[ sub_elem_index ] = repository_elem
sub_elem_altered = True
if not altered:
altered = True
- return altered, sub_elem_altered, elem
+ return altered, sub_elem_altered, elem, error_message
def handle_directory_changes( trans, repository, full_path, filenames_in_archive, remove_repo_files_not_in_tar, new_repo_alert, commit_message,
undesirable_dirs_removed, undesirable_files_removed ):
@@ -359,13 +358,16 @@
for package_index, package_elem in enumerate( root_elem ):
if package_elem.tag == 'repository':
# We have a complex repository dependency.
- altered, package_altered, root_elem = handle_complex_repository_dependency_elem( trans,
- root_elem,
- package_index,
- package_elem,
- package_altered,
- altered,
- unpopulate=unpopulate )
+ altered, package_altered, root_elem, message = \
+ handle_complex_repository_dependency_elem( trans,
+ root_elem,
+ package_index,
+ package_elem,
+ package_altered,
+ altered,
+ unpopulate=unpopulate )
+ if message:
+ error_message += message
elif package_elem.tag == 'install':
# <install version="1.0">
for actions_index, actions_elem in enumerate( package_elem ):
@@ -392,7 +394,7 @@
for last_actions_elem_package_index, last_actions_elem_package_elem in enumerate( last_actions_elem ):
if last_actions_elem_package_elem.tag == 'repository':
# We have a complex repository dependency.
- altered, last_actions_package_altered, last_actions_elem = \
+ altered, last_actions_package_altered, last_actions_elem, message = \
handle_complex_repository_dependency_elem( trans,
last_actions_elem,
last_actions_elem_package_index,
@@ -400,6 +402,8 @@
last_actions_package_altered,
altered,
unpopulate=unpopulate )
+ if message:
+ error_message += message
if last_actions_package_altered:
last_actions_elem[ last_actions_elem_package_index ] = last_actions_elem_package_elem
actions_group_elem[ last_actions_index ] = last_actions_elem
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: greg: Display an error message rather than raising an exception when handling invalid complex repository dependencies in the Tool Shed.
by commits-noreply@bitbucket.org 14 Nov '13
by commits-noreply@bitbucket.org 14 Nov '13
14 Nov '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/51105146f487/
Changeset: 51105146f487
User: greg
Date: 2013-11-14 21:51:24
Summary: Display an error message rather than raising an exception when handling invalid complex repository dependencies in the Tool Shed.
Affected #: 1 file
diff -r 418993fac75d07297dc317e183cf401fd9fbb869 -r 51105146f487822cb1d38ba3396882d610e0282e lib/tool_shed/util/commit_util.py
--- a/lib/tool_shed/util/commit_util.py
+++ b/lib/tool_shed/util/commit_util.py
@@ -142,14 +142,13 @@
# <repository name="package_eigen_2_0" owner="test" prior_installation_required="True" />
revised, repository_elem, error_message = handle_repository_dependency_elem( trans, sub_elem, unpopulate=unpopulate )
if error_message:
- exception_message = 'The tool_dependencies.xml file contains an invalid <repository> tag. %s' % error_message
- raise Exception( exception_message )
+ error_message = 'The tool_dependencies.xml file contains an invalid <repository> tag. %s' % error_message
if revised:
elem[ sub_elem_index ] = repository_elem
sub_elem_altered = True
if not altered:
altered = True
- return altered, sub_elem_altered, elem
+ return altered, sub_elem_altered, elem, error_message
def handle_directory_changes( trans, repository, full_path, filenames_in_archive, remove_repo_files_not_in_tar, new_repo_alert, commit_message,
undesirable_dirs_removed, undesirable_files_removed ):
@@ -359,13 +358,16 @@
for package_index, package_elem in enumerate( root_elem ):
if package_elem.tag == 'repository':
# We have a complex repository dependency.
- altered, package_altered, root_elem = handle_complex_repository_dependency_elem( trans,
- root_elem,
- package_index,
- package_elem,
- package_altered,
- altered,
- unpopulate=unpopulate )
+ altered, package_altered, root_elem, message = \
+ handle_complex_repository_dependency_elem( trans,
+ root_elem,
+ package_index,
+ package_elem,
+ package_altered,
+ altered,
+ unpopulate=unpopulate )
+ if message:
+ error_message += message
elif package_elem.tag == 'install':
# <install version="1.0">
for actions_index, actions_elem in enumerate( package_elem ):
@@ -392,7 +394,7 @@
for last_actions_elem_package_index, last_actions_elem_package_elem in enumerate( last_actions_elem ):
if last_actions_elem_package_elem.tag == 'repository':
# We have a complex repository dependency.
- altered, last_actions_package_altered, last_actions_elem = \
+ altered, last_actions_package_altered, last_actions_elem, message = \
handle_complex_repository_dependency_elem( trans,
last_actions_elem,
last_actions_elem_package_index,
@@ -400,6 +402,8 @@
last_actions_package_altered,
altered,
unpopulate=unpopulate )
+ if message:
+ error_message += message
if last_actions_package_altered:
last_actions_elem[ last_actions_elem_package_index ] = last_actions_elem_package_elem
actions_group_elem[ last_actions_index ] = last_actions_elem
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jmchilton: get_intiail_value history fix. Allows ToolDataParameters inside of repeats when using API.
by commits-noreply@bitbucket.org 14 Nov '13
by commits-noreply@bitbucket.org 14 Nov '13
14 Nov '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/418993fac75d/
Changeset: 418993fac75d
User: jmchilton
Date: 2013-11-14 19:35:27
Summary: get_intiail_value history fix. Allows ToolDataParameters inside of repeats when using API.
Affected #: 1 file
diff -r 3402a11b008865ee37ee29c9d7d3d5ea27c6fe84 -r 418993fac75d07297dc317e183cf401fd9fbb869 lib/galaxy/tools/parameters/grouping.py
--- a/lib/galaxy/tools/parameters/grouping.py
+++ b/lib/galaxy/tools/parameters/grouping.py
@@ -113,7 +113,7 @@
for i in range( self.default ):
rval_dict = { '__index__': i}
for input in self.inputs.itervalues():
- rval_dict[ input.name ] = input.get_initial_value( trans, context )
+ rval_dict[ input.name ] = input.get_initial_value( trans, context, history=history )
rval.append( rval_dict )
return rval
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
16 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/2edddde7517d/
Changeset: 2edddde7517d
User: jmchilton
Date: 2013-11-11 08:45:32
Summary: Some PEP-8 fixes for lib/galaxy/tools/parameters/basic.py.
Affected #: 1 file
diff -r 1df960b4892ae935840455de9ac058e396ec9410 -r 2edddde7517d7957fe75a87fa7d45b80dedc156f lib/galaxy/tools/parameters/basic.py
--- a/lib/galaxy/tools/parameters/basic.py
+++ b/lib/galaxy/tools/parameters/basic.py
@@ -2,14 +2,20 @@
Basic tool parameters.
"""
-import logging, string, sys, os, os.path, urllib
+import logging
+import string
+import sys
+import os
+import os.path
+import urllib
from elementtree.ElementTree import XML, Element
from galaxy import config, datatypes, util
from galaxy.web import form_builder
from galaxy.util.bunch import Bunch
from galaxy.util import string_as_bool, sanitize_param, unicodify
from sanitize import ToolParameterSanitizer
-import validation, dynamic_options
+import validation
+import dynamic_options
# For BaseURLToolParameter
from galaxy.web import url_for
from galaxy.model.item_attrs import Dictifiable
@@ -53,8 +59,10 @@
def get_label( self ):
"""Return user friendly name for the parameter"""
- if self.label: return self.label
- else: return self.name
+ if self.label:
+ return self.label
+ else:
+ return self.name
def get_html_field( self, trans=None, value=None, other_values={} ):
raise TypeError( "Abstract Method" )
@@ -87,7 +95,7 @@
if a value has already been chosen from the history. This is to support the capability to
choose each dataset once
"""
- return self.get_initial_value(trans, context, history=history);
+ return self.get_initial_value(trans, context, history=history)
def get_required_enctype( self ):
"""
@@ -166,7 +174,7 @@
return value
def validate( self, value, history=None ):
- if value=="" and self.optional:
+ if value == "" and self.optional:
return
for validator in self.validators:
validator.validate( value, history )
@@ -219,7 +227,8 @@
self.area = string_as_bool( elem.get( 'area', False ) )
def get_html_field( self, trans=None, value=None, other_values={} ):
- if value is None: value = self.value
+ if value is None:
+ value = self.value
if self.area:
return form_builder.TextArea( self.name, self.size, value )
else:
@@ -228,6 +237,7 @@
def get_initial_value( self, trans, context, history=None ):
return self.value
+
class IntegerToolParameter( TextToolParameter ):
"""
Parameter that takes an integer value.
@@ -412,7 +422,7 @@
checked = self.checked
if value is not None:
checked = form_builder.CheckboxField.is_checked( value )
- return form_builder.CheckboxField( self.name, checked, refresh_on_change = self.refresh_on_change )
+ return form_builder.CheckboxField( self.name, checked, refresh_on_change=self.refresh_on_change )
def from_html( self, value, trans=None, other_values={} ):
return form_builder.CheckboxField.is_checked( value )
@@ -461,7 +471,7 @@
self.ajax = string_as_bool( elem.get( 'ajax-upload' ) )
def get_html_field( self, trans=None, value=None, other_values={} ):
- return form_builder.FileField( self.name, ajax = self.ajax, value = value )
+ return form_builder.FileField( self.name, ajax=self.ajax, value=value )
def from_html( self, value, trans=None, other_values={} ):
# Middleware or proxies may encode files in special ways (TODO: this
@@ -476,8 +486,8 @@
assert local_filename.startswith( upload_store ), \
"Filename provided by nginx is not in correct directory"
value = dict(
- filename = value["name"],
- local_filename = local_filename
+ filename=value["name"],
+ local_filename=local_filename
)
return value
@@ -533,7 +543,7 @@
user_ftp_dir = None
else:
user_ftp_dir = trans.user_ftp_dir
- return form_builder.FTPFileField( self.name, user_ftp_dir, trans.app.config.ftp_upload_site, value = value )
+ return form_builder.FTPFileField( self.name, user_ftp_dir, trans.app.config.ftp_upload_site, value=value )
def from_html( self, value, trans=None, other_values={} ):
try:
@@ -754,8 +764,9 @@
else:
return form_builder.TextField( self.name, value=(value or "") )
if value is not None:
- if not isinstance( value, list ): value = [ value ]
- field = form_builder.SelectField( self.name, self.multiple, self.display, self.refresh_on_change, refresh_on_change_values = self.refresh_on_change_values )
+ if not isinstance( value, list ):
+ value = [ value ]
+ field = form_builder.SelectField( self.name, self.multiple, self.display, self.refresh_on_change, refresh_on_change_values=self.refresh_on_change_values )
options = self.get_options( trans, context )
for text, optval, selected in options:
if isinstance( optval, UnvalidatedValue ):
@@ -793,7 +804,7 @@
rval.append( v )
return rval
else:
- value_is_none = ( value == "None" and "None" not in legal_values )
+ value_is_none = ( value == "None" and "None" not in legal_values )
if value_is_none:
if self.multiple:
if self.optional:
@@ -943,7 +954,7 @@
options = []
try:
options = self.get_options( trans, {} )
- except AssertionError, assertion:
+ except AssertionError:
# we dont/cant set other_values (the {} above), so params that require other params to be filled will error:
# required dependency in filter_options
# associated DataToolParam in get_column_list
@@ -1531,8 +1542,9 @@
TODO: There should be an alternate display that allows single selects to be
displayed as radio buttons and multiple selects as a set of checkboxes
- TODO: The following must be fixed to test correctly for the new security_check tag in the DataToolParameter ( the last test below is broken )
- Nate's next pass at the dataset security stuff will dramatically alter this anyway.
+ TODO: The following must be fixed to test correctly for the new security_check tag in
+ the DataToolParameter ( the last test below is broken ) Nate's next pass at the dataset
+ security stuff will dramatically alter this anyway.
"""
def __init__( self, tool, elem, trans=None):
@@ -1579,8 +1591,8 @@
# Load conversions required for the dataset input
self.conversions = []
for conv_elem in elem.findall( "conversion" ):
- name = conv_elem.get( "name" ) #name for commandline substitution
- conv_extensions = conv_elem.get( "type" ) #target datatype extension
+ name = conv_elem.get( "name" ) # name for commandline substitution
+ conv_extensions = conv_elem.get( "type" ) # target datatype extension
# FIXME: conv_extensions should be able to be an ordered list
assert None not in [ name, type ], 'A name (%s) and type (%s) are required for explicit conversion' % ( name, type )
conv_types = tool.app.datatypes_registry.get_datatype_by_extension( conv_extensions.lower() )
@@ -1592,14 +1604,15 @@
try:
filter_value = self.options.get_options( trans, other_values )[0][0]
except IndexError:
- pass #no valid options
+ pass # no valid options
assert trans is not None, "DataToolParameter requires a trans"
history = trans.get_history()
assert history is not None, "DataToolParameter requires a history"
if value is not None:
if type( value ) != list:
value = [ value ]
- field = form_builder.SelectField( self.name, self.multiple, None, self.refresh_on_change, refresh_on_change_values = self.refresh_on_change_values )
+ field = form_builder.SelectField( self.name, self.multiple, None, self.refresh_on_change, refresh_on_change_values=self.refresh_on_change_values )
+
# CRUCIAL: the dataset_collector function needs to be local to DataToolParameter.get_html_field()
def dataset_collector( hdas, parent_hid ):
current_user_roles = trans.get_current_user_roles()
@@ -1654,7 +1667,7 @@
return field
def get_initial_value( self, trans, context, history=None ):
- return self.get_initial_value_from_history_prevent_repeats(trans, context, None, history=history);
+ return self.get_initial_value_from_history_prevent_repeats(trans, context, None, history=history)
def get_initial_value_from_history_prevent_repeats( self, trans, context, already_used, history=None ):
"""
@@ -1676,7 +1689,8 @@
try:
filter_value = self.options.get_options( trans, context )[0][0]
except IndexError:
- pass #no valid options
+ pass # no valid options
+
def dataset_collector( datasets ):
def is_convertable( dataset ):
target_ext, converted_dataset = dataset.find_conversion_destination( self.formats )
https://bitbucket.org/galaxy/galaxy-central/commits/4f68a886036c/
Changeset: 4f68a886036c
User: jmchilton
Date: 2013-11-11 08:45:32
Summary: PEP-8 cleanup of lib/galaxy/tools/actions/upload.py.
Affected #: 1 file
diff -r 2edddde7517d7957fe75a87fa7d45b80dedc156f -r 4f68a886036c934194d4a625cb2fcccf32e64aba lib/galaxy/tools/actions/upload.py
--- a/lib/galaxy/tools/actions/upload.py
+++ b/lib/galaxy/tools/actions/upload.py
@@ -4,8 +4,10 @@
import logging
log = logging.getLogger( __name__ )
+
class UploadToolAction( ToolAction ):
- def execute( self, tool, trans, incoming={}, set_output_hid = True, history=None, **kwargs ):
+
+ def execute( self, tool, trans, incoming={}, set_output_hid=True, history=None, **kwargs ):
dataset_upload_inputs = []
for input_name, input in tool.inputs.iteritems():
if input.type == "upload_dataset":
https://bitbucket.org/galaxy/galaxy-central/commits/510cbdd44e77/
Changeset: 510cbdd44e77
User: jmchilton
Date: 2013-11-11 08:45:32
Summary: PEP-8 cleanups for lib/galaxy/tools/actions/upload_common.py.
Affected #: 1 file
diff -r 4f68a886036c934194d4a625cb2fcccf32e64aba -r 510cbdd44e772629b49d1ae134af199a006ee28d lib/galaxy/tools/actions/upload_common.py
--- a/lib/galaxy/tools/actions/upload_common.py
+++ b/lib/galaxy/tools/actions/upload_common.py
@@ -1,4 +1,8 @@
-import os, tempfile, StringIO, pwd, subprocess
+import os
+import tempfile
+import StringIO
+import pwd
+import subprocess
from cgi import FieldStorage
from galaxy import datatypes, util
from galaxy.util.odict import odict
@@ -10,13 +14,13 @@
import logging
log = logging.getLogger( __name__ )
+
def persist_uploads( params ):
"""
Turn any uploads in the submitted form to persisted files.
"""
if 'files' in params:
new_files = []
- temp_files = []
for upload_dataset in params['files']:
f = upload_dataset['file_data']
if isinstance( f, FieldStorage ):
@@ -24,8 +28,8 @@
assert f.file.name != '<fdopen>'
local_filename = util.mkstemp_ln( f.file.name, 'upload_file_data_' )
f.file.close()
- upload_dataset['file_data'] = dict( filename = f.filename,
- local_filename = local_filename )
+ upload_dataset['file_data'] = dict( filename=f.filename,
+ local_filename=local_filename )
elif type( f ) == dict and 'filename' and 'local_filename' not in f:
raise Exception( 'Uploaded file was encoded in a way not understood by Galaxy.' )
if upload_dataset['url_paste'] and upload_dataset['url_paste'].strip() != '':
@@ -35,6 +39,8 @@
new_files.append( upload_dataset )
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
@@ -62,6 +68,8 @@
role = trans.sa_session.query( trans.app.model.Role ).get( role_id )
library_bunch.roles.append( role )
return library_bunch
+
+
def get_precreated_datasets( trans, params, data_obj, controller='root' ):
"""
Get any precreated datasets (when using asynchronous uploads).
@@ -90,6 +98,8 @@
else:
rval.append( data )
return rval
+
+
def get_precreated_dataset( precreated_datasets, name ):
"""
Return a dataset matching a name from the list of precreated (via async
@@ -101,21 +111,24 @@
return precreated_datasets.pop( names.index( name ) )
else:
return None
+
+
def cleanup_unused_precreated_datasets( precreated_datasets ):
for data in precreated_datasets:
log.info( 'Cleaned up unclaimed precreated dataset (%s).' % ( data.id ) )
data.state = data.states.ERROR
data.info = 'No file contents were available.'
+
def __new_history_upload( trans, uploaded_dataset, history=None, state=None ):
if not history:
history = trans.history
- hda = trans.app.model.HistoryDatasetAssociation( name = uploaded_dataset.name,
- extension = uploaded_dataset.file_type,
- dbkey = uploaded_dataset.dbkey,
- history = history,
- create_dataset = True,
- sa_session = trans.sa_session )
+ hda = trans.app.model.HistoryDatasetAssociation( name=uploaded_dataset.name,
+ extension=uploaded_dataset.file_type,
+ dbkey=uploaded_dataset.dbkey,
+ history=history,
+ create_dataset=True,
+ sa_session=trans.sa_session )
if state:
hda.state = state
else:
@@ -128,6 +141,7 @@
trans.sa_session.flush()
return hda
+
def __new_library_upload( trans, cntrller, uploaded_dataset, library_bunch, state=None ):
current_user_roles = trans.get_current_user_roles()
if not ( ( trans.user_is_admin() and cntrller in [ 'library_admin', 'api' ] ) or trans.app.security_agent.can_add_library_item( current_user_roles, library_bunch.folder ) ):
@@ -156,13 +170,13 @@
trans.sa_session.add( ld )
trans.sa_session.flush()
trans.app.security_agent.copy_library_permissions( trans, folder, ld )
- ldda = trans.app.model.LibraryDatasetDatasetAssociation( name = uploaded_dataset.name,
- extension = uploaded_dataset.file_type,
- dbkey = uploaded_dataset.dbkey,
- library_dataset = ld,
- user = trans.user,
- create_dataset = True,
- sa_session = trans.sa_session )
+ ldda = trans.app.model.LibraryDatasetDatasetAssociation( name=uploaded_dataset.name,
+ extension=uploaded_dataset.file_type,
+ dbkey=uploaded_dataset.dbkey,
+ library_dataset=ld,
+ user=trans.user,
+ create_dataset=True,
+ sa_session=trans.sa_session )
trans.sa_session.add( ldda )
if state:
ldda.state = state
@@ -210,12 +224,14 @@
trans.sa_session.flush()
return ldda
+
def new_upload( trans, cntrller, uploaded_dataset, library_bunch=None, history=None, state=None ):
if library_bunch:
return __new_library_upload( trans, cntrller, uploaded_dataset, library_bunch, state )
else:
return __new_history_upload( trans, uploaded_dataset, history=history, state=state )
+
def get_uploaded_datasets( trans, cntrller, params, precreated_datasets, dataset_upload_inputs, library_bunch=None, history=None ):
uploaded_datasets = []
for dataset_upload_input in dataset_upload_inputs:
@@ -256,6 +272,8 @@
history.genome_build = uploaded_dataset.dbkey
uploaded_dataset.data = data
return uploaded_datasets
+
+
def create_paramfile( trans, uploaded_datasets ):
"""
Create the upload tool's JSON "param" file.
@@ -284,14 +302,14 @@
setattr( data.metadata, meta_name, meta_value )
trans.sa_session.add( data )
trans.sa_session.flush()
- json = dict( file_type = uploaded_dataset.file_type,
- dataset_id = data.dataset.id,
- dbkey = uploaded_dataset.dbkey,
- type = uploaded_dataset.type,
- metadata = uploaded_dataset.metadata,
- primary_file = uploaded_dataset.primary_file,
- composite_file_paths = uploaded_dataset.composite_files,
- composite_files = dict( [ ( k, v.__dict__ ) for k, v in data.datatype.get_composite_files( data ).items() ] ) )
+ json = dict( file_type=uploaded_dataset.file_type,
+ dataset_id=data.dataset.id,
+ dbkey=uploaded_dataset.dbkey,
+ type=uploaded_dataset.type,
+ metadata=uploaded_dataset.metadata,
+ primary_file=uploaded_dataset.primary_file,
+ composite_file_paths=uploaded_dataset.composite_files,
+ composite_files=dict( [ ( k, v.__dict__ ) for k, v in data.datatype.get_composite_files( data ).items() ] ) )
else:
try:
is_binary = uploaded_dataset.datatype.is_binary
@@ -305,18 +323,18 @@
uuid_str = uploaded_dataset.uuid
except:
uuid_str = None
- json = dict( file_type = uploaded_dataset.file_type,
- ext = uploaded_dataset.ext,
- name = uploaded_dataset.name,
- dataset_id = data.dataset.id,
- dbkey = uploaded_dataset.dbkey,
- type = uploaded_dataset.type,
- is_binary = is_binary,
- link_data_only = link_data_only,
- uuid = uuid_str,
- space_to_tab = uploaded_dataset.space_to_tab,
- in_place = trans.app.config.external_chown_script is None,
- path = uploaded_dataset.path )
+ json = dict( file_type=uploaded_dataset.file_type,
+ ext=uploaded_dataset.ext,
+ name=uploaded_dataset.name,
+ dataset_id=data.dataset.id,
+ dbkey=uploaded_dataset.dbkey,
+ type=uploaded_dataset.type,
+ is_binary=is_binary,
+ link_data_only=link_data_only,
+ uuid=uuid_str,
+ space_to_tab=uploaded_dataset.space_to_tab,
+ in_place=trans.app.config.external_chown_script is None,
+ path=uploaded_dataset.path )
# TODO: This will have to change when we start bundling inputs.
# Also, in_place above causes the file to be left behind since the
# user cannot remove it unless the parent directory is writable.
@@ -327,6 +345,8 @@
if trans.app.config.external_chown_script:
_chown( json_file_path )
return json_file_path
+
+
def create_job( trans, params, tool, json_file_path, data_list, folder=None, history=None ):
"""
Create the upload job.
@@ -383,6 +403,8 @@
for i, v in enumerate( data_list ):
output[ 'output%i' % i ] = v
return job, output
+
+
def active_folders( trans, folder ):
# Stolen from galaxy.web.controllers.library_common (importing from which causes a circular issues).
# Much faster way of retrieving all active sub-folders within a given folder than the
https://bitbucket.org/galaxy/galaxy-central/commits/83970bc291d2/
Changeset: 83970bc291d2
User: jmchilton
Date: 2013-11-11 08:45:32
Summary: Break up row_for_param in tool_form.mako into smaller pieces.
Affected #: 2 files
diff -r 510cbdd44e772629b49d1ae134af199a006ee28d -r 83970bc291d2866ccc8782111a64a01e48bea9d1 lib/galaxy/tools/parameters/basic.py
--- a/lib/galaxy/tools/parameters/basic.py
+++ b/lib/galaxy/tools/parameters/basic.py
@@ -1359,7 +1359,7 @@
options = []
for filter_key, filter_value in self.filtered.iteritems():
dataset = other_values[filter_key]
- if dataset.__class__.__name__.endswith( "DatasetFilenameWrapper" ): #this is a bad way to check for this, but problems importing class ( due to circular imports? )
+ if dataset.__class__.__name__.endswith( "DatasetFilenameWrapper" ): # this is a bad way to check for this, but problems importing class ( due to circular imports? )
dataset = dataset.dataset
if dataset:
for meta_key, meta_dict in filter_value.iteritems():
diff -r 510cbdd44e772629b49d1ae134af199a006ee28d -r 83970bc291d2866ccc8782111a64a01e48bea9d1 templates/webapps/galaxy/tool_form.mako
--- a/templates/webapps/galaxy/tool_form.mako
+++ b/templates/webapps/galaxy/tool_form.mako
@@ -218,12 +218,11 @@
else:
cls = "form-row"
- label = param.get_label()
-
field = param.get_html_field( trans, parent_state[ param.name ], other_values )
field.refresh_on_change = param.refresh_on_change
- # Field may contain characters submitted by user and these characters may be unicode; handle non-ascii characters gracefully.
+ # Field may contain characters submitted by user and these characters may
+ # be unicode; handle non-ascii characters gracefully.
field_html = field.get_html( prefix )
if type( field_html ) is not unicode:
field_html = unicode( field_html, 'utf-8', 'replace' )
@@ -232,25 +231,39 @@
return field_html
%><div class="${cls}">
- %if label:
- <label for="${param.name}">${label}:</label>
- %endif
- <div class="form-row-input">${field_html}</div>
- %if parent_errors.has_key( param.name ):
- <div class="form-row-error-message">
- <div><img style="vertical-align: middle;" src="${h.url_for('/static/style/error_small.png')}"> <span style="vertical-align: middle;">${parent_errors[param.name]}</span></div>
- </div>
- %endif
+ ${label_for_param( param )}
+ ${input_for_param( param, field_html )}
+ ${errors_for_param( param, parent_errors )}
+ ${help_for_param( param )}
+ <div style="clear: both;"></div>
+ </div>
+</%def>
- %if param.help:
- <div class="toolParamHelp" style="clear: both;">
- ${param.help}
- </div>
- %endif
+<%def name="input_for_param( param, field_html )">
+ <div class="form-row-input">${field_html}</div>
+</%def>
- <div style="clear: both;"></div>
+<%def name="label_for_param( param )">
+ <% label = param.get_label()%>
+ %if label:
+ <label for="${param.name}">${label}:</label>
+ %endif
+</%def>
- </div>
+<%def name="errors_for_param( param, parent_errors )">
+ %if parent_errors.has_key( param.name ):
+ <div class="form-row-error-message">
+ <div><img style="vertical-align: middle;" src="${h.url_for('/static/style/error_small.png')}"> <span style="vertical-align: middle;">${parent_errors[param.name]}</span></div>
+ </div>
+ %endif
+</%def>
+
+<%def name="help_for_param( param )">
+ %if param.help:
+ <div class="toolParamHelp" style="clear: both;">
+ ${param.help}
+ </div>
+ %endif
</%def><%def name="row_for_rerun()">
https://bitbucket.org/galaxy/galaxy-central/commits/fcb39c3fdd3e/
Changeset: fcb39c3fdd3e
User: jmchilton
Date: 2013-11-11 08:45:32
Summary: Break up tools.handle_input - split out param checking.
Affected #: 1 file
diff -r 83970bc291d2866ccc8782111a64a01e48bea9d1 -r fcb39c3fdd3ece51e9d4753a91880a634e6419e2 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -1926,24 +1926,8 @@
if len(incoming):
self.update_state( trans, self.inputs_by_page[state.page], state.inputs, incoming, old_errors=old_errors or {} )
return "tool_form.mako", dict( errors={}, tool_state=state, param_values={}, incoming={} )
- # Process incoming data
- if not( self.check_values ):
- # If `self.check_values` is false we don't do any checking or
- # processing on input This is used to pass raw values
- # through to/from external sites. FIXME: This should be handled
- # more cleanly, there is no reason why external sites need to
- # post back to the same URL that the tool interface uses.
- errors = {}
- params = incoming
- else:
- # Update state for all inputs on the current page taking new
- # values from `incoming`.
- errors = self.update_state( trans, self.inputs_by_page[state.page], state.inputs, incoming, old_errors=old_errors or {} )
- # If the tool provides a `validate_input` hook, call it.
- validate_input = self.get_hook( 'validate_input' )
- if validate_input:
- validate_input( trans, errors, state.inputs, self.inputs_by_page[state.page] )
- params = state.inputs
+
+ errors, params = self.__check_param_values( trans, incoming, state, old_errors )
# Did the user actually click next / execute or is this just
# a refresh?
if 'runtool_btn' in incoming or 'URL' in incoming or 'ajax_upload' in incoming:
@@ -1996,6 +1980,28 @@
if not self.display_interface:
return 'message.mako', dict( status='info', message="The interface for this tool cannot be displayed", refresh_frames=['everything'] )
return 'tool_form.mako', dict( errors=errors, tool_state=state )
+
+ def __check_param_values( self, trans, incoming, state, old_errors ):
+ # Process incoming data
+ if not( self.check_values ):
+ # If `self.check_values` is false we don't do any checking or
+ # processing on input This is used to pass raw values
+ # through to/from external sites. FIXME: This should be handled
+ # more cleanly, there is no reason why external sites need to
+ # post back to the same URL that the tool interface uses.
+ errors = {}
+ params = incoming
+ else:
+ # Update state for all inputs on the current page taking new
+ # values from `incoming`.
+ errors = self.update_state( trans, self.inputs_by_page[state.page], state.inputs, incoming, old_errors=old_errors or {} )
+ # If the tool provides a `validate_input` hook, call it.
+ validate_input = self.get_hook( 'validate_input' )
+ if validate_input:
+ validate_input( trans, errors, state.inputs, self.inputs_by_page[state.page] )
+ params = state.inputs
+ return errors, params
+
def find_fieldstorage( self, x ):
if isinstance( x, FieldStorage ):
raise InterruptedUpload( None )
https://bitbucket.org/galaxy/galaxy-central/commits/0c0692e52ff7/
Changeset: 0c0692e52ff7
User: jmchilton
Date: 2013-11-11 08:45:32
Summary: Break up tools.handle_input - split out state creation.
Affected #: 1 file
diff -r fcb39c3fdd3ece51e9d4753a91880a634e6419e2 -r 0c0692e52ff7ed81b7784ecaea7dff7dcdd28fa5 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -1908,13 +1908,8 @@
to the form or execute the tool (only if 'execute' was clicked and
there were no errors).
"""
- # Get the state or create if not found
- if "tool_state" in incoming:
- encoded_state = string_to_object( incoming["tool_state"] )
- state = DefaultToolState()
- state.decode( encoded_state, self, trans.app )
- else:
- state = self.new_state( trans, history=history )
+ state, state_new = self.__fetch_state( trans, incoming, history )
+ if state_new:
# This feels a bit like a hack. It allows forcing full processing
# of inputs even when there is no state in the incoming dictionary
# by providing either 'runtool_btn' (the name of the submit button
@@ -1928,6 +1923,7 @@
return "tool_form.mako", dict( errors={}, tool_state=state, param_values={}, incoming={} )
errors, params = self.__check_param_values( trans, incoming, state, old_errors )
+
# Did the user actually click next / execute or is this just
# a refresh?
if 'runtool_btn' in incoming or 'URL' in incoming or 'ajax_upload' in incoming:
@@ -1981,6 +1977,18 @@
return 'message.mako', dict( status='info', message="The interface for this tool cannot be displayed", refresh_frames=['everything'] )
return 'tool_form.mako', dict( errors=errors, tool_state=state )
+ def __fetch_state( self, trans, incoming, history ):
+ # Get the state or create if not found
+ if "tool_state" in incoming:
+ encoded_state = string_to_object( incoming["tool_state"] )
+ state = DefaultToolState()
+ state.decode( encoded_state, self, trans.app )
+ new = False
+ else:
+ state = self.new_state( trans, history=history )
+ new = True
+ return state, new
+
def __check_param_values( self, trans, incoming, state, old_errors ):
# Process incoming data
if not( self.check_values ):
https://bitbucket.org/galaxy/galaxy-central/commits/c4632090a444/
Changeset: c4632090a444
User: jmchilton
Date: 2013-11-11 08:45:32
Summary: Break up tools.handle_input - split out refresh state logic.
Affected #: 1 file
diff -r 0c0692e52ff7ed81b7784ecaea7dff7dcdd28fa5 -r c4632090a444751660a354e997873da5fd14cfe1 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -1924,9 +1924,11 @@
errors, params = self.__check_param_values( trans, incoming, state, old_errors )
- # Did the user actually click next / execute or is this just
- # a refresh?
- if 'runtool_btn' in incoming or 'URL' in incoming or 'ajax_upload' in incoming:
+ if self.__should_refresh_state( incoming ):
+ return self.__handle_state_refresh( trans, state, errors )
+ else:
+ # User actually clicked next or execute.
+
# If there were errors, we stay on the same page and display
# error messages
if errors:
@@ -1962,7 +1964,11 @@
if not self.display_interface:
return 'message.mako', dict( status='info', message="The interface for this tool cannot be displayed", refresh_frames=['everything'] )
return 'tool_form.mako', dict( errors=errors, tool_state=state )
- else:
+
+ def __should_refresh_state( self, incoming ):
+ return not( 'runtool_btn' in incoming or 'URL' in incoming or 'ajax_upload' in incoming )
+
+ def __handle_state_refresh( self, trans, state, errors ):
try:
self.find_fieldstorage( state.inputs )
except InterruptedUpload:
@@ -1974,7 +1980,7 @@
pass
# Just a refresh, render the form with updated state and errors.
if not self.display_interface:
- return 'message.mako', dict( status='info', message="The interface for this tool cannot be displayed", refresh_frames=['everything'] )
+ return 'message.mako', dict( status='info', message="The interface for this tool cannot be displayed", refresh_frames=['everything'] )
return 'tool_form.mako', dict( errors=errors, tool_state=state )
def __fetch_state( self, trans, incoming, history ):
https://bitbucket.org/galaxy/galaxy-central/commits/2cf8be3f467b/
Changeset: 2cf8be3f467b
User: jmchilton
Date: 2013-11-11 08:45:32
Summary: Break up tools.handle_input - split out page advance logic.
Affected #: 1 file
diff -r c4632090a444751660a354e997873da5fd14cfe1 -r 2cf8be3f467ba645d175782ae4c85d942c0cd88f lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -1958,12 +1958,7 @@
return 'message.mako', dict( status='error', message=message, refresh_frames=[] )
# Otherwise move on to the next page
else:
- state.page += 1
- # Fill in the default values for the next page
- self.fill_in_new_state( trans, self.inputs_by_page[ state.page ], state.inputs )
- if not self.display_interface:
- return 'message.mako', dict( status='info', message="The interface for this tool cannot be displayed", refresh_frames=['everything'] )
- return 'tool_form.mako', dict( errors=errors, tool_state=state )
+ return self.__handle_page_advance( trans, state, errors )
def __should_refresh_state( self, incoming ):
return not( 'runtool_btn' in incoming or 'URL' in incoming or 'ajax_upload' in incoming )
@@ -1983,6 +1978,14 @@
return 'message.mako', dict( status='info', message="The interface for this tool cannot be displayed", refresh_frames=['everything'] )
return 'tool_form.mako', dict( errors=errors, tool_state=state )
+ def __handle_page_advance( self, trans, state, errors ):
+ state.page += 1
+ # Fill in the default values for the next page
+ self.fill_in_new_state( trans, self.inputs_by_page[ state.page ], state.inputs )
+ if not self.display_interface:
+ return 'message.mako', dict( status='info', message="The interface for this tool cannot be displayed", refresh_frames=['everything'] )
+ return 'tool_form.mako', dict( errors=errors, tool_state=state )
+
def __fetch_state( self, trans, incoming, history ):
# Get the state or create if not found
if "tool_state" in incoming:
https://bitbucket.org/galaxy/galaxy-central/commits/5541fd3245c5/
Changeset: 5541fd3245c5
User: jmchilton
Date: 2013-11-11 08:45:32
Summary: Break up tools.handle_input - split out actual tool execution intiation.
Affected #: 1 file
diff -r 2cf8be3f467ba645d175782ae4c85d942c0cd88f -r 5541fd3245c571c1cbe7a51faa734cd6aa052d4e lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -1936,26 +1936,7 @@
return "tool_form.mako", dict( errors=errors, tool_state=state, incoming=incoming, error_message=error_message )
# If we've completed the last page we can execute the tool
elif state.page == self.last_page:
- try:
- rerun_remap_job_id = None
- if 'rerun_remap_job_id' in incoming:
- rerun_remap_job_id = trans.app.security.decode_id(incoming['rerun_remap_job_id'])
- _, out_data = self.execute( trans, incoming=params, history=history, rerun_remap_job_id=rerun_remap_job_id )
- except httpexceptions.HTTPFound, e:
- #if it's a paste redirect exception, pass it up the stack
- raise e
- except Exception, e:
- log.exception('Exception caught while attempting tool execution:')
- return 'message.mako', dict( status='error', message='Error executing tool: %s' % str(e), refresh_frames=[] )
- try:
- assert isinstance( out_data, odict )
- return 'tool_executed.mako', dict( out_data=out_data )
- except:
- if isinstance( out_data, str ):
- message = out_data
- else:
- message = 'Failure executing tool (odict not returned from tool execution)'
- return 'message.mako', dict( status='error', message=message, refresh_frames=[] )
+ return self.__handle_tool_execute( trans, incoming, params, history )
# Otherwise move on to the next page
else:
return self.__handle_page_advance( trans, state, errors )
@@ -1963,6 +1944,28 @@
def __should_refresh_state( self, incoming ):
return not( 'runtool_btn' in incoming or 'URL' in incoming or 'ajax_upload' in incoming )
+ def __handle_tool_execute( self, trans, incoming, params, history ):
+ try:
+ rerun_remap_job_id = None
+ if 'rerun_remap_job_id' in incoming:
+ rerun_remap_job_id = trans.app.security.decode_id(incoming['rerun_remap_job_id'])
+ _, out_data = self.execute( trans, incoming=params, history=history, rerun_remap_job_id=rerun_remap_job_id )
+ except httpexceptions.HTTPFound, e:
+ #if it's a paste redirect exception, pass it up the stack
+ raise e
+ except Exception, e:
+ log.exception('Exception caught while attempting tool execution:')
+ return 'message.mako', dict( status='error', message='Error executing tool: %s' % str(e), refresh_frames=[] )
+ try:
+ assert isinstance( out_data, odict )
+ return 'tool_executed.mako', dict( out_data=out_data )
+ except:
+ if isinstance( out_data, str ):
+ message = out_data
+ else:
+ message = 'Failure executing tool (odict not returned from tool execution)'
+ return 'message.mako', dict( status='error', message=message, refresh_frames=[] )
+
def __handle_state_refresh( self, trans, state, errors ):
try:
self.find_fieldstorage( state.inputs )
https://bitbucket.org/galaxy/galaxy-central/commits/d4f8824c11b1/
Changeset: d4f8824c11b1
User: jmchilton
Date: 2013-11-11 08:45:32
Summary: Don't pass API key to datatype display method.
Some datatypes cannot take the keyword parameter and none of them should need it.
Affected #: 1 file
diff -r 5541fd3245c571c1cbe7a51faa734cd6aa052d4e -r d4f8824c11b1cb868f3a0a06c3d533cad123ccee lib/galaxy/webapps/galaxy/api/datasets.py
--- a/lib/galaxy/webapps/galaxy/api/datasets.py
+++ b/lib/galaxy/webapps/galaxy/api/datasets.py
@@ -269,7 +269,13 @@
hda = self.get_history_dataset_association( trans, history, history_content_id,
check_ownership=True, check_accessible=True )
- rval = hda.datatype.display_data( trans, hda, preview, filename, to_ext, chunk, **kwd )
+ display_kwd = kwd.copy()
+ try:
+ del display_kwd["key"]
+ except KeyError:
+ pass
+ rval = hda.datatype.display_data( trans, hda, preview, filename, to_ext, chunk, **display_kwd )
+
except Exception, exception:
log.error( "Error getting display data for dataset (%s) from history (%s): %s",
https://bitbucket.org/galaxy/galaxy-central/commits/4f7e715db123/
Changeset: 4f7e715db123
User: jmchilton
Date: 2013-11-11 08:45:32
Summary: Allow easier use of tool repeat and conditional params via the API.
For now, still using the flat format of web ui. So
{...
"a_repeat_0|a_repeat_param" : "value"
}
instead of the more ideal:
{...
a_repeat: [
{ "a_repeat_param": "value" }
]
}
To implement this, there is a new path through the tool state processing code that sets the state based on the supplied inputs instead of requiring iterative calls (one for each repeat addition for instance) like the UI or specifing a tool_state externally. To specify this path through the code, simply do not include a tool_state parameter when using the tools API.
Affected #: 2 files
diff -r d4f8824c11b1cb868f3a0a06c3d533cad123ccee -r 4f7e715db123cb3d31258fbe828854c36719af9e lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -1901,12 +1901,18 @@
callback( "", input, value[input.name] )
else:
input.visit_inputs( "", value[input.name], callback )
- def handle_input( self, trans, incoming, history=None, old_errors=None ):
+ def handle_input( self, trans, incoming, history=None, old_errors=None, process_state='update' ):
"""
Process incoming parameters for this tool from the dict `incoming`,
update the tool state (or create if none existed), and either return
to the form or execute the tool (only if 'execute' was clicked and
there were no errors).
+
+ process_state can be either 'update' (to incrementally build up the state
+ over several calls - one repeat per handle for instance) or 'populate'
+ force a complete build of the state and submission all at once (like
+ from API). May want an incremental version of the API also at some point,
+ that is why this is not just called for_api.
"""
state, state_new = self.__fetch_state( trans, incoming, history )
if state_new:
@@ -1922,8 +1928,7 @@
self.update_state( trans, self.inputs_by_page[state.page], state.inputs, incoming, old_errors=old_errors or {} )
return "tool_form.mako", dict( errors={}, tool_state=state, param_values={}, incoming={} )
- errors, params = self.__check_param_values( trans, incoming, state, old_errors )
-
+ errors, params = self.__check_param_values( trans, incoming, state, old_errors, process_state, history=history )
if self.__should_refresh_state( incoming ):
return self.__handle_state_refresh( trans, state, errors )
else:
@@ -2001,7 +2006,7 @@
new = True
return state, new
- def __check_param_values( self, trans, incoming, state, old_errors ):
+ def __check_param_values( self, trans, incoming, state, old_errors, process_state, history ):
# Process incoming data
if not( self.check_values ):
# If `self.check_values` is false we don't do any checking or
@@ -2014,7 +2019,12 @@
else:
# Update state for all inputs on the current page taking new
# values from `incoming`.
- errors = self.update_state( trans, self.inputs_by_page[state.page], state.inputs, incoming, old_errors=old_errors or {} )
+ if process_state == "update":
+ errors = self.update_state( trans, self.inputs_by_page[state.page], state.inputs, incoming, old_errors=old_errors or {} )
+ elif process_state == "populate":
+ errors = self.populate_state( trans, self.inputs_by_page[state.page], state.inputs, incoming, history )
+ else:
+ raise Exception("Unknown process_state type %s" % process_state)
# If the tool provides a `validate_input` hook, call it.
validate_input = self.get_hook( 'validate_input' )
if validate_input:
@@ -2059,6 +2069,137 @@
return 'message.mako', dict( status='error',
message='Your upload was interrupted. If this was uninentional, please retry it.',
refresh_frames=[], cont=None )
+
+ def populate_state( self, trans, inputs, state, incoming, history, prefix="", context=None ):
+ errors = dict()
+ # Push this level onto the context stack
+ context = ExpressionContext( state, context )
+ for input in inputs.itervalues():
+ key = prefix + input.name
+ if isinstance( input, Repeat ):
+ group_state = state[input.name]
+ # Create list of empty errors for each previously existing state
+ group_errors = [ ]
+ any_group_errors = False
+ rep_index = 0
+ while True:
+ rep_name = "%s_%d" % ( key, rep_index )
+ if not any( [ key.startswith(rep_name) for key in incoming.keys() ] ):
+ break
+ if rep_index < input.max:
+ new_state = {}
+ new_state['__index__'] = rep_index
+ self.fill_in_new_state( trans, input.inputs, new_state, context, history=history )
+ group_state.append( new_state )
+ group_errors.append( {} )
+ rep_errors = self.populate_state( trans,
+ input.inputs,
+ new_state,
+ incoming,
+ history,
+ prefix=rep_name + "|",
+ context=context )
+ if rep_errors:
+ any_group_errors = True
+ group_errors[rep_index].update( rep_errors )
+
+ else:
+ group_errors[-1] = { '__index__': 'Cannot add repeat (max size=%i).' % input.max }
+ any_group_errors = True
+ rep_index += 1
+ elif isinstance( input, Conditional ):
+ group_state = state[input.name]
+ group_prefix = "%s|" % ( key )
+ # Deal with the 'test' element and see if it's value changed
+ if input.value_ref and not input.value_ref_in_group:
+ # We are referencing an existent parameter, which is not
+ # part of this group
+ test_param_key = prefix + input.test_param.name
+ else:
+ test_param_key = group_prefix + input.test_param.name
+ test_param_error = None
+ test_incoming = get_incoming_value( incoming, test_param_key, None )
+
+ # Get value of test param and determine current case
+ value, test_param_error = \
+ check_param( trans, input.test_param, test_incoming, context )
+ current_case = input.get_current_case( value, trans )
+ # Current case has changed, throw away old state
+ group_state = state[input.name] = {}
+ # TODO: we should try to preserve values if we can
+ self.fill_in_new_state( trans, input.cases[current_case].inputs, group_state, context, history=history )
+ group_errors = self.populate_state( trans,
+ input.cases[current_case].inputs,
+ group_state,
+ incoming,
+ history,
+ prefix=group_prefix,
+ context=context,
+ )
+ if test_param_error:
+ group_errors[ input.test_param.name ] = test_param_error
+ if group_errors:
+ errors[ input.name ] = group_errors
+ # Store the current case in a special value
+ group_state['__current_case__'] = current_case
+ # Store the value of the test element
+ group_state[ input.test_param.name ] = value
+ elif isinstance( input, UploadDataset ):
+ group_state = state[input.name]
+ group_errors = []
+ any_group_errors = False
+ d_type = input.get_datatype( trans, context )
+ writable_files = d_type.writable_files
+ #remove extra files
+ while len( group_state ) > len( writable_files ):
+ del group_state[-1]
+ # Update state
+ max_index = -1
+ for i, rep_state in enumerate( group_state ):
+ rep_index = rep_state['__index__']
+ max_index = max( max_index, rep_index )
+ rep_prefix = "%s_%d|" % ( key, rep_index )
+ rep_errors = self.populate_state( trans,
+ input.inputs,
+ rep_state,
+ incoming,
+ history,
+ prefix=rep_prefix,
+ context=context)
+ if rep_errors:
+ any_group_errors = True
+ group_errors.append( rep_errors )
+ else:
+ group_errors.append( {} )
+ # Add new fileupload as needed
+ offset = 1
+ while len( writable_files ) > len( group_state ):
+ new_state = {}
+ new_state['__index__'] = max_index + offset
+ offset += 1
+ self.fill_in_new_state( trans, input.inputs, new_state, context )
+ group_state.append( new_state )
+ if any_group_errors:
+ group_errors.append( {} )
+ # Were there *any* errors for any repetition?
+ if any_group_errors:
+ errors[input.name] = group_errors
+ else:
+ if key not in incoming \
+ and "__force_update__" + key not in incoming:
+ # No new value provided, and we are only updating, so keep
+ # the old value (which should already be in the state) and
+ # preserve the old error message.
+ pass
+ else:
+ incoming_value = get_incoming_value( incoming, key, None )
+ value, error = check_param( trans, input, incoming_value, context )
+ # If a callback was provided, allow it to process the value
+ if error:
+ errors[ input.name ] = error
+ state[ input.name ] = value
+ return errors
+
def update_state( self, trans, inputs, state, incoming, prefix="", context=None,
update_only=False, old_errors={}, item_callback=None ):
"""
diff -r d4f8824c11b1cb868f3a0a06c3d533cad123ccee -r 4f7e715db123cb3d31258fbe828854c36719af9e lib/galaxy/webapps/galaxy/api/tools.py
--- a/lib/galaxy/webapps/galaxy/api/tools.py
+++ b/lib/galaxy/webapps/galaxy/api/tools.py
@@ -9,6 +9,9 @@
import logging
log = logging.getLogger( __name__ )
+DEFAULT_STATE_PROCESSING = "update" # See comment below.
+
+
class ToolsController( BaseAPIController, UsesVisualizationMixin ):
"""
RESTful controller for interactions with tools.
@@ -113,7 +116,15 @@
# TODO: encode data ids and decode ids.
# TODO: handle dbkeys
params = util.Params( inputs, sanitize = False )
- template, vars = tool.handle_input( trans, params.__dict__, history=target_history )
+ # process_state must be 'populate' or 'update'. If 'populate', fully
+ # expand repeat and conditionals when building up state, if 'update'
+ # state must be built up over several iterative calls to the API -
+ # mimicing behavior of web controller. Mimic the the web controller
+ # and modify state outright if "tool_state" is contain in input params,
+ # else "populate" the tool state from scratch using payload.
+ incoming = params.__dict__
+ process_state = "update" if "tool_state" in incoming else "populate"
+ template, vars = tool.handle_input( trans, incoming, history=target_history, process_state=process_state )
if 'errors' in vars:
trans.response.status = 400
return { "message": { "type": "error", "data" : vars[ 'errors' ] } }
https://bitbucket.org/galaxy/galaxy-central/commits/336525248012/
Changeset: 336525248012
User: jmchilton
Date: 2013-11-11 08:45:32
Summary: When parsing tool inputs - distinguish between those coming from HTML post and those from JSON.
Most of the time they have the same value parsing rules right now, but the parsing rules for booleans would kind of hackish if applied to JSON clients (only a list with two values is considered true). Ultimately this could simplify from_html in DataToolParameter which has grown unwieldy.
TODO: Refactor state building logic out into its own class, too many variables are being passed around over and over at this point.
Affected #: 4 files
diff -r 4f7e715db123cb3d31258fbe828854c36719af9e -r 33652524801287703e2abefecf2c676243c83b25 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -1901,7 +1901,7 @@
callback( "", input, value[input.name] )
else:
input.visit_inputs( "", value[input.name], callback )
- def handle_input( self, trans, incoming, history=None, old_errors=None, process_state='update' ):
+ def handle_input( self, trans, incoming, history=None, old_errors=None, process_state='update', source='html' ):
"""
Process incoming parameters for this tool from the dict `incoming`,
update the tool state (or create if none existed), and either return
@@ -1925,10 +1925,10 @@
if not self.display_interface:
return 'message.mako', dict( status='info', message="The interface for this tool cannot be displayed", refresh_frames=['everything'] )
if len(incoming):
- self.update_state( trans, self.inputs_by_page[state.page], state.inputs, incoming, old_errors=old_errors or {} )
+ self.update_state( trans, self.inputs_by_page[state.page], state.inputs, incoming, old_errors=old_errors or {}, source=source )
return "tool_form.mako", dict( errors={}, tool_state=state, param_values={}, incoming={} )
- errors, params = self.__check_param_values( trans, incoming, state, old_errors, process_state, history=history )
+ errors, params = self.__check_param_values( trans, incoming, state, old_errors, process_state, history=history, source=source )
if self.__should_refresh_state( incoming ):
return self.__handle_state_refresh( trans, state, errors )
else:
@@ -2006,7 +2006,7 @@
new = True
return state, new
- def __check_param_values( self, trans, incoming, state, old_errors, process_state, history ):
+ def __check_param_values( self, trans, incoming, state, old_errors, process_state, history, source ):
# Process incoming data
if not( self.check_values ):
# If `self.check_values` is false we don't do any checking or
@@ -2020,9 +2020,9 @@
# Update state for all inputs on the current page taking new
# values from `incoming`.
if process_state == "update":
- errors = self.update_state( trans, self.inputs_by_page[state.page], state.inputs, incoming, old_errors=old_errors or {} )
+ errors = self.update_state( trans, self.inputs_by_page[state.page], state.inputs, incoming, old_errors=old_errors or {}, source=source )
elif process_state == "populate":
- errors = self.populate_state( trans, self.inputs_by_page[state.page], state.inputs, incoming, history )
+ errors = self.populate_state( trans, self.inputs_by_page[state.page], state.inputs, incoming, history, source=source )
else:
raise Exception("Unknown process_state type %s" % process_state)
# If the tool provides a `validate_input` hook, call it.
@@ -2070,7 +2070,7 @@
message='Your upload was interrupted. If this was uninentional, please retry it.',
refresh_frames=[], cont=None )
- def populate_state( self, trans, inputs, state, incoming, history, prefix="", context=None ):
+ def populate_state( self, trans, inputs, state, incoming, history, source, prefix="", context=None ):
errors = dict()
# Push this level onto the context stack
context = ExpressionContext( state, context )
@@ -2097,6 +2097,7 @@
new_state,
incoming,
history,
+ source,
prefix=rep_name + "|",
context=context )
if rep_errors:
@@ -2122,7 +2123,7 @@
# Get value of test param and determine current case
value, test_param_error = \
- check_param( trans, input.test_param, test_incoming, context )
+ check_param( trans, input.test_param, test_incoming, context, source=source )
current_case = input.get_current_case( value, trans )
# Current case has changed, throw away old state
group_state = state[input.name] = {}
@@ -2133,6 +2134,7 @@
group_state,
incoming,
history,
+ source,
prefix=group_prefix,
context=context,
)
@@ -2164,6 +2166,7 @@
rep_state,
incoming,
history,
+ source,
prefix=rep_prefix,
context=context)
if rep_errors:
@@ -2193,14 +2196,14 @@
pass
else:
incoming_value = get_incoming_value( incoming, key, None )
- value, error = check_param( trans, input, incoming_value, context )
+ value, error = check_param( trans, input, incoming_value, context, source=source )
# If a callback was provided, allow it to process the value
if error:
errors[ input.name ] = error
state[ input.name ] = value
return errors
- def update_state( self, trans, inputs, state, incoming, prefix="", context=None,
+ def update_state( self, trans, inputs, state, incoming, source='html', prefix="", context=None,
update_only=False, old_errors={}, item_callback=None ):
"""
Update the tool state in `state` using the user input in `incoming`.
@@ -2258,6 +2261,7 @@
input.inputs,
rep_state,
incoming,
+ source=source,
prefix=rep_prefix,
context=context,
update_only=update_only,
@@ -2306,7 +2310,7 @@
else:
# Get value of test param and determine current case
value, test_param_error = \
- check_param( trans, input.test_param, test_incoming, context )
+ check_param( trans, input.test_param, test_incoming, context, source=source )
current_case = input.get_current_case( value, trans )
if current_case != old_current_case:
# Current case has changed, throw away old state
@@ -2323,6 +2327,7 @@
incoming,
prefix=group_prefix,
context=context,
+ source=source,
update_only=update_only,
old_errors=group_old_errors,
item_callback=item_callback )
@@ -2364,6 +2369,7 @@
incoming,
prefix=rep_prefix,
context=context,
+ source=source,
update_only=update_only,
old_errors=rep_old_errors,
item_callback=item_callback )
@@ -2396,7 +2402,7 @@
errors[ input.name ] = old_errors[ input.name ]
else:
incoming_value = get_incoming_value( incoming, key, None )
- value, error = check_param( trans, input, incoming_value, context )
+ value, error = check_param( trans, input, incoming_value, context, source=source )
# If a callback was provided, allow it to process the value
if item_callback:
old_value = state.get( input.name, None )
diff -r 4f7e715db123cb3d31258fbe828854c36719af9e -r 33652524801287703e2abefecf2c676243c83b25 lib/galaxy/tools/parameters/__init__.py
--- a/lib/galaxy/tools/parameters/__init__.py
+++ b/lib/galaxy/tools/parameters/__init__.py
@@ -40,7 +40,7 @@
if new_value:
input_values[input.name] = new_value
-def check_param( trans, param, incoming_value, param_values ):
+def check_param( trans, param, incoming_value, param_values, source='html' ):
"""
Check the value of a single parameter `param`. The value in
`incoming_value` is converted from its HTML encoding and validated.
@@ -53,7 +53,10 @@
try:
if value is not None or isinstance(param, DataToolParameter):
# Convert value from HTML representation
- value = param.from_html( value, trans, param_values )
+ if source == 'html':
+ value = param.from_html( value, trans, param_values )
+ else:
+ value = param.from_json( value, trans, param_values )
# Allow the value to be converted if neccesary
filtered_value = param.filter_value( value, trans, param_values )
# Then do any further validation on the value
diff -r 4f7e715db123cb3d31258fbe828854c36719af9e -r 33652524801287703e2abefecf2c676243c83b25 lib/galaxy/tools/parameters/basic.py
--- a/lib/galaxy/tools/parameters/basic.py
+++ b/lib/galaxy/tools/parameters/basic.py
@@ -81,6 +81,9 @@
"""
return value
+ def from_json( self, value, trans=None, other_values={} ):
+ return self.from_html( value, trans, other_values )
+
def get_initial_value( self, trans, context, history=None ):
"""
Return the starting value of the parameter
@@ -427,6 +430,9 @@
def from_html( self, value, trans=None, other_values={} ):
return form_builder.CheckboxField.is_checked( value )
+ def from_json( self, value, trans=None, other_values={} ):
+ return string_as_bool( value )
+
def to_html_value( self, value, app ):
if value:
return [ 'true', 'true' ]
diff -r 4f7e715db123cb3d31258fbe828854c36719af9e -r 33652524801287703e2abefecf2c676243c83b25 lib/galaxy/webapps/galaxy/api/tools.py
--- a/lib/galaxy/webapps/galaxy/api/tools.py
+++ b/lib/galaxy/webapps/galaxy/api/tools.py
@@ -124,7 +124,7 @@
# else "populate" the tool state from scratch using payload.
incoming = params.__dict__
process_state = "update" if "tool_state" in incoming else "populate"
- template, vars = tool.handle_input( trans, incoming, history=target_history, process_state=process_state )
+ template, vars = tool.handle_input( trans, incoming, history=target_history, process_state=process_state, source="json" )
if 'errors' in vars:
trans.response.status = 400
return { "message": { "type": "error", "data" : vars[ 'errors' ] } }
https://bitbucket.org/galaxy/galaxy-central/commits/9e503de59f9b/
Changeset: 9e503de59f9b
User: jmchilton
Date: 2013-11-11 08:45:32
Summary: Allow raw display of data via API.
Matching functionality available with sessions at /display in root controller. The test framework uses this functionality in root controller to read test result data so an API driven approach to testing will need to have similar functionality available. I am not sure I am enitrely comfortable with serving raw data this way, but I guess it is no worse than the existing /display route. This is marked as beta and there is a note that it may be dropped at some point in the future.
Affected #: 1 file
diff -r 33652524801287703e2abefecf2c676243c83b25 -r 9e503de59f9b939e81cfa26645d7595d3c8a5df8 lib/galaxy/webapps/galaxy/api/datasets.py
--- a/lib/galaxy/webapps/galaxy/api/datasets.py
+++ b/lib/galaxy/webapps/galaxy/api/datasets.py
@@ -7,7 +7,7 @@
from galaxy.web.base.controller import UsesHistoryMixin
from galaxy.web.framework.helpers import is_true
from galaxy.datatypes import dataproviders
-
+from galaxy.util import string_as_bool_or_none
import logging
log = logging.getLogger( __name__ )
@@ -245,11 +245,16 @@
@web.expose_api_raw_anonymous
def display( self, trans, history_content_id, history_id,
- preview=False, filename=None, to_ext=None, chunk=None, **kwd ):
+ preview=False, filename=None, to_ext=None, chunk=None, raw=False, **kwd ):
"""
GET /api/histories/{encoded_history_id}/contents/{encoded_content_id}/display
Displays history content (dataset).
+
+ The query parameter 'raw' should be considered experimental and may be dropped at
+ some point in the future without warning. Generally, data should be processed by its
+ datatype prior to display (the defult if raw is unspecified or explicitly false.
"""
+ raw = string_as_bool_or_none( raw )
# Huge amount of code overlap with lib/galaxy/webapps/galaxy/api/history_content:show here.
rval = ''
try:
@@ -274,8 +279,10 @@
del display_kwd["key"]
except KeyError:
pass
- rval = hda.datatype.display_data( trans, hda, preview, filename, to_ext, chunk, **display_kwd )
-
+ if raw:
+ rval = open( hda.file_name )
+ else:
+ rval = hda.datatype.display_data( trans, hda, preview, filename, to_ext, chunk, **display_kwd )
except Exception, exception:
log.error( "Error getting display data for dataset (%s) from history (%s): %s",
https://bitbucket.org/galaxy/galaxy-central/commits/468fe654a360/
Changeset: 468fe654a360
User: jmchilton
Date: 2013-11-11 08:45:32
Summary: Fix specifing dbkeys with API uploads.
Essentially a redo of changeset 83103cff8757. In order to fix uploads when now history was specified, the only available dbkey allowed was '?'. As a result of that changeset, when uploading files via the API users could only specify '?'. Now the stock dbbuilds are also available - though builds in the history are still not aviailable (TODO) and user custom builds may not be available (TODO check this).
Affected #: 2 files
diff -r 9e503de59f9b939e81cfa26645d7595d3c8a5df8 -r 468fe654a360f41e5f20f40d2b1461a074076969 lib/galaxy/tools/parameters/basic.py
--- a/lib/galaxy/tools/parameters/basic.py
+++ b/lib/galaxy/tools/parameters/basic.py
@@ -1023,16 +1023,13 @@
self.static_options = [ ( value, key, False ) for key, value in util.dbnames ]
def get_options( self, trans, other_values ):
- if not trans.history:
- yield 'unspecified', '?', False
- else:
+ last_used_build = object()
+ if trans.history:
last_used_build = trans.history.genome_build
- for dbkey, build_name in trans.db_builds:
- yield build_name, dbkey, ( dbkey == last_used_build )
+ for dbkey, build_name in trans.db_builds:
+ yield build_name, dbkey, ( dbkey == last_used_build )
def get_legal_values( self, trans, other_values ):
- if not trans.history:
- return set( '?' )
return set( dbkey for dbkey, _ in trans.db_builds )
def to_dict( self, trans, view='collection', value_mapper=None ):
diff -r 9e503de59f9b939e81cfa26645d7595d3c8a5df8 -r 468fe654a360f41e5f20f40d2b1461a074076969 lib/galaxy/web/framework/__init__.py
--- a/lib/galaxy/web/framework/__init__.py
+++ b/lib/galaxy/web/framework/__init__.py
@@ -1070,10 +1070,11 @@
the user (chromInfo in history).
"""
dbnames = list()
- datasets = self.sa_session.query( self.app.model.HistoryDatasetAssociation ) \
- .filter_by( deleted=False, history_id=self.history.id, extension="len" )
- for dataset in datasets:
- dbnames.append( (dataset.dbkey, dataset.name) )
+ if self.history:
+ datasets = self.sa_session.query( self.app.model.HistoryDatasetAssociation ) \
+ .filter_by( deleted=False, history_id=self.history.id, extension="len" )
+ for dataset in datasets:
+ dbnames.append( (dataset.dbkey, dataset.name) )
user = self.get_user()
if user and 'dbkeys' in user.preferences:
user_keys = from_json_string( user.preferences['dbkeys'] )
https://bitbucket.org/galaxy/galaxy-central/commits/2769dec77197/
Changeset: 2769dec77197
User: jmchilton
Date: 2013-11-14 19:32:24
Summary: Clean up 4f7e715 slightly.
Affected #: 1 file
diff -r 468fe654a360f41e5f20f40d2b1461a074076969 -r 2769dec771976d29ac5904bff55fa448672d8bd6 lib/galaxy/webapps/galaxy/api/tools.py
--- a/lib/galaxy/webapps/galaxy/api/tools.py
+++ b/lib/galaxy/webapps/galaxy/api/tools.py
@@ -9,8 +9,6 @@
import logging
log = logging.getLogger( __name__ )
-DEFAULT_STATE_PROCESSING = "update" # See comment below.
-
class ToolsController( BaseAPIController, UsesVisualizationMixin ):
"""
@@ -116,12 +114,16 @@
# TODO: encode data ids and decode ids.
# TODO: handle dbkeys
params = util.Params( inputs, sanitize = False )
- # process_state must be 'populate' or 'update'. If 'populate', fully
- # expand repeat and conditionals when building up state, if 'update'
- # state must be built up over several iterative calls to the API -
- # mimicing behavior of web controller. Mimic the the web controller
- # and modify state outright if "tool_state" is contain in input params,
- # else "populate" the tool state from scratch using payload.
+ # process_state will be 'populate' or 'update'. When no tool
+ # state is specified in input - it will be 'populate', and
+ # tool will fully expand repeat and conditionals when building
+ # up state. If tool state is found in input
+ # parameters,process_state will be 'update' and complex
+ # submissions (with repeats and conditionals) must be built up
+ # over several iterative calls to the API - mimicing behavior
+ # of web controller (though frankly API never returns
+ # tool_state so this "legacy" behavior is probably impossible
+ # through API currently).
incoming = params.__dict__
process_state = "update" if "tool_state" in incoming else "populate"
template, vars = tool.handle_input( trans, incoming, history=target_history, process_state=process_state, source="json" )
https://bitbucket.org/galaxy/galaxy-central/commits/3402a11b0088/
Changeset: 3402a11b0088
User: jmchilton
Date: 2013-11-14 19:34:05
Summary: Merged in jmchilton/galaxy-central-fork-1 (pull request #256)
API Enhancements Required for API Driven Tool Testing
Affected #: 9 files
diff -r ac744f96faa5d4a61c73ca2e20655f818af3dddd -r 3402a11b008865ee37ee29c9d7d3d5ea27c6fe84 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -1901,20 +1901,21 @@
callback( "", input, value[input.name] )
else:
input.visit_inputs( "", value[input.name], callback )
- def handle_input( self, trans, incoming, history=None, old_errors=None ):
+ def handle_input( self, trans, incoming, history=None, old_errors=None, process_state='update', source='html' ):
"""
Process incoming parameters for this tool from the dict `incoming`,
update the tool state (or create if none existed), and either return
to the form or execute the tool (only if 'execute' was clicked and
there were no errors).
+
+ process_state can be either 'update' (to incrementally build up the state
+ over several calls - one repeat per handle for instance) or 'populate'
+ force a complete build of the state and submission all at once (like
+ from API). May want an incremental version of the API also at some point,
+ that is why this is not just called for_api.
"""
- # Get the state or create if not found
- if "tool_state" in incoming:
- encoded_state = string_to_object( incoming["tool_state"] )
- state = DefaultToolState()
- state.decode( encoded_state, self, trans.app )
- else:
- state = self.new_state( trans, history=history )
+ state, state_new = self.__fetch_state( trans, incoming, history )
+ if state_new:
# This feels a bit like a hack. It allows forcing full processing
# of inputs even when there is no state in the incoming dictionary
# by providing either 'runtool_btn' (the name of the submit button
@@ -1924,8 +1925,88 @@
if not self.display_interface:
return 'message.mako', dict( status='info', message="The interface for this tool cannot be displayed", refresh_frames=['everything'] )
if len(incoming):
- self.update_state( trans, self.inputs_by_page[state.page], state.inputs, incoming, old_errors=old_errors or {} )
+ self.update_state( trans, self.inputs_by_page[state.page], state.inputs, incoming, old_errors=old_errors or {}, source=source )
return "tool_form.mako", dict( errors={}, tool_state=state, param_values={}, incoming={} )
+
+ errors, params = self.__check_param_values( trans, incoming, state, old_errors, process_state, history=history, source=source )
+ if self.__should_refresh_state( incoming ):
+ return self.__handle_state_refresh( trans, state, errors )
+ else:
+ # User actually clicked next or execute.
+
+ # If there were errors, we stay on the same page and display
+ # error messages
+ if errors:
+ error_message = "One or more errors were found in the input you provided. The specific errors are marked below."
+ return "tool_form.mako", dict( errors=errors, tool_state=state, incoming=incoming, error_message=error_message )
+ # If we've completed the last page we can execute the tool
+ elif state.page == self.last_page:
+ return self.__handle_tool_execute( trans, incoming, params, history )
+ # Otherwise move on to the next page
+ else:
+ return self.__handle_page_advance( trans, state, errors )
+
+ def __should_refresh_state( self, incoming ):
+ return not( 'runtool_btn' in incoming or 'URL' in incoming or 'ajax_upload' in incoming )
+
+ def __handle_tool_execute( self, trans, incoming, params, history ):
+ try:
+ rerun_remap_job_id = None
+ if 'rerun_remap_job_id' in incoming:
+ rerun_remap_job_id = trans.app.security.decode_id(incoming['rerun_remap_job_id'])
+ _, out_data = self.execute( trans, incoming=params, history=history, rerun_remap_job_id=rerun_remap_job_id )
+ except httpexceptions.HTTPFound, e:
+ #if it's a paste redirect exception, pass it up the stack
+ raise e
+ except Exception, e:
+ log.exception('Exception caught while attempting tool execution:')
+ return 'message.mako', dict( status='error', message='Error executing tool: %s' % str(e), refresh_frames=[] )
+ try:
+ assert isinstance( out_data, odict )
+ return 'tool_executed.mako', dict( out_data=out_data )
+ except:
+ if isinstance( out_data, str ):
+ message = out_data
+ else:
+ message = 'Failure executing tool (odict not returned from tool execution)'
+ return 'message.mako', dict( status='error', message=message, refresh_frames=[] )
+
+ def __handle_state_refresh( self, trans, state, errors ):
+ try:
+ self.find_fieldstorage( state.inputs )
+ except InterruptedUpload:
+ # If inputs contain a file it won't persist. Most likely this
+ # is an interrupted upload. We should probably find a more
+ # standard method of determining an incomplete POST.
+ return self.handle_interrupted( trans, state.inputs )
+ except:
+ pass
+ # Just a refresh, render the form with updated state and errors.
+ if not self.display_interface:
+ return 'message.mako', dict( status='info', message="The interface for this tool cannot be displayed", refresh_frames=['everything'] )
+ return 'tool_form.mako', dict( errors=errors, tool_state=state )
+
+ def __handle_page_advance( self, trans, state, errors ):
+ state.page += 1
+ # Fill in the default values for the next page
+ self.fill_in_new_state( trans, self.inputs_by_page[ state.page ], state.inputs )
+ if not self.display_interface:
+ return 'message.mako', dict( status='info', message="The interface for this tool cannot be displayed", refresh_frames=['everything'] )
+ return 'tool_form.mako', dict( errors=errors, tool_state=state )
+
+ def __fetch_state( self, trans, incoming, history ):
+ # Get the state or create if not found
+ if "tool_state" in incoming:
+ encoded_state = string_to_object( incoming["tool_state"] )
+ state = DefaultToolState()
+ state.decode( encoded_state, self, trans.app )
+ new = False
+ else:
+ state = self.new_state( trans, history=history )
+ new = True
+ return state, new
+
+ def __check_param_values( self, trans, incoming, state, old_errors, process_state, history, source ):
# Process incoming data
if not( self.check_values ):
# If `self.check_values` is false we don't do any checking or
@@ -1938,64 +2019,19 @@
else:
# Update state for all inputs on the current page taking new
# values from `incoming`.
- errors = self.update_state( trans, self.inputs_by_page[state.page], state.inputs, incoming, old_errors=old_errors or {} )
+ if process_state == "update":
+ errors = self.update_state( trans, self.inputs_by_page[state.page], state.inputs, incoming, old_errors=old_errors or {}, source=source )
+ elif process_state == "populate":
+ errors = self.populate_state( trans, self.inputs_by_page[state.page], state.inputs, incoming, history, source=source )
+ else:
+ raise Exception("Unknown process_state type %s" % process_state)
# If the tool provides a `validate_input` hook, call it.
validate_input = self.get_hook( 'validate_input' )
if validate_input:
validate_input( trans, errors, state.inputs, self.inputs_by_page[state.page] )
params = state.inputs
- # Did the user actually click next / execute or is this just
- # a refresh?
- if 'runtool_btn' in incoming or 'URL' in incoming or 'ajax_upload' in incoming:
- # If there were errors, we stay on the same page and display
- # error messages
- if errors:
- error_message = "One or more errors were found in the input you provided. The specific errors are marked below."
- return "tool_form.mako", dict( errors=errors, tool_state=state, incoming=incoming, error_message=error_message )
- # If we've completed the last page we can execute the tool
- elif state.page == self.last_page:
- try:
- rerun_remap_job_id = None
- if 'rerun_remap_job_id' in incoming:
- rerun_remap_job_id = trans.app.security.decode_id(incoming['rerun_remap_job_id'])
- _, out_data = self.execute( trans, incoming=params, history=history, rerun_remap_job_id=rerun_remap_job_id )
- except httpexceptions.HTTPFound, e:
- #if it's a paste redirect exception, pass it up the stack
- raise e
- except Exception, e:
- log.exception('Exception caught while attempting tool execution:')
- return 'message.mako', dict( status='error', message='Error executing tool: %s' % str(e), refresh_frames=[] )
- try:
- assert isinstance( out_data, odict )
- return 'tool_executed.mako', dict( out_data=out_data )
- except:
- if isinstance( out_data, str ):
- message = out_data
- else:
- message = 'Failure executing tool (odict not returned from tool execution)'
- return 'message.mako', dict( status='error', message=message, refresh_frames=[] )
- # Otherwise move on to the next page
- else:
- state.page += 1
- # Fill in the default values for the next page
- self.fill_in_new_state( trans, self.inputs_by_page[ state.page ], state.inputs )
- if not self.display_interface:
- return 'message.mako', dict( status='info', message="The interface for this tool cannot be displayed", refresh_frames=['everything'] )
- return 'tool_form.mako', dict( errors=errors, tool_state=state )
- else:
- try:
- self.find_fieldstorage( state.inputs )
- except InterruptedUpload:
- # If inputs contain a file it won't persist. Most likely this
- # is an interrupted upload. We should probably find a more
- # standard method of determining an incomplete POST.
- return self.handle_interrupted( trans, state.inputs )
- except:
- pass
- # Just a refresh, render the form with updated state and errors.
- if not self.display_interface:
- return 'message.mako', dict( status='info', message="The interface for this tool cannot be displayed", refresh_frames=['everything'] )
- return 'tool_form.mako', dict( errors=errors, tool_state=state )
+ return errors, params
+
def find_fieldstorage( self, x ):
if isinstance( x, FieldStorage ):
raise InterruptedUpload( None )
@@ -2033,7 +2069,141 @@
return 'message.mako', dict( status='error',
message='Your upload was interrupted. If this was uninentional, please retry it.',
refresh_frames=[], cont=None )
- def update_state( self, trans, inputs, state, incoming, prefix="", context=None,
+
+ def populate_state( self, trans, inputs, state, incoming, history, source, prefix="", context=None ):
+ errors = dict()
+ # Push this level onto the context stack
+ context = ExpressionContext( state, context )
+ for input in inputs.itervalues():
+ key = prefix + input.name
+ if isinstance( input, Repeat ):
+ group_state = state[input.name]
+ # Create list of empty errors for each previously existing state
+ group_errors = [ ]
+ any_group_errors = False
+ rep_index = 0
+ while True:
+ rep_name = "%s_%d" % ( key, rep_index )
+ if not any( [ key.startswith(rep_name) for key in incoming.keys() ] ):
+ break
+ if rep_index < input.max:
+ new_state = {}
+ new_state['__index__'] = rep_index
+ self.fill_in_new_state( trans, input.inputs, new_state, context, history=history )
+ group_state.append( new_state )
+ group_errors.append( {} )
+ rep_errors = self.populate_state( trans,
+ input.inputs,
+ new_state,
+ incoming,
+ history,
+ source,
+ prefix=rep_name + "|",
+ context=context )
+ if rep_errors:
+ any_group_errors = True
+ group_errors[rep_index].update( rep_errors )
+
+ else:
+ group_errors[-1] = { '__index__': 'Cannot add repeat (max size=%i).' % input.max }
+ any_group_errors = True
+ rep_index += 1
+ elif isinstance( input, Conditional ):
+ group_state = state[input.name]
+ group_prefix = "%s|" % ( key )
+ # Deal with the 'test' element and see if it's value changed
+ if input.value_ref and not input.value_ref_in_group:
+ # We are referencing an existent parameter, which is not
+ # part of this group
+ test_param_key = prefix + input.test_param.name
+ else:
+ test_param_key = group_prefix + input.test_param.name
+ test_param_error = None
+ test_incoming = get_incoming_value( incoming, test_param_key, None )
+
+ # Get value of test param and determine current case
+ value, test_param_error = \
+ check_param( trans, input.test_param, test_incoming, context, source=source )
+ current_case = input.get_current_case( value, trans )
+ # Current case has changed, throw away old state
+ group_state = state[input.name] = {}
+ # TODO: we should try to preserve values if we can
+ self.fill_in_new_state( trans, input.cases[current_case].inputs, group_state, context, history=history )
+ group_errors = self.populate_state( trans,
+ input.cases[current_case].inputs,
+ group_state,
+ incoming,
+ history,
+ source,
+ prefix=group_prefix,
+ context=context,
+ )
+ if test_param_error:
+ group_errors[ input.test_param.name ] = test_param_error
+ if group_errors:
+ errors[ input.name ] = group_errors
+ # Store the current case in a special value
+ group_state['__current_case__'] = current_case
+ # Store the value of the test element
+ group_state[ input.test_param.name ] = value
+ elif isinstance( input, UploadDataset ):
+ group_state = state[input.name]
+ group_errors = []
+ any_group_errors = False
+ d_type = input.get_datatype( trans, context )
+ writable_files = d_type.writable_files
+ #remove extra files
+ while len( group_state ) > len( writable_files ):
+ del group_state[-1]
+ # Update state
+ max_index = -1
+ for i, rep_state in enumerate( group_state ):
+ rep_index = rep_state['__index__']
+ max_index = max( max_index, rep_index )
+ rep_prefix = "%s_%d|" % ( key, rep_index )
+ rep_errors = self.populate_state( trans,
+ input.inputs,
+ rep_state,
+ incoming,
+ history,
+ source,
+ prefix=rep_prefix,
+ context=context)
+ if rep_errors:
+ any_group_errors = True
+ group_errors.append( rep_errors )
+ else:
+ group_errors.append( {} )
+ # Add new fileupload as needed
+ offset = 1
+ while len( writable_files ) > len( group_state ):
+ new_state = {}
+ new_state['__index__'] = max_index + offset
+ offset += 1
+ self.fill_in_new_state( trans, input.inputs, new_state, context )
+ group_state.append( new_state )
+ if any_group_errors:
+ group_errors.append( {} )
+ # Were there *any* errors for any repetition?
+ if any_group_errors:
+ errors[input.name] = group_errors
+ else:
+ if key not in incoming \
+ and "__force_update__" + key not in incoming:
+ # No new value provided, and we are only updating, so keep
+ # the old value (which should already be in the state) and
+ # preserve the old error message.
+ pass
+ else:
+ incoming_value = get_incoming_value( incoming, key, None )
+ value, error = check_param( trans, input, incoming_value, context, source=source )
+ # If a callback was provided, allow it to process the value
+ if error:
+ errors[ input.name ] = error
+ state[ input.name ] = value
+ return errors
+
+ def update_state( self, trans, inputs, state, incoming, source='html', prefix="", context=None,
update_only=False, old_errors={}, item_callback=None ):
"""
Update the tool state in `state` using the user input in `incoming`.
@@ -2091,6 +2261,7 @@
input.inputs,
rep_state,
incoming,
+ source=source,
prefix=rep_prefix,
context=context,
update_only=update_only,
@@ -2139,7 +2310,7 @@
else:
# Get value of test param and determine current case
value, test_param_error = \
- check_param( trans, input.test_param, test_incoming, context )
+ check_param( trans, input.test_param, test_incoming, context, source=source )
current_case = input.get_current_case( value, trans )
if current_case != old_current_case:
# Current case has changed, throw away old state
@@ -2156,6 +2327,7 @@
incoming,
prefix=group_prefix,
context=context,
+ source=source,
update_only=update_only,
old_errors=group_old_errors,
item_callback=item_callback )
@@ -2197,6 +2369,7 @@
incoming,
prefix=rep_prefix,
context=context,
+ source=source,
update_only=update_only,
old_errors=rep_old_errors,
item_callback=item_callback )
@@ -2229,7 +2402,7 @@
errors[ input.name ] = old_errors[ input.name ]
else:
incoming_value = get_incoming_value( incoming, key, None )
- value, error = check_param( trans, input, incoming_value, context )
+ value, error = check_param( trans, input, incoming_value, context, source=source )
# If a callback was provided, allow it to process the value
if item_callback:
old_value = state.get( input.name, None )
diff -r ac744f96faa5d4a61c73ca2e20655f818af3dddd -r 3402a11b008865ee37ee29c9d7d3d5ea27c6fe84 lib/galaxy/tools/actions/upload.py
--- a/lib/galaxy/tools/actions/upload.py
+++ b/lib/galaxy/tools/actions/upload.py
@@ -4,8 +4,10 @@
import logging
log = logging.getLogger( __name__ )
+
class UploadToolAction( ToolAction ):
- def execute( self, tool, trans, incoming={}, set_output_hid = True, history=None, **kwargs ):
+
+ def execute( self, tool, trans, incoming={}, set_output_hid=True, history=None, **kwargs ):
dataset_upload_inputs = []
for input_name, input in tool.inputs.iteritems():
if input.type == "upload_dataset":
diff -r ac744f96faa5d4a61c73ca2e20655f818af3dddd -r 3402a11b008865ee37ee29c9d7d3d5ea27c6fe84 lib/galaxy/tools/actions/upload_common.py
--- a/lib/galaxy/tools/actions/upload_common.py
+++ b/lib/galaxy/tools/actions/upload_common.py
@@ -1,4 +1,8 @@
-import os, tempfile, StringIO, pwd, subprocess
+import os
+import tempfile
+import StringIO
+import pwd
+import subprocess
from cgi import FieldStorage
from galaxy import datatypes, util
from galaxy.util.odict import odict
@@ -10,13 +14,13 @@
import logging
log = logging.getLogger( __name__ )
+
def persist_uploads( params ):
"""
Turn any uploads in the submitted form to persisted files.
"""
if 'files' in params:
new_files = []
- temp_files = []
for upload_dataset in params['files']:
f = upload_dataset['file_data']
if isinstance( f, FieldStorage ):
@@ -24,8 +28,8 @@
assert f.file.name != '<fdopen>'
local_filename = util.mkstemp_ln( f.file.name, 'upload_file_data_' )
f.file.close()
- upload_dataset['file_data'] = dict( filename = f.filename,
- local_filename = local_filename )
+ upload_dataset['file_data'] = dict( filename=f.filename,
+ local_filename=local_filename )
elif type( f ) == dict and 'filename' and 'local_filename' not in f:
raise Exception( 'Uploaded file was encoded in a way not understood by Galaxy.' )
if upload_dataset['url_paste'] and upload_dataset['url_paste'].strip() != '':
@@ -35,6 +39,8 @@
new_files.append( upload_dataset )
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
@@ -62,6 +68,8 @@
role = trans.sa_session.query( trans.app.model.Role ).get( role_id )
library_bunch.roles.append( role )
return library_bunch
+
+
def get_precreated_datasets( trans, params, data_obj, controller='root' ):
"""
Get any precreated datasets (when using asynchronous uploads).
@@ -90,6 +98,8 @@
else:
rval.append( data )
return rval
+
+
def get_precreated_dataset( precreated_datasets, name ):
"""
Return a dataset matching a name from the list of precreated (via async
@@ -101,21 +111,24 @@
return precreated_datasets.pop( names.index( name ) )
else:
return None
+
+
def cleanup_unused_precreated_datasets( precreated_datasets ):
for data in precreated_datasets:
log.info( 'Cleaned up unclaimed precreated dataset (%s).' % ( data.id ) )
data.state = data.states.ERROR
data.info = 'No file contents were available.'
+
def __new_history_upload( trans, uploaded_dataset, history=None, state=None ):
if not history:
history = trans.history
- hda = trans.app.model.HistoryDatasetAssociation( name = uploaded_dataset.name,
- extension = uploaded_dataset.file_type,
- dbkey = uploaded_dataset.dbkey,
- history = history,
- create_dataset = True,
- sa_session = trans.sa_session )
+ hda = trans.app.model.HistoryDatasetAssociation( name=uploaded_dataset.name,
+ extension=uploaded_dataset.file_type,
+ dbkey=uploaded_dataset.dbkey,
+ history=history,
+ create_dataset=True,
+ sa_session=trans.sa_session )
if state:
hda.state = state
else:
@@ -128,6 +141,7 @@
trans.sa_session.flush()
return hda
+
def __new_library_upload( trans, cntrller, uploaded_dataset, library_bunch, state=None ):
current_user_roles = trans.get_current_user_roles()
if not ( ( trans.user_is_admin() and cntrller in [ 'library_admin', 'api' ] ) or trans.app.security_agent.can_add_library_item( current_user_roles, library_bunch.folder ) ):
@@ -156,13 +170,13 @@
trans.sa_session.add( ld )
trans.sa_session.flush()
trans.app.security_agent.copy_library_permissions( trans, folder, ld )
- ldda = trans.app.model.LibraryDatasetDatasetAssociation( name = uploaded_dataset.name,
- extension = uploaded_dataset.file_type,
- dbkey = uploaded_dataset.dbkey,
- library_dataset = ld,
- user = trans.user,
- create_dataset = True,
- sa_session = trans.sa_session )
+ ldda = trans.app.model.LibraryDatasetDatasetAssociation( name=uploaded_dataset.name,
+ extension=uploaded_dataset.file_type,
+ dbkey=uploaded_dataset.dbkey,
+ library_dataset=ld,
+ user=trans.user,
+ create_dataset=True,
+ sa_session=trans.sa_session )
trans.sa_session.add( ldda )
if state:
ldda.state = state
@@ -210,12 +224,14 @@
trans.sa_session.flush()
return ldda
+
def new_upload( trans, cntrller, uploaded_dataset, library_bunch=None, history=None, state=None ):
if library_bunch:
return __new_library_upload( trans, cntrller, uploaded_dataset, library_bunch, state )
else:
return __new_history_upload( trans, uploaded_dataset, history=history, state=state )
+
def get_uploaded_datasets( trans, cntrller, params, precreated_datasets, dataset_upload_inputs, library_bunch=None, history=None ):
uploaded_datasets = []
for dataset_upload_input in dataset_upload_inputs:
@@ -256,6 +272,8 @@
history.genome_build = uploaded_dataset.dbkey
uploaded_dataset.data = data
return uploaded_datasets
+
+
def create_paramfile( trans, uploaded_datasets ):
"""
Create the upload tool's JSON "param" file.
@@ -284,14 +302,14 @@
setattr( data.metadata, meta_name, meta_value )
trans.sa_session.add( data )
trans.sa_session.flush()
- json = dict( file_type = uploaded_dataset.file_type,
- dataset_id = data.dataset.id,
- dbkey = uploaded_dataset.dbkey,
- type = uploaded_dataset.type,
- metadata = uploaded_dataset.metadata,
- primary_file = uploaded_dataset.primary_file,
- composite_file_paths = uploaded_dataset.composite_files,
- composite_files = dict( [ ( k, v.__dict__ ) for k, v in data.datatype.get_composite_files( data ).items() ] ) )
+ json = dict( file_type=uploaded_dataset.file_type,
+ dataset_id=data.dataset.id,
+ dbkey=uploaded_dataset.dbkey,
+ type=uploaded_dataset.type,
+ metadata=uploaded_dataset.metadata,
+ primary_file=uploaded_dataset.primary_file,
+ composite_file_paths=uploaded_dataset.composite_files,
+ composite_files=dict( [ ( k, v.__dict__ ) for k, v in data.datatype.get_composite_files( data ).items() ] ) )
else:
try:
is_binary = uploaded_dataset.datatype.is_binary
@@ -305,18 +323,18 @@
uuid_str = uploaded_dataset.uuid
except:
uuid_str = None
- json = dict( file_type = uploaded_dataset.file_type,
- ext = uploaded_dataset.ext,
- name = uploaded_dataset.name,
- dataset_id = data.dataset.id,
- dbkey = uploaded_dataset.dbkey,
- type = uploaded_dataset.type,
- is_binary = is_binary,
- link_data_only = link_data_only,
- uuid = uuid_str,
- space_to_tab = uploaded_dataset.space_to_tab,
- in_place = trans.app.config.external_chown_script is None,
- path = uploaded_dataset.path )
+ json = dict( file_type=uploaded_dataset.file_type,
+ ext=uploaded_dataset.ext,
+ name=uploaded_dataset.name,
+ dataset_id=data.dataset.id,
+ dbkey=uploaded_dataset.dbkey,
+ type=uploaded_dataset.type,
+ is_binary=is_binary,
+ link_data_only=link_data_only,
+ uuid=uuid_str,
+ space_to_tab=uploaded_dataset.space_to_tab,
+ in_place=trans.app.config.external_chown_script is None,
+ path=uploaded_dataset.path )
# TODO: This will have to change when we start bundling inputs.
# Also, in_place above causes the file to be left behind since the
# user cannot remove it unless the parent directory is writable.
@@ -327,6 +345,8 @@
if trans.app.config.external_chown_script:
_chown( json_file_path )
return json_file_path
+
+
def create_job( trans, params, tool, json_file_path, data_list, folder=None, history=None ):
"""
Create the upload job.
@@ -383,6 +403,8 @@
for i, v in enumerate( data_list ):
output[ 'output%i' % i ] = v
return job, output
+
+
def active_folders( trans, folder ):
# Stolen from galaxy.web.controllers.library_common (importing from which causes a circular issues).
# Much faster way of retrieving all active sub-folders within a given folder than the
diff -r ac744f96faa5d4a61c73ca2e20655f818af3dddd -r 3402a11b008865ee37ee29c9d7d3d5ea27c6fe84 lib/galaxy/tools/parameters/__init__.py
--- a/lib/galaxy/tools/parameters/__init__.py
+++ b/lib/galaxy/tools/parameters/__init__.py
@@ -40,7 +40,7 @@
if new_value:
input_values[input.name] = new_value
-def check_param( trans, param, incoming_value, param_values ):
+def check_param( trans, param, incoming_value, param_values, source='html' ):
"""
Check the value of a single parameter `param`. The value in
`incoming_value` is converted from its HTML encoding and validated.
@@ -53,7 +53,10 @@
try:
if value is not None or isinstance(param, DataToolParameter):
# Convert value from HTML representation
- value = param.from_html( value, trans, param_values )
+ if source == 'html':
+ value = param.from_html( value, trans, param_values )
+ else:
+ value = param.from_json( value, trans, param_values )
# Allow the value to be converted if neccesary
filtered_value = param.filter_value( value, trans, param_values )
# Then do any further validation on the value
diff -r ac744f96faa5d4a61c73ca2e20655f818af3dddd -r 3402a11b008865ee37ee29c9d7d3d5ea27c6fe84 lib/galaxy/tools/parameters/basic.py
--- a/lib/galaxy/tools/parameters/basic.py
+++ b/lib/galaxy/tools/parameters/basic.py
@@ -2,14 +2,20 @@
Basic tool parameters.
"""
-import logging, string, sys, os, os.path, urllib
+import logging
+import string
+import sys
+import os
+import os.path
+import urllib
from elementtree.ElementTree import XML, Element
from galaxy import config, datatypes, util
from galaxy.web import form_builder
from galaxy.util.bunch import Bunch
from galaxy.util import string_as_bool, sanitize_param, unicodify
from sanitize import ToolParameterSanitizer
-import validation, dynamic_options
+import validation
+import dynamic_options
# For BaseURLToolParameter
from galaxy.web import url_for
from galaxy.model.item_attrs import Dictifiable
@@ -53,8 +59,10 @@
def get_label( self ):
"""Return user friendly name for the parameter"""
- if self.label: return self.label
- else: return self.name
+ if self.label:
+ return self.label
+ else:
+ return self.name
def get_html_field( self, trans=None, value=None, other_values={} ):
raise TypeError( "Abstract Method" )
@@ -73,6 +81,9 @@
"""
return value
+ def from_json( self, value, trans=None, other_values={} ):
+ return self.from_html( value, trans, other_values )
+
def get_initial_value( self, trans, context, history=None ):
"""
Return the starting value of the parameter
@@ -87,7 +98,7 @@
if a value has already been chosen from the history. This is to support the capability to
choose each dataset once
"""
- return self.get_initial_value(trans, context, history=history);
+ return self.get_initial_value(trans, context, history=history)
def get_required_enctype( self ):
"""
@@ -166,7 +177,7 @@
return value
def validate( self, value, history=None ):
- if value=="" and self.optional:
+ if value == "" and self.optional:
return
for validator in self.validators:
validator.validate( value, history )
@@ -219,7 +230,8 @@
self.area = string_as_bool( elem.get( 'area', False ) )
def get_html_field( self, trans=None, value=None, other_values={} ):
- if value is None: value = self.value
+ if value is None:
+ value = self.value
if self.area:
return form_builder.TextArea( self.name, self.size, value )
else:
@@ -228,6 +240,7 @@
def get_initial_value( self, trans, context, history=None ):
return self.value
+
class IntegerToolParameter( TextToolParameter ):
"""
Parameter that takes an integer value.
@@ -412,11 +425,14 @@
checked = self.checked
if value is not None:
checked = form_builder.CheckboxField.is_checked( value )
- return form_builder.CheckboxField( self.name, checked, refresh_on_change = self.refresh_on_change )
+ return form_builder.CheckboxField( self.name, checked, refresh_on_change=self.refresh_on_change )
def from_html( self, value, trans=None, other_values={} ):
return form_builder.CheckboxField.is_checked( value )
+ def from_json( self, value, trans=None, other_values={} ):
+ return string_as_bool( value )
+
def to_html_value( self, value, app ):
if value:
return [ 'true', 'true' ]
@@ -461,7 +477,7 @@
self.ajax = string_as_bool( elem.get( 'ajax-upload' ) )
def get_html_field( self, trans=None, value=None, other_values={} ):
- return form_builder.FileField( self.name, ajax = self.ajax, value = value )
+ return form_builder.FileField( self.name, ajax=self.ajax, value=value )
def from_html( self, value, trans=None, other_values={} ):
# Middleware or proxies may encode files in special ways (TODO: this
@@ -476,8 +492,8 @@
assert local_filename.startswith( upload_store ), \
"Filename provided by nginx is not in correct directory"
value = dict(
- filename = value["name"],
- local_filename = local_filename
+ filename=value["name"],
+ local_filename=local_filename
)
return value
@@ -533,7 +549,7 @@
user_ftp_dir = None
else:
user_ftp_dir = trans.user_ftp_dir
- return form_builder.FTPFileField( self.name, user_ftp_dir, trans.app.config.ftp_upload_site, value = value )
+ return form_builder.FTPFileField( self.name, user_ftp_dir, trans.app.config.ftp_upload_site, value=value )
def from_html( self, value, trans=None, other_values={} ):
try:
@@ -754,8 +770,9 @@
else:
return form_builder.TextField( self.name, value=(value or "") )
if value is not None:
- if not isinstance( value, list ): value = [ value ]
- field = form_builder.SelectField( self.name, self.multiple, self.display, self.refresh_on_change, refresh_on_change_values = self.refresh_on_change_values )
+ if not isinstance( value, list ):
+ value = [ value ]
+ field = form_builder.SelectField( self.name, self.multiple, self.display, self.refresh_on_change, refresh_on_change_values=self.refresh_on_change_values )
options = self.get_options( trans, context )
for text, optval, selected in options:
if isinstance( optval, UnvalidatedValue ):
@@ -793,7 +810,7 @@
rval.append( v )
return rval
else:
- value_is_none = ( value == "None" and "None" not in legal_values )
+ value_is_none = ( value == "None" and "None" not in legal_values )
if value_is_none:
if self.multiple:
if self.optional:
@@ -943,7 +960,7 @@
options = []
try:
options = self.get_options( trans, {} )
- except AssertionError, assertion:
+ except AssertionError:
# we dont/cant set other_values (the {} above), so params that require other params to be filled will error:
# required dependency in filter_options
# associated DataToolParam in get_column_list
@@ -1006,16 +1023,13 @@
self.static_options = [ ( value, key, False ) for key, value in util.dbnames ]
def get_options( self, trans, other_values ):
- if not trans.history:
- yield 'unspecified', '?', False
- else:
+ last_used_build = object()
+ if trans.history:
last_used_build = trans.history.genome_build
- for dbkey, build_name in trans.db_builds:
- yield build_name, dbkey, ( dbkey == last_used_build )
+ for dbkey, build_name in trans.db_builds:
+ yield build_name, dbkey, ( dbkey == last_used_build )
def get_legal_values( self, trans, other_values ):
- if not trans.history:
- return set( '?' )
return set( dbkey for dbkey, _ in trans.db_builds )
def to_dict( self, trans, view='collection', value_mapper=None ):
@@ -1348,7 +1362,7 @@
options = []
for filter_key, filter_value in self.filtered.iteritems():
dataset = other_values[filter_key]
- if dataset.__class__.__name__.endswith( "DatasetFilenameWrapper" ): #this is a bad way to check for this, but problems importing class ( due to circular imports? )
+ if dataset.__class__.__name__.endswith( "DatasetFilenameWrapper" ): # this is a bad way to check for this, but problems importing class ( due to circular imports? )
dataset = dataset.dataset
if dataset:
for meta_key, meta_dict in filter_value.iteritems():
@@ -1531,8 +1545,9 @@
TODO: There should be an alternate display that allows single selects to be
displayed as radio buttons and multiple selects as a set of checkboxes
- TODO: The following must be fixed to test correctly for the new security_check tag in the DataToolParameter ( the last test below is broken )
- Nate's next pass at the dataset security stuff will dramatically alter this anyway.
+ TODO: The following must be fixed to test correctly for the new security_check tag in
+ the DataToolParameter ( the last test below is broken ) Nate's next pass at the dataset
+ security stuff will dramatically alter this anyway.
"""
def __init__( self, tool, elem, trans=None):
@@ -1579,8 +1594,8 @@
# Load conversions required for the dataset input
self.conversions = []
for conv_elem in elem.findall( "conversion" ):
- name = conv_elem.get( "name" ) #name for commandline substitution
- conv_extensions = conv_elem.get( "type" ) #target datatype extension
+ name = conv_elem.get( "name" ) # name for commandline substitution
+ conv_extensions = conv_elem.get( "type" ) # target datatype extension
# FIXME: conv_extensions should be able to be an ordered list
assert None not in [ name, type ], 'A name (%s) and type (%s) are required for explicit conversion' % ( name, type )
conv_types = tool.app.datatypes_registry.get_datatype_by_extension( conv_extensions.lower() )
@@ -1592,14 +1607,15 @@
try:
filter_value = self.options.get_options( trans, other_values )[0][0]
except IndexError:
- pass #no valid options
+ pass # no valid options
assert trans is not None, "DataToolParameter requires a trans"
history = trans.get_history()
assert history is not None, "DataToolParameter requires a history"
if value is not None:
if type( value ) != list:
value = [ value ]
- field = form_builder.SelectField( self.name, self.multiple, None, self.refresh_on_change, refresh_on_change_values = self.refresh_on_change_values )
+ field = form_builder.SelectField( self.name, self.multiple, None, self.refresh_on_change, refresh_on_change_values=self.refresh_on_change_values )
+
# CRUCIAL: the dataset_collector function needs to be local to DataToolParameter.get_html_field()
def dataset_collector( hdas, parent_hid ):
current_user_roles = trans.get_current_user_roles()
@@ -1654,7 +1670,7 @@
return field
def get_initial_value( self, trans, context, history=None ):
- return self.get_initial_value_from_history_prevent_repeats(trans, context, None, history=history);
+ return self.get_initial_value_from_history_prevent_repeats(trans, context, None, history=history)
def get_initial_value_from_history_prevent_repeats( self, trans, context, already_used, history=None ):
"""
@@ -1676,7 +1692,8 @@
try:
filter_value = self.options.get_options( trans, context )[0][0]
except IndexError:
- pass #no valid options
+ pass # no valid options
+
def dataset_collector( datasets ):
def is_convertable( dataset ):
target_ext, converted_dataset = dataset.find_conversion_destination( self.formats )
diff -r ac744f96faa5d4a61c73ca2e20655f818af3dddd -r 3402a11b008865ee37ee29c9d7d3d5ea27c6fe84 lib/galaxy/web/framework/__init__.py
--- a/lib/galaxy/web/framework/__init__.py
+++ b/lib/galaxy/web/framework/__init__.py
@@ -1070,10 +1070,11 @@
the user (chromInfo in history).
"""
dbnames = list()
- datasets = self.sa_session.query( self.app.model.HistoryDatasetAssociation ) \
- .filter_by( deleted=False, history_id=self.history.id, extension="len" )
- for dataset in datasets:
- dbnames.append( (dataset.dbkey, dataset.name) )
+ if self.history:
+ datasets = self.sa_session.query( self.app.model.HistoryDatasetAssociation ) \
+ .filter_by( deleted=False, history_id=self.history.id, extension="len" )
+ for dataset in datasets:
+ dbnames.append( (dataset.dbkey, dataset.name) )
user = self.get_user()
if user and 'dbkeys' in user.preferences:
user_keys = from_json_string( user.preferences['dbkeys'] )
diff -r ac744f96faa5d4a61c73ca2e20655f818af3dddd -r 3402a11b008865ee37ee29c9d7d3d5ea27c6fe84 lib/galaxy/webapps/galaxy/api/datasets.py
--- a/lib/galaxy/webapps/galaxy/api/datasets.py
+++ b/lib/galaxy/webapps/galaxy/api/datasets.py
@@ -7,7 +7,7 @@
from galaxy.web.base.controller import UsesHistoryMixin
from galaxy.web.framework.helpers import is_true
from galaxy.datatypes import dataproviders
-
+from galaxy.util import string_as_bool_or_none
import logging
log = logging.getLogger( __name__ )
@@ -245,11 +245,16 @@
@web.expose_api_raw_anonymous
def display( self, trans, history_content_id, history_id,
- preview=False, filename=None, to_ext=None, chunk=None, **kwd ):
+ preview=False, filename=None, to_ext=None, chunk=None, raw=False, **kwd ):
"""
GET /api/histories/{encoded_history_id}/contents/{encoded_content_id}/display
Displays history content (dataset).
+
+ The query parameter 'raw' should be considered experimental and may be dropped at
+ some point in the future without warning. Generally, data should be processed by its
+ datatype prior to display (the defult if raw is unspecified or explicitly false.
"""
+ raw = string_as_bool_or_none( raw )
# Huge amount of code overlap with lib/galaxy/webapps/galaxy/api/history_content:show here.
rval = ''
try:
@@ -269,7 +274,15 @@
hda = self.get_history_dataset_association( trans, history, history_content_id,
check_ownership=True, check_accessible=True )
- rval = hda.datatype.display_data( trans, hda, preview, filename, to_ext, chunk, **kwd )
+ display_kwd = kwd.copy()
+ try:
+ del display_kwd["key"]
+ except KeyError:
+ pass
+ if raw:
+ rval = open( hda.file_name )
+ else:
+ rval = hda.datatype.display_data( trans, hda, preview, filename, to_ext, chunk, **display_kwd )
except Exception, exception:
log.error( "Error getting display data for dataset (%s) from history (%s): %s",
diff -r ac744f96faa5d4a61c73ca2e20655f818af3dddd -r 3402a11b008865ee37ee29c9d7d3d5ea27c6fe84 lib/galaxy/webapps/galaxy/api/tools.py
--- a/lib/galaxy/webapps/galaxy/api/tools.py
+++ b/lib/galaxy/webapps/galaxy/api/tools.py
@@ -9,6 +9,7 @@
import logging
log = logging.getLogger( __name__ )
+
class ToolsController( BaseAPIController, UsesVisualizationMixin ):
"""
RESTful controller for interactions with tools.
@@ -113,7 +114,19 @@
# TODO: encode data ids and decode ids.
# TODO: handle dbkeys
params = util.Params( inputs, sanitize = False )
- template, vars = tool.handle_input( trans, params.__dict__, history=target_history )
+ # process_state will be 'populate' or 'update'. When no tool
+ # state is specified in input - it will be 'populate', and
+ # tool will fully expand repeat and conditionals when building
+ # up state. If tool state is found in input
+ # parameters,process_state will be 'update' and complex
+ # submissions (with repeats and conditionals) must be built up
+ # over several iterative calls to the API - mimicing behavior
+ # of web controller (though frankly API never returns
+ # tool_state so this "legacy" behavior is probably impossible
+ # through API currently).
+ incoming = params.__dict__
+ process_state = "update" if "tool_state" in incoming else "populate"
+ template, vars = tool.handle_input( trans, incoming, history=target_history, process_state=process_state, source="json" )
if 'errors' in vars:
trans.response.status = 400
return { "message": { "type": "error", "data" : vars[ 'errors' ] } }
diff -r ac744f96faa5d4a61c73ca2e20655f818af3dddd -r 3402a11b008865ee37ee29c9d7d3d5ea27c6fe84 templates/webapps/galaxy/tool_form.mako
--- a/templates/webapps/galaxy/tool_form.mako
+++ b/templates/webapps/galaxy/tool_form.mako
@@ -218,12 +218,11 @@
else:
cls = "form-row"
- label = param.get_label()
-
field = param.get_html_field( trans, parent_state[ param.name ], other_values )
field.refresh_on_change = param.refresh_on_change
- # Field may contain characters submitted by user and these characters may be unicode; handle non-ascii characters gracefully.
+ # Field may contain characters submitted by user and these characters may
+ # be unicode; handle non-ascii characters gracefully.
field_html = field.get_html( prefix )
if type( field_html ) is not unicode:
field_html = unicode( field_html, 'utf-8', 'replace' )
@@ -232,25 +231,39 @@
return field_html
%><div class="${cls}">
- %if label:
- <label for="${param.name}">${label}:</label>
- %endif
- <div class="form-row-input">${field_html}</div>
- %if parent_errors.has_key( param.name ):
- <div class="form-row-error-message">
- <div><img style="vertical-align: middle;" src="${h.url_for('/static/style/error_small.png')}"> <span style="vertical-align: middle;">${parent_errors[param.name]}</span></div>
- </div>
- %endif
+ ${label_for_param( param )}
+ ${input_for_param( param, field_html )}
+ ${errors_for_param( param, parent_errors )}
+ ${help_for_param( param )}
+ <div style="clear: both;"></div>
+ </div>
+</%def>
- %if param.help:
- <div class="toolParamHelp" style="clear: both;">
- ${param.help}
- </div>
- %endif
+<%def name="input_for_param( param, field_html )">
+ <div class="form-row-input">${field_html}</div>
+</%def>
- <div style="clear: both;"></div>
+<%def name="label_for_param( param )">
+ <% label = param.get_label()%>
+ %if label:
+ <label for="${param.name}">${label}:</label>
+ %endif
+</%def>
- </div>
+<%def name="errors_for_param( param, parent_errors )">
+ %if parent_errors.has_key( param.name ):
+ <div class="form-row-error-message">
+ <div><img style="vertical-align: middle;" src="${h.url_for('/static/style/error_small.png')}"> <span style="vertical-align: middle;">${parent_errors[param.name]}</span></div>
+ </div>
+ %endif
+</%def>
+
+<%def name="help_for_param( param )">
+ %if param.help:
+ <div class="toolParamHelp" style="clear: both;">
+ ${param.help}
+ </div>
+ %endif
</%def><%def name="row_for_rerun()">
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
10 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/08ca76c1804d/
Changeset: 08ca76c1804d
User: BjoernGruening
Date: 2013-11-14 17:39:49
Summary: add setup_perl_environment as Tool Shed functionality
Affected #: 2 files
diff -r 516df888b97a164b7ff2d8235f5d4ea6462e185d -r 08ca76c1804d9307feb3db95fdcecfe0d74af20b lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
@@ -441,6 +441,99 @@
return_code = file_append( env_entry, env_file, skip_if_contained=True, make_executable=True )
if return_code:
return
+ elif action_type == 'setup_perl_environment':
+ # setup an Perl environment
+ # <action type="setup_perl_environment">
+ # <repository name="package_perl_5_18" owner="bgruening">
+ # <package name="perl" version="5.18.1" />
+ # </repository>
+ # <!-- allow downloading and installing an Perl package from cpan.org-->
+ # <package>XML::Parser</package>
+ # <package>http://search.cpan.org/CPAN/authors/id/C/CJ/CJFIELDS/BioPerl-1.6.922.tar.gz</package>
+ # </action>
+ filtered_actions = actions[ 1: ]
+
+ if action_dict.get( 'env_shell_file_paths', False ):
+ install_environment.add_env_shell_file_paths( action_dict[ 'env_shell_file_paths' ] )
+ else:
+ log.warning( 'Missing Rerl environment. Please check if your specified Rerl installation exists.' )
+ return
+
+ dir = os.path.curdir
+ current_dir = os.path.abspath( os.path.join( work_dir, dir ) )
+ with lcd( current_dir ):
+ with settings( warn_only=True ):
+
+ for package in action_dict[ 'perl_packages' ]:
+ """
+ If set to a true value then MakeMaker's prompt function will always return the default without waiting for user input.
+ """
+ cmd = '''export PERL_MM_USE_DEFAULT=1 && '''
+
+ if package.find('://') != -1:
+ # we assume a URL to a gem file
+ url = package
+ package_name = url.split( '/' )[ -1 ]
+ dir = td_common_util.url_download( work_dir, package_name, url, extract=True )
+ # search for Build.PL or Makefile.PL (ExtUtils::MakeMaker vs. Module::Build)
+
+ tmp_work_dir = os.path.join( work_dir, dir)
+ if os.path.exists( os.path.join( tmp_work_dir, 'Makefile.PL' ) ):
+
+ cmd += '''perl Makefile.PL INSTALL_BASE=$INSTALL_DIR && make && make install'''
+ elif os.path.exists( os.path.join( tmp_work_dir, 'Build.PL' ) ):
+ cmd += '''perl Build.PL --install_base $INSTALL_DIR && perl Build && perl Build install'''
+ else:
+ log.warning( 'No Makefile.PL or Build.PL file found in %s. Skip installation of %s.' % ( url, package_name ) )
+ return
+ with lcd( tmp_work_dir ):
+ cmd = install_environment.build_command( td_common_util.evaluate_template( cmd, install_dir ) )
+ return_code = handle_command( app, tool_dependency, install_dir, cmd )
+ if return_code:
+ return
+ else:
+ # perl package from CPAN without version number
+ # cpanm should be installed with the parent perl distribution, otherwise this will not work
+ cmd += '''cpanm --local-lib=$INSTALL_DIR %s''' % ( package )
+
+ cmd = install_environment.build_command( td_common_util.evaluate_template( cmd, install_dir ) )
+ return_code = handle_command( app, tool_dependency, install_dir, cmd )
+ if return_code:
+ return
+
+ # Ruby libraries are installed to $INSTALL_DIR (install_dir), we now set the GEM_PATH path to that directory
+ # TODO: That code is used a lot for the different environments and should be refactored, once the environments are integrated
+ installed_env_dict = install_environment.environment_dict()
+ perl5lib_path = installed_env_dict.get('PERL5LIB', False)
+ perlbin_path = installed_env_dict.get('PATH', False)
+
+ if not perl5lib_path or not perlbin_path:
+ log.warning( 'Missing RRUBYLIB or/and RUBY_HOME environment variable. Please check if your specified Ruby installation is valid.' )
+
+ modify_env_command_dict = dict( name="PATH", action="set_to", value=perlbin_path )
+ env_entry, env_file = td_common_util.create_or_update_env_shell_file( install_dir, modify_env_command_dict )
+ return_code = file_append( env_entry, env_file, skip_if_contained=True, make_executable=True )
+ if return_code:
+ return
+
+ modify_env_command_dict = dict( name="PERL5LIB", action="set_to", value=perl5lib_path )
+ env_entry, env_file = td_common_util.create_or_update_env_shell_file( install_dir, modify_env_command_dict )
+ return_code = file_append( env_entry, env_file, skip_if_contained=True, make_executable=True )
+ if return_code:
+ return
+
+ modify_env_command_dict = dict( name="PERL5LIB", action="prepend_to", value=os.path.join(install_dir, 'lib', 'perl5') )
+ env_entry, env_file = td_common_util.create_or_update_env_shell_file( install_dir, modify_env_command_dict )
+ return_code = file_append( env_entry, env_file, skip_if_contained=True, make_executable=True )
+ if return_code:
+ return
+
+ modify_env_command_dict = dict( name="PATH", action="prepend_to", value=os.path.join(install_dir, 'bin') )
+ env_entry, env_file = td_common_util.create_or_update_env_shell_file( install_dir, modify_env_command_dict )
+ return_code = file_append( env_entry, env_file, skip_if_contained=True, make_executable=True )
+ if return_code:
+ return
+
else:
# We're handling a complex repository dependency where we only have a set_environment tag set.
diff -r 516df888b97a164b7ff2d8235f5d4ea6462e185d -r 08ca76c1804d9307feb3db95fdcecfe0d74af20b lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
@@ -719,6 +719,36 @@
action_dict[ 'ruby_packages' ] = ruby_packages
else:
continue
+ elif action_type == 'setup_perl_environment':
+ # setup an Perl environment
+ # <action type="setup_perl_environment">
+ # <repository name="package_perl_5_18" owner="bgruening">
+ # <package name="perl" version="5.18.1" />
+ # </repository>
+ # <!-- allow downloading and installing an Perl package from cpan.org-->
+ # <package>XML::Parser</package>
+ # <package>http://search.cpan.org/CPAN/authors/id/C/CJ/CJFIELDS/BioPerl-1.6.922.tar.gz</package>
+ # </action>
+
+ env_shell_file_paths = td_common_util.get_env_shell_file_paths( app, action_elem.find('repository') )
+ all_env_shell_file_paths.extend( env_shell_file_paths )
+ if all_env_shell_file_paths:
+ action_dict[ 'env_shell_file_paths' ] = all_env_shell_file_paths
+ perl_packages = list()
+ for env_elem in action_elem:
+ if env_elem.tag == 'package':
+ """
+ A valid package definition can be:
+ XML::Parser
+ http://search.cpan.org/CPAN/authors/id/C/CJ/CJFIELDS/BioPerl-1.6.922.tar.gz
+ Unfortunately, CPAN does not support versioning. If you want real Reproducibility,
+ you need to specify the tarball path and the right order of different tarballs manually.
+ """
+ perl_packages.append( env_elem.text.strip() )
+ if perl_packages:
+ action_dict[ 'perl_packages' ] = perl_packages
+ else:
+ continue
elif action_type == 'make_install':
# make; make install; allow providing make options
if action_elem.text:
https://bitbucket.org/galaxy/galaxy-central/commits/bfc098707375/
Changeset: bfc098707375
User: BjoernGruening
Date: 2013-11-14 17:39:49
Summary: fix c&p leftovers in comments
Affected #: 1 file
diff -r 08ca76c1804d9307feb3db95fdcecfe0d74af20b -r bfc098707375ff25cad706a9929ac29aef84e38c lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
@@ -501,14 +501,14 @@
if return_code:
return
- # Ruby libraries are installed to $INSTALL_DIR (install_dir), we now set the GEM_PATH path to that directory
+ # Perl libraries are installed to $INSTALL_DIR (install_dir), we now set the PERL5LIB path to that directory
# TODO: That code is used a lot for the different environments and should be refactored, once the environments are integrated
installed_env_dict = install_environment.environment_dict()
perl5lib_path = installed_env_dict.get('PERL5LIB', False)
perlbin_path = installed_env_dict.get('PATH', False)
if not perl5lib_path or not perlbin_path:
- log.warning( 'Missing RRUBYLIB or/and RUBY_HOME environment variable. Please check if your specified Ruby installation is valid.' )
+ log.warning( 'Missing PERL5LIB or/and PATH environment variable. Please check if your specified Perl installation is valid.' )
modify_env_command_dict = dict( name="PATH", action="set_to", value=perlbin_path )
env_entry, env_file = td_common_util.create_or_update_env_shell_file( install_dir, modify_env_command_dict )
https://bitbucket.org/galaxy/galaxy-central/commits/78ebe94f1492/
Changeset: 78ebe94f1492
User: jmchilton
Date: 2013-11-14 17:39:49
Summary: Introduce utility method parse_setup_environment_repositories.
Use to reduce code duplication in install_util and provides target for unit tests of new functionality. Add unit tests. Add new functionality for parsing out which packages should be recursive runtime dependencies (not implemented on fabric side yet).
Affected #: 4 files
diff -r bfc098707375ff25cad706a9929ac29aef84e38c -r 78ebe94f1492e145b298539042a9d9f68e5f0ae1 lib/galaxy/util/__init__.py
--- a/lib/galaxy/util/__init__.py
+++ b/lib/galaxy/util/__init__.py
@@ -137,6 +137,11 @@
ElementInclude.include(root)
return tree
+
+def parse_xml_string(xml_string):
+ tree = ElementTree.fromstring(xml_string)
+ return tree
+
def xml_to_string( elem, pretty=False ):
"""Returns a string from an xml tree"""
if pretty:
diff -r bfc098707375ff25cad706a9929ac29aef84e38c -r 78ebe94f1492e145b298539042a9d9f68e5f0ae1 lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
@@ -665,11 +665,7 @@
# <!-- allow installing an R packages -->
# <package>https://github.com/bgruening/download_store/raw/master/DESeq2-1_0_18/BiocGe…</package>
# </action>
- env_shell_file_paths = td_common_util.get_env_shell_file_paths( app, action_elem.find('repository') )
-
- all_env_shell_file_paths.extend( env_shell_file_paths )
- if all_env_shell_file_paths:
- action_dict[ 'env_shell_file_paths' ] = all_env_shell_file_paths
+ td_common_util.parse_setup_environment_repositories( app, all_env_shell_file_paths, action_elem, action_dict )
r_packages = list()
for env_elem in action_elem:
if env_elem.tag == 'package':
@@ -690,11 +686,7 @@
# <package>protk=1.2.4</package>
# <package>http://url-to-some-gem-file.de/protk.gem</package>
# </action>
-
- env_shell_file_paths = td_common_util.get_env_shell_file_paths( app, action_elem.find('repository') )
- all_env_shell_file_paths.extend( env_shell_file_paths )
- if all_env_shell_file_paths:
- action_dict[ 'env_shell_file_paths' ] = all_env_shell_file_paths
+ td_common_util.parse_setup_environment_repositories( app, all_env_shell_file_paths, action_elem, action_dict )
ruby_packages = list()
for env_elem in action_elem:
if env_elem.tag == 'package':
diff -r bfc098707375ff25cad706a9929ac29aef84e38c -r 78ebe94f1492e145b298539042a9d9f68e5f0ae1 lib/tool_shed/galaxy_install/tool_dependencies/td_common_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/td_common_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/td_common_util.py
@@ -193,6 +193,7 @@
return os.path.abspath( os.path.join( root, name ) )
return None
+
def get_env_shell_file_paths( app, elem ):
# Currently only the following tag set is supported.
# <repository toolshed="http://localhost:9009/" name="package_numpy_1_7" owner="test" changeset_revision="c84c6a8be056">
@@ -383,7 +384,7 @@
# platform. Append the child element to the list of elements to process.
actions_elem_list.append( child_element )
elif child_element.tag == 'action':
- # Any <action> tags within an <actions_group> tag set must come after all <actions> tags.
+ # Any <action> tags within an <actions_group> tag set must come after all <actions> tags.
if actions_elems_processed == actions_elem_count:
# If all <actions> elements have been processed, then this <action> element can be appended to the list of actions to
# execute within this group.
@@ -409,6 +410,16 @@
continue
return actions_elem_tuples
+
+def parse_setup_environment_repositories( app, all_env_shell_file_paths, action_elem, action_dict ):
+ env_shell_file_paths = get_env_shell_file_paths( app, action_elem.find('repository') )
+
+ all_env_shell_file_paths.extend( env_shell_file_paths )
+ if all_env_shell_file_paths:
+ action_dict[ 'env_shell_file_paths' ] = all_env_shell_file_paths
+ action_dict[ 'action_shell_file_paths' ] = env_shell_file_paths
+
+
def url_download( install_dir, downloaded_file_name, download_url, extract=True ):
file_path = os.path.join( install_dir, downloaded_file_name )
src = None
diff -r bfc098707375ff25cad706a9929ac29aef84e38c -r 78ebe94f1492e145b298539042a9d9f68e5f0ae1 test/unit/tool_shed/test_td_common_util.py
--- /dev/null
+++ b/test/unit/tool_shed/test_td_common_util.py
@@ -0,0 +1,57 @@
+from contextlib import contextmanager
+from galaxy.util import parse_xml_string
+
+from tool_shed.galaxy_install.tool_dependencies import td_common_util
+
+
+class MockApp( object ):
+
+ def __init__( self ):
+ pass
+
+
+def test_parse_setup_environment_repositories( ):
+ xml = """<action name="setup_r_environment">
+ <repository name="package_r_3_0_1" owner="bgruening" toolshed="toolshed.g2.bx.psu.edu" changeset_revision="1234567">
+ <package name="R" version="3.0.1" />
+ </repository>
+ </action>
+ """
+ mock_app = MockApp()
+ action_elem = parse_xml_string( xml )
+ required_for_install_env_sh = '/path/to/existing.sh'
+ all_env_paths = [ required_for_install_env_sh ]
+ action_dict = {}
+
+ r_env_sh = '/path/to/go/env.sh'
+
+ def mock_get_env_shell_file_paths( app, elem):
+ assert app == mock_app
+ assert elem.get( 'name' ) == "package_r_3_0_1"
+ return [ r_env_sh ]
+
+ with __mock_common_util_method("get_env_shell_file_paths", mock_get_env_shell_file_paths):
+ td_common_util.parse_setup_environment_repositories( mock_app, all_env_paths, action_elem, action_dict )
+ ## Verify old env files weren't deleted.
+ assert required_for_install_env_sh in all_env_paths
+ ## Verify new ones added.
+ assert r_env_sh in all_env_paths
+ ## env_shell_file_paths includes everything
+ assert all( [env in action_dict[ 'env_shell_file_paths' ] for env in all_env_paths] )
+
+ ## action_shell_file_paths includes only env files defined in
+ ## inside the setup_ action element.
+ assert required_for_install_env_sh not in action_dict[ 'action_shell_file_paths' ]
+ assert r_env_sh in action_dict[ 'action_shell_file_paths' ]
+
+
+## Poor man's mocking. Need to get a real mocking library as real Galaxy development
+## dependnecy.
+@contextmanager
+def __mock_common_util_method(name, mock_method):
+ real_method = getattr(td_common_util, name)
+ try:
+ setattr(td_common_util, name, mock_method)
+ yield
+ finally:
+ setattr(td_common_util, name, real_method)
https://bitbucket.org/galaxy/galaxy-central/commits/443628e7b555/
Changeset: 443628e7b555
User: jmchilton
Date: 2013-11-14 17:39:49
Summary: Update perl to use parse_setup_environment_repositories.
Affected #: 1 file
diff -r 78ebe94f1492e145b298539042a9d9f68e5f0ae1 -r 443628e7b555600d33937bebe0ae03f637650025 lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
@@ -721,11 +721,7 @@
# <package>XML::Parser</package>
# <package>http://search.cpan.org/CPAN/authors/id/C/CJ/CJFIELDS/BioPerl-1.6.922.tar.gz</package>
# </action>
-
- env_shell_file_paths = td_common_util.get_env_shell_file_paths( app, action_elem.find('repository') )
- all_env_shell_file_paths.extend( env_shell_file_paths )
- if all_env_shell_file_paths:
- action_dict[ 'env_shell_file_paths' ] = all_env_shell_file_paths
+ td_common_util.parse_setup_environment_repositories( app, all_env_shell_file_paths, action_elem, action_dict )
perl_packages = list()
for env_elem in action_elem:
if env_elem.tag == 'package':
https://bitbucket.org/galaxy/galaxy-central/commits/bc18a1706c12/
Changeset: bc18a1706c12
User: jmchilton
Date: 2013-11-14 17:39:49
Summary: Add unit test for all existing functionality in td_common_util.create_or_update_env_shell_file
Affected #: 1 file
diff -r 443628e7b555600d33937bebe0ae03f637650025 -r bc18a1706c12849df23985c0fc5f04feff5bd956 test/unit/tool_shed/test_td_common_util.py
--- a/test/unit/tool_shed/test_td_common_util.py
+++ b/test/unit/tool_shed/test_td_common_util.py
@@ -1,15 +1,35 @@
+from os.path import join
from contextlib import contextmanager
from galaxy.util import parse_xml_string
from tool_shed.galaxy_install.tool_dependencies import td_common_util
+TEST_DEPENDENCIES_DIR = "/opt/galaxy/dependencies"
+TEST_INSTALL_DIR = "%s/test_install_dir" % TEST_DEPENDENCIES_DIR
+
+
class MockApp( object ):
def __init__( self ):
pass
+def test_create_or_update_env_shell_file( ):
+ test_path = "/usr/share/R/libs"
+ line, path = td_common_util.create_or_update_env_shell_file( TEST_INSTALL_DIR, dict(action="append_to", name="R_LIBS", value=test_path))
+ assert path == join( TEST_INSTALL_DIR, "env.sh" )
+ assert line == "R_LIBS=$R_LIBS:/usr/share/R/libs; export R_LIBS"
+
+ line, path = td_common_util.create_or_update_env_shell_file( TEST_INSTALL_DIR, dict(action="prepend_to", name="R_LIBS", value=test_path))
+ assert path == join( TEST_INSTALL_DIR, "env.sh" )
+ assert line == "R_LIBS=/usr/share/R/libs:$R_LIBS; export R_LIBS"
+
+ line, path = td_common_util.create_or_update_env_shell_file( TEST_INSTALL_DIR, dict(action="set_to", name="R_LIBS", value=test_path))
+ assert path == join( TEST_INSTALL_DIR, "env.sh" )
+ assert line == "R_LIBS=/usr/share/R/libs; export R_LIBS"
+
+
def test_parse_setup_environment_repositories( ):
xml = """<action name="setup_r_environment"><repository name="package_r_3_0_1" owner="bgruening" toolshed="toolshed.g2.bx.psu.edu" changeset_revision="1234567">
https://bitbucket.org/galaxy/galaxy-central/commits/8e7cface9bf1/
Changeset: 8e7cface9bf1
User: jmchilton
Date: 2013-11-14 17:39:49
Summary: Add new action to create_or_update_env_shell_file for sourcing other env.sh files.
With unit test.
Affected #: 2 files
diff -r bc18a1706c12849df23985c0fc5f04feff5bd956 -r 8e7cface9bf1060c41ebbda99e025572abbafe5b lib/tool_shed/galaxy_install/tool_dependencies/td_common_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/td_common_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/td_common_util.py
@@ -146,16 +146,21 @@
return None
def create_or_update_env_shell_file( install_dir, env_var_dict ):
- env_var_name = env_var_dict[ 'name' ]
env_var_action = env_var_dict[ 'action' ]
env_var_value = env_var_dict[ 'value' ]
- if env_var_action == 'prepend_to':
- changed_value = '%s:$%s' % ( env_var_value, env_var_name )
- elif env_var_action == 'set_to':
- changed_value = '%s' % env_var_value
- elif env_var_action == 'append_to':
- changed_value = '$%s:%s' % ( env_var_name, env_var_value )
- line = "%s=%s; export %s" % ( env_var_name, changed_value, env_var_name )
+ if env_var_action in ['prepend_to', 'set_to', 'append_to']:
+ env_var_name = env_var_dict[ 'name' ]
+ if env_var_action == 'prepend_to':
+ changed_value = '%s:$%s' % ( env_var_value, env_var_name )
+ elif env_var_action == 'set_to':
+ changed_value = '%s' % env_var_value
+ elif env_var_action == 'append_to':
+ changed_value = '$%s:%s' % ( env_var_name, env_var_value )
+ line = "%s=%s; export %s" % ( env_var_name, changed_value, env_var_name )
+ elif env_var_action == "source":
+ line = ". %s" % env_var_value
+ else:
+ raise Exception( "Unknown shell file action %s" % env_var_action )
env_shell_file_path = os.path.join( install_dir, 'env.sh' )
return line, env_shell_file_path
diff -r bc18a1706c12849df23985c0fc5f04feff5bd956 -r 8e7cface9bf1060c41ebbda99e025572abbafe5b test/unit/tool_shed/test_td_common_util.py
--- a/test/unit/tool_shed/test_td_common_util.py
+++ b/test/unit/tool_shed/test_td_common_util.py
@@ -29,6 +29,10 @@
assert path == join( TEST_INSTALL_DIR, "env.sh" )
assert line == "R_LIBS=/usr/share/R/libs; export R_LIBS"
+ line, path = td_common_util.create_or_update_env_shell_file( TEST_INSTALL_DIR, dict(action="source", value=test_path))
+ assert path == join( TEST_INSTALL_DIR, "env.sh" )
+ assert line == ". /usr/share/R/libs"
+
def test_parse_setup_environment_repositories( ):
xml = """<action name="setup_r_environment">
https://bitbucket.org/galaxy/galaxy-central/commits/cf33c63f9a9b/
Changeset: cf33c63f9a9b
User: jmchilton
Date: 2013-11-14 17:39:49
Summary: Introduce higher level abstraction for building up env.sh files in fabric_util.py.
Use it to reduced duplicated code in fabric_util.py. Implement unit tests describing this new class.
Affected #: 2 files
diff -r 8e7cface9bf1060c41ebbda99e025572abbafe5b -r cf33c63f9a9b14b395d02d459ae6e30236236a67 lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
@@ -200,6 +200,20 @@
return True
+class EnvFileBuilder( object ):
+
+ def __init__( self, install_dir ):
+ self.install_dir = install_dir
+ self.return_code = 0
+
+ def append_line( self, skip_if_contained=True, make_executable=True, **kwds ):
+ env_var_dict = dict(**kwds)
+ env_entry, env_file = td_common_util.create_or_update_env_shell_file( self.install_dir, env_var_dict )
+ return_code = file_append( env_entry, env_file, skip_if_contained=skip_if_contained, make_executable=make_executable )
+ self.return_code = self.return_code or return_code
+ return self.return_code
+
+
class InstallEnvironment( object ):
"""
Object describing the environment built up as part of the process of building
@@ -373,11 +387,9 @@
return
# R libraries are installed to $INSTALL_DIR (install_dir), we now set the R_LIBS path to that directory
- # TODO: That code is used a lot for the different environments and should be refactored, once the environments are integrated
- modify_env_command_dict = dict( name="R_LIBS", action="prepend_to", value=install_dir )
- env_entry, env_file = td_common_util.create_or_update_env_shell_file( install_dir, modify_env_command_dict )
- return_code = file_append( env_entry, env_file, skip_if_contained=True, make_executable=True )
-
+ env_file_builder = EnvFileBuilder( install_dir )
+ env_file_builder.append_line( name="R_LIBS", action="prepend_to", value=install_dir )
+ return_code = env_file_builder.return_code
if return_code:
return
elif action_type == 'setup_ruby_environment':
@@ -428,17 +440,10 @@
if return_code:
return
- # Ruby libraries are installed to $INSTALL_DIR (install_dir), we now set the GEM_PATH path to that directory
- # TODO: That code is used a lot for the different environments and should be refactored, once the environments are integrated
- modify_env_command_dict = dict( name="GEM_PATH", action="prepend_to", value=install_dir )
- env_entry, env_file = td_common_util.create_or_update_env_shell_file( install_dir, modify_env_command_dict )
- return_code = file_append( env_entry, env_file, skip_if_contained=True, make_executable=True )
- if return_code:
- return
-
- modify_env_command_dict = dict( name="PATH", action="prepend_to", value=os.path.join(install_dir, 'bin') )
- env_entry, env_file = td_common_util.create_or_update_env_shell_file( install_dir, modify_env_command_dict )
- return_code = file_append( env_entry, env_file, skip_if_contained=True, make_executable=True )
+ env_file_builder = EnvFileBuilder( install_dir )
+ env_file_builder.append_line( name="GEM_PATH", action="prepend_to", value=install_dir )
+ env_file_builder.append_line( name="PATH", action="prepend_to", value=os.path.join(install_dir, 'bin') )
+ return_code = env_file_builder.return_code
if return_code:
return
elif action_type == 'setup_perl_environment':
@@ -573,13 +578,14 @@
# in the set_environment action.
cmds = install_environment.environment_commands( 'set_environment' )
env_var_dicts = action_dict[ 'environment_variable' ]
+ env_file_builder = EnvFileBuilder( install_dir )
for env_var_dict in env_var_dicts:
# Check for the presence of the $ENV[] key string and populate it if possible.
env_var_dict = handle_environment_variables( app, tool_dependency, install_dir, env_var_dict, cmds )
- env_entry, env_file = td_common_util.create_or_update_env_shell_file( install_dir, env_var_dict )
- return_code = file_append( env_entry, env_file, skip_if_contained=True, make_executable=True )
- if return_code:
- return
+ env_file_builder.append_line( **env_var_dict )
+ return_code = env_file_builder.return_code
+ if return_code:
+ return
elif action_type == 'set_environment_for_install':
# Currently the only action supported in this category is a list of paths to one or more tool dependency env.sh files,
# the environment setting in each of which will be injected into the environment for all <action type="shell_command">
@@ -618,14 +624,10 @@
if not os.path.exists( output.stdout ):
log.error( "virtualenv's site-packages directory '%s' does not exist", output.stdout )
return
- modify_env_command_dict = dict( name="PYTHONPATH", action="prepend_to", value=output.stdout )
- env_entry, env_file = td_common_util.create_or_update_env_shell_file( install_dir, modify_env_command_dict )
- return_code = file_append( env_entry, env_file, skip_if_contained=True, make_executable=True )
- if return_code:
- return
- modify_env_command_dict = dict( name="PATH", action="prepend_to", value=os.path.join( venv_directory, "bin" ) )
- env_entry, env_file = td_common_util.create_or_update_env_shell_file( install_dir, modify_env_command_dict )
- return_code = file_append( env_entry, env_file, skip_if_contained=True, make_executable=True )
+ env_file_builder = EnvFileBuilder( install_dir )
+ env_file_builder.append_line( name="PYTHONPATH", action="prepend_to", value=output.stdout )
+ env_file_builder.append_line( name="PATH", action="prepend_to", value=os.path.join( venv_directory, "bin" ) )
+ return_code = env_file_builder.return_code
if return_code:
return
elif action_type == 'shell_command':
diff -r 8e7cface9bf1060c41ebbda99e025572abbafe5b -r cf33c63f9a9b14b395d02d459ae6e30236236a67 test/unit/tool_shed/test_fabric_util.py
--- /dev/null
+++ b/test/unit/tool_shed/test_fabric_util.py
@@ -0,0 +1,45 @@
+from contextlib import contextmanager
+from tool_shed.galaxy_install.tool_dependencies import fabric_util
+
+
+def test_env_file_builder():
+ install_dir = "/opt/galaxy/dependencies/foo/"
+ env_file_builder = fabric_util.EnvFileBuilder( install_dir )
+ added_lines = []
+ mock_return = dict(value=0)
+
+ def mock_file_append( text, file_path, **kwds ):
+ added_lines.append(text)
+ return mock_return["value"]
+
+ with __mock_fabric_util_method("file_append", mock_file_append):
+ env_file_builder.append_line( name="PATH", action="prepend_to", value="/usr/bin/local/R" )
+ assert added_lines == [ "PATH=/usr/bin/local/R:$PATH; export PATH" ]
+ assert env_file_builder.return_code == 0
+
+ # Reset mock lines
+ del added_lines[:]
+ # Next time file_append will fail
+ mock_return["value"] = 1
+
+ env_file_builder.append_line( action="source", value="/usr/bin/local/R/env.sh" )
+ assert added_lines == [ ". /usr/bin/local/R/env.sh" ]
+ # Check failure
+ assert env_file_builder.return_code == 1
+
+ mock_return["value"] = 0
+ env_file_builder.append_line( name="LD_LIBRARY_PATH", action="append_to", value="/usr/bin/local/R/lib" )
+ # Verify even though last append succeeded, previous failure still recorded.
+ assert env_file_builder.return_code == 1
+
+
+## Poor man's mocking. Need to get a real mocking library as real Galaxy development
+## dependnecy.
+@contextmanager
+def __mock_fabric_util_method(name, mock_method):
+ real_method = getattr(fabric_util, name)
+ try:
+ setattr(fabric_util, name, mock_method)
+ yield
+ finally:
+ setattr(fabric_util, name, real_method)
https://bitbucket.org/galaxy/galaxy-central/commits/27edf6bd91d1/
Changeset: 27edf6bd91d1
User: jmchilton
Date: 2013-11-14 17:39:49
Summary: Pull in dependant R, Ruby, and Perl complete environments at recursively runtime.
Affected #: 1 file
diff -r cf33c63f9a9b14b395d02d459ae6e30236236a67 -r 27edf6bd91d1b9b2153680adec361674c1f9b113 lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
@@ -388,6 +388,7 @@
# R libraries are installed to $INSTALL_DIR (install_dir), we now set the R_LIBS path to that directory
env_file_builder = EnvFileBuilder( install_dir )
+ handle_action_shell_file_paths( env_file_builder, action_dict ) # Pull in R environment (runtime).
env_file_builder.append_line( name="R_LIBS", action="prepend_to", value=install_dir )
return_code = env_file_builder.return_code
if return_code:
@@ -441,6 +442,7 @@
return
env_file_builder = EnvFileBuilder( install_dir )
+ handle_action_shell_file_paths( env_file_builder, action_dict ) # Pull in ruby dependencies (runtime).
env_file_builder.append_line( name="GEM_PATH", action="prepend_to", value=install_dir )
env_file_builder.append_line( name="PATH", action="prepend_to", value=os.path.join(install_dir, 'bin') )
return_code = env_file_builder.return_code
@@ -506,40 +508,16 @@
if return_code:
return
- # Perl libraries are installed to $INSTALL_DIR (install_dir), we now set the PERL5LIB path to that directory
- # TODO: That code is used a lot for the different environments and should be refactored, once the environments are integrated
- installed_env_dict = install_environment.environment_dict()
- perl5lib_path = installed_env_dict.get('PERL5LIB', False)
- perlbin_path = installed_env_dict.get('PATH', False)
+ env_file_builder = EnvFileBuilder( install_dir )
+ # Recursively add dependent PERL5LIB and PATH to env.sh & anything else needed.
+ handle_action_shell_file_paths( env_file_builder, action_dict ) # Pull in ruby dependencies (runtime).
- if not perl5lib_path or not perlbin_path:
- log.warning( 'Missing PERL5LIB or/and PATH environment variable. Please check if your specified Perl installation is valid.' )
-
- modify_env_command_dict = dict( name="PATH", action="set_to", value=perlbin_path )
- env_entry, env_file = td_common_util.create_or_update_env_shell_file( install_dir, modify_env_command_dict )
- return_code = file_append( env_entry, env_file, skip_if_contained=True, make_executable=True )
+ env_file_builder.append_line( name="PERL5LIB", action="prepend_to", value=os.path.join(install_dir, 'lib', 'perl5') )
+ env_file_builder.append_line( name="PATH", action="prepend_to", value=os.path.join(install_dir, 'bin') )
+ return_code = env_file_builder.return_code
if return_code:
return
- modify_env_command_dict = dict( name="PERL5LIB", action="set_to", value=perl5lib_path )
- env_entry, env_file = td_common_util.create_or_update_env_shell_file( install_dir, modify_env_command_dict )
- return_code = file_append( env_entry, env_file, skip_if_contained=True, make_executable=True )
- if return_code:
- return
-
- modify_env_command_dict = dict( name="PERL5LIB", action="prepend_to", value=os.path.join(install_dir, 'lib', 'perl5') )
- env_entry, env_file = td_common_util.create_or_update_env_shell_file( install_dir, modify_env_command_dict )
- return_code = file_append( env_entry, env_file, skip_if_contained=True, make_executable=True )
- if return_code:
- return
-
- modify_env_command_dict = dict( name="PATH", action="prepend_to", value=os.path.join(install_dir, 'bin') )
- env_entry, env_file = td_common_util.create_or_update_env_shell_file( install_dir, modify_env_command_dict )
- return_code = file_append( env_entry, env_file, skip_if_contained=True, make_executable=True )
- if return_code:
- return
-
-
else:
# We're handling a complex repository dependency where we only have a set_environment tag set.
# <action type="set_environment">
@@ -714,6 +692,13 @@
source=downloaded_filename,
destination=full_path_to_dir )
+
+def handle_action_shell_file_paths( env_file_builder, action_dict ):
+ shell_file_paths = action_dict.get( 'action_shell_file_paths', [])
+ for shell_file_path in shell_file_paths:
+ env_file_builder.append_line( action="source", value=shell_file_path )
+
+
def log_results( command, fabric_AttributeString, file_path ):
"""
Write attributes of fabric.operations._AttributeString (which is the output of executing command using fabric's local() method)
https://bitbucket.org/galaxy/galaxy-central/commits/a545da034f0a/
Changeset: a545da034f0a
User: jmchilton
Date: 2013-11-14 17:39:49
Summary: Bring in action fix from @BjoernGruening, not included in previous commit.
Affected #: 1 file
diff -r 27edf6bd91d1b9b2153680adec361674c1f9b113 -r a545da034f0a4ffe525df3cd5e0346838bffb723 lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
@@ -404,6 +404,8 @@
# <package>protk=1.2.4</package>
# <package>http://url-to-some-gem-file.de/protk.gem</package>
# </action>
+ filtered_actions = actions[ 1: ]
+
if action_dict.get( 'env_shell_file_paths', False ):
install_environment.add_env_shell_file_paths( action_dict[ 'env_shell_file_paths' ] )
else:
https://bitbucket.org/galaxy/galaxy-central/commits/ac744f96faa5/
Changeset: ac744f96faa5
User: jmchilton
Date: 2013-11-14 17:39:49
Summary: Outline some enhancements to InstallEnvironment, not used yet.
Affected #: 1 file
diff -r a545da034f0a4ffe525df3cd5e0346838bffb723 -r ac744f96faa5d4a61c73ca2e20655f818af3dddd lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
@@ -21,6 +21,7 @@
from fabric.api import lcd
from fabric.api import local
from fabric.api import settings
+from fabric.api import prefix
log = logging.getLogger( __name__ )
@@ -245,6 +246,17 @@
log.debug( 'Invalid file %s specified, ignoring %s action.', env_shell_file_path, action_type )
return cmds
+ def __call__( self, install_dir ):
+ with settings( warn_only=True, **td_common_util.get_env_var_values( install_dir ) ):
+ with prefix( self.__setup_environment() ):
+ yield
+
+ def __setup_environment(self):
+ return "&&".join( [". %s" % file for file in self.__valid_env_shell_file_paths() ] )
+
+ def __valid_env_shell_file_paths(self):
+ return [ file for file in self.env_shell_file_paths if os.path.exists( file ) ]
+
def environment_dict(self, action_type='template_command'):
env_vars = dict()
for env_shell_file_path in self.env_shell_file_paths:
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0