mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Grid framework refactoring to increase speed and ease of debugging: (1) create and use Backbone object for grid; (2) move grid javascript to its own file; (3) remove webapp parameter; (4) augment search box style so that search button does not wrap. Pack scripts.
This commit is contained in:
@@ -16,7 +16,6 @@ class Grid( object ):
|
||||
"""
|
||||
Specifies the content and format of a grid (data table).
|
||||
"""
|
||||
webapp = None
|
||||
title = ""
|
||||
exposed = True
|
||||
model_class = None
|
||||
@@ -56,7 +55,6 @@ class Grid( object ):
|
||||
def __call__( self, trans, **kwargs ):
|
||||
# Get basics.
|
||||
# FIXME: pretty sure this is only here to pass along, can likely be eliminated
|
||||
webapp = trans.webapp.name
|
||||
status = kwargs.get( 'status', None )
|
||||
message = kwargs.get( 'message', None )
|
||||
# Build a base filter and sort key that is the combination of the saved state and defaults.
|
||||
@@ -229,7 +227,6 @@ class Grid( object ):
|
||||
params = cur_filter_dict.copy()
|
||||
params['sort'] = sort_key
|
||||
params['async'] = ( 'async' in kwargs )
|
||||
params['webapp'] = webapp
|
||||
trans.log_action( trans.get_user(), unicode( "grid.view" ), context, params )
|
||||
# Render grid.
|
||||
def url( *args, **kwargs ):
|
||||
@@ -273,7 +270,6 @@ class Grid( object ):
|
||||
status = status,
|
||||
message = message,
|
||||
use_panels=self.use_panels,
|
||||
webapp=webapp,
|
||||
show_item_checkboxes = ( self.show_item_checkboxes or
|
||||
kwargs.get( 'show_item_checkboxes', '' ) in [ 'True', 'true' ] ),
|
||||
# Pass back kwargs so that grid template can set and use args without
|
||||
|
||||
@@ -1085,6 +1085,7 @@ div.debug {
|
||||
vertical-align: bottom;
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
white-space: nowrap;
|
||||
// border: 1px solid #aaa;
|
||||
}
|
||||
.gray-background {
|
||||
|
||||
@@ -976,7 +976,7 @@ div.debug{margin:10px;padding:5px;background:#FFFF99;border:solid #FFFF33 1px;co
|
||||
#advanced-search table{border-collapse:separate;}
|
||||
.delete-search-icon{background:url(../images/delete_tag_icon_gray.png) center no-repeat;display:inline-block;width:10px;cursor:pointer;height:18px;vertical-align:middle;margin-left:2px;}
|
||||
.search-box-input{border:0;float:left;outline:medium none;font-style:italic;font-size:inherit;}
|
||||
.search-box{vertical-align:bottom;display:inline-block;padding:0;}
|
||||
.search-box{vertical-align:bottom;display:inline-block;padding:0;white-space:nowrap;}
|
||||
.gray-background{background-color:#DDDDDD;}
|
||||
.loading-elt-overlay{background-color:white;opacity:0.5;width:100%;height:100%;z-index:14000;position:fixed;display:none;}
|
||||
div.odd_row{background:#dadfef;}
|
||||
|
||||
@@ -0,0 +1,549 @@
|
||||
// External dependencies (for module management eventually): jQuery, Backbone, underscore
|
||||
|
||||
// This is necessary so that, when nested arrays are used in ajax/post/get methods, square brackets ('[]') are
|
||||
// not appended to the identifier of a nested array.
|
||||
jQuery.ajaxSettings.traditional = true;
|
||||
|
||||
// Initialize grid objects on load.
|
||||
$(document).ready(function() {
|
||||
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"); });
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* A Galaxy grid.
|
||||
*/
|
||||
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
|
||||
},
|
||||
|
||||
/**
|
||||
* Return true if operation can be done asynchronously.
|
||||
*/
|
||||
can_async_op: function(op) {
|
||||
return _.indexOf(this.attributes.async_ops, op) !== -1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Add filtering criterion.
|
||||
*/
|
||||
add_filter: function(key, value, append) {
|
||||
// Update URL arg with new condition.
|
||||
if (append) {
|
||||
// Update or append value.
|
||||
var cur_val = this.attributes.key,
|
||||
new_val;
|
||||
if (cur_val === null || cur_val === undefined) {
|
||||
new_val = value;
|
||||
}
|
||||
else if (typeof(cur_val) == "string") {
|
||||
if (cur_val == "All") {
|
||||
new_val = value;
|
||||
} else {
|
||||
// Replace string with array.
|
||||
var values = [];
|
||||
values[0] = cur_val;
|
||||
values[1] = value;
|
||||
new_val = values;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Current value is an array.
|
||||
new_val = cur_val;
|
||||
new_val.push(value);
|
||||
}
|
||||
this.attributes.filters[key] = new_val;
|
||||
}
|
||||
else {
|
||||
// Replace value.
|
||||
this.attributes.filters[key] = value;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove filtering criterion.
|
||||
*/
|
||||
remove_filter: function(key, condition) {
|
||||
var cur_val = this.attributes.filters[key];
|
||||
if (cur_val === null || cur_val === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var removed = true;
|
||||
if (typeof(cur_val) === "string") {
|
||||
if (cur_val == "All") {
|
||||
// Unexpected. Throw error?
|
||||
removed = false;
|
||||
}
|
||||
else {
|
||||
// Remove condition.
|
||||
delete this.attributes.filters[key];
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Filter contains an array of conditions.
|
||||
var condition_index = _.indexOf(cur_val, condition);
|
||||
if (condition_index !== -1) {
|
||||
cur_val.splice(condition_index, 1);
|
||||
}
|
||||
else {
|
||||
removed = false;
|
||||
}
|
||||
}
|
||||
|
||||
return removed;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns URL data for obtaining a new grid.
|
||||
*/
|
||||
get_url_data: function() {
|
||||
var url_data = {
|
||||
async: this.attributes.async,
|
||||
sort: this.attributes.sort_key,
|
||||
page: this.attributes.cur_page,
|
||||
show_item_checkboxes: this.attributes.show_item_checkboxes,
|
||||
operation: this.attributes.operation,
|
||||
id: this.attributes.item_ids
|
||||
};
|
||||
|
||||
// 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];
|
||||
});
|
||||
|
||||
return url_data;
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// Code to handle grid operations: filtering, sorting, paging, and operations.
|
||||
//
|
||||
|
||||
// Init operation buttons.
|
||||
function init_operation_buttons() {
|
||||
// Initialize operation buttons.
|
||||
$('input[name=operation]:submit').each(function() {
|
||||
$(this).click( function() {
|
||||
var operation_name = $(this).val();
|
||||
// For some reason, $('input[name=id]:checked').val() does not return all ids for checked boxes.
|
||||
// The code below performs this function.
|
||||
var item_ids = [];
|
||||
$('input[name=id]:checked').each(function() {
|
||||
item_ids.push( $(this).val() );
|
||||
});
|
||||
do_operation(operation_name, item_ids);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize grid controls
|
||||
function init_grid_controls() {
|
||||
init_operation_buttons();
|
||||
|
||||
// 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');
|
||||
});
|
||||
});
|
||||
|
||||
// Initialize sort links.
|
||||
$('.sort-link').each( function() {
|
||||
$(this).click( function() {
|
||||
set_sort_condition( $(this).attr('sort_key') );
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
// Initialize page links.
|
||||
$('.page-link > a').each( function() {
|
||||
$(this).click( function() {
|
||||
set_page( $(this).attr('page_num') );
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
// Initialize categorical filters.
|
||||
$('.categorical-filter > a').each( function() {
|
||||
$(this).click( function() {
|
||||
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('');
|
||||
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(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.
|
||||
$('.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();
|
||||
}
|
||||
}
|
||||
|
||||
// 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];
|
||||
}
|
||||
}
|
||||
// Do operation.
|
||||
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.
|
||||
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();
|
||||
}
|
||||
|
||||
// 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();
|
||||
init_operation_buttons();
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for ( i=0; i < checks.length; i++ ) {
|
||||
if ( checks[i].name.indexOf( 'id' ) !== -1) {
|
||||
checks[i].checked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
init_grid_elements();
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
var History=BaseModel.extend(LoggableMixin).extend({defaults:{id:"",name:"",state:"",diskSize:0,deleted:false,annotation:null,message:null},urlRoot:"api/histories/",url:function(){return"api/histories/"+this.get("id")},initialize:function(a,b){this.log(this+".initialize:",a,b);this.hdas=new HDACollection();if(b&&b.length){this.hdas.reset(b);this.checkForUpdates()}},loadFromApi:function(a,c){var b=this;b.attributes.id=a;jQuery.when(jQuery.ajax("api/users/current"),b.fetch()).then(function(e,d){b.attributes.user=e[0];b.trigger("loaded:user",e[0]);b.trigger("loaded",d[0])}).then(function(){jQuery.ajax(b.url()+"/contents?"+jQuery.param({ids:b.hdaIdsFromStateIds().join(",")})).success(function(d){b.hdas.reset(d);b.checkForUpdates();b.trigger("loaded:hdas",d);if(c){callback(b)}})})},hdaIdsFromStateIds:function(){return _.reduce(_.values(this.get("state_ids")),function(b,a){return b.concat(a)})},checkForUpdates:function(a){if(this.hdas.running().length){this.stateUpdater()}else{this.trigger("ready")}return this},stateUpdater:function(){var c=this,a=this.get("state"),b=this.get("state_ids");jQuery.ajax("api/histories/"+this.get("id")).success(function(d){c.set(d);c.log("current history state:",c.get("state"),"(was)",a,"new size:",c.get("nice_size"));var e=[];_.each(_.keys(d.state_ids),function(g){var f=_.difference(d.state_ids[g],b[g]);e=e.concat(f)});if(e.length){c.updateHdas(e)}if((c.get("state")===HistoryDatasetAssociation.STATES.RUNNING)||(c.get("state")===HistoryDatasetAssociation.STATES.QUEUED)){setTimeout(function(){c.stateUpdater()},History.UPDATE_DELAY)}else{c.trigger("ready")}}).error(function(f,d,e){if(!((f.readyState===0)&&(f.status===0))){alert(_l("Error getting history updates from the server.")+"\n"+e)}})},updateHdas:function(b){var a=this;jQuery.ajax({url:this.url()+"/contents?"+jQuery.param({ids:b.join(",")}),error:function(f,c,d){var e="ERROR updating hdas from api history contents:";a.log(e,b,f,c,d);alert(e+b.join(","))},success:function(d,c,f){a.log(a+".updateHdas, success:",d,c,f);var e=[];_.each(d,function(h,i){var g=a.hdas.get(h.id);if(g){a.log("found existing model in list for id "+h.id+", updating...:");g.set(h)}else{a.log("NO existing model for id "+h.id+", creating...:");e.push(h)}});if(e.length){a.addHdas(e)}}})},addHdas:function(a){var b=this;_.each(a,function(c,d){var e=b.hdas.hidToCollectionIndex(c.hid);c.history_id=b.get("id");b.hdas.add(new HistoryDatasetAssociation(c),{at:e,silent:true})});b.hdas.trigger("add",a)},toString:function(){var a=(this.get("name"))?(","+this.get("name")):("");return"History("+this.get("id")+a+")"}});History.UPDATE_DELAY=4000;var HistoryCollection=Backbone.Collection.extend(LoggableMixin).extend({model:History,urlRoot:"api/histories"});
|
||||
var History=BaseModel.extend(LoggableMixin).extend({defaults:{id:"",name:"",state:"",diskSize:0,deleted:false,annotation:null,message:null},urlRoot:"api/histories/",url:function(){return"api/histories/"+this.get("id")},initialize:function(a,b){this.log(this+".initialize:",a,b);this.hdas=new HDACollection();if(b){if(_.isArray(b)){this.hdas.reset(b);this.checkForUpdates()}else{if(_.isString(b)&&(b.match(/error/i))){alert(_l("Error loading bootstrapped history")+":\n"+b)}}}},loadFromApi:function(a,c){var b=this;b.attributes.id=a;jQuery.when(jQuery.ajax("api/users/current"),b.fetch()).then(function(e,d){b.attributes.user=e[0];b.trigger("loaded:user",e[0]);b.trigger("loaded",d[0])}).then(function(){jQuery.ajax(b.url()+"/contents?"+jQuery.param({ids:b.hdaIdsFromStateIds().join(",")})).success(function(d){b.hdas.reset(d);b.checkForUpdates();b.trigger("loaded:hdas",d);if(c){callback(b)}})})},hdaIdsFromStateIds:function(){return _.reduce(_.values(this.get("state_ids")),function(b,a){return b.concat(a)})},checkForUpdates:function(a){if(this.hdas.running().length){this.stateUpdater()}else{this.trigger("ready")}return this},stateUpdater:function(){var c=this,a=this.get("state"),b=this.get("state_ids");jQuery.ajax("api/histories/"+this.get("id")).success(function(d){c.set(d);c.log("current history state:",c.get("state"),"(was)",a,"new size:",c.get("nice_size"));var e=[];_.each(_.keys(d.state_ids),function(g){var f=_.difference(d.state_ids[g],b[g]);e=e.concat(f)});if(e.length){c.fetchHdaUpdates(e)}if((c.get("state")===HistoryDatasetAssociation.STATES.RUNNING)||(c.get("state")===HistoryDatasetAssociation.STATES.QUEUED)){setTimeout(function(){c.stateUpdater()},History.UPDATE_DELAY)}else{c.trigger("ready")}}).error(function(f,d,e){if(!((f.readyState===0)&&(f.status===0))){alert(_l("Error getting history updates from the server.")+"\n"+e)}})},fetchHdaUpdates:function(b){var a=this;jQuery.ajax({url:this.url()+"/contents?"+jQuery.param({ids:b.join(",")}),error:function(h,c,d){if((h.readyState===0)&&(h.status===0)){return}var f=JSON.parse(h.responseText);if(_.isArray(f)){var e=_.groupBy(f,function(i){if(_.has(i,"error")){return"errored"}return"ok"});a.log("fetched, errored datasets:",e.errored);a.updateHdas(f)}else{var g=_l("ERROR updating hdas from api history contents")+": ";a.log(g,b,h,c,d,errorJSON);alert(g+b.join(","))}},success:function(d,c,e){a.log(a+".fetchHdaUpdates, success:",c,e);a.updateHdas(d)}})},updateHdas:function(a){var c=this,b=[];c.log(c+".updateHdas:",a);_.each(a,function(e,f){var d=c.hdas.get(e.id);if(d){c.log("found existing model in list for id "+e.id+", updating...:");d.set(e)}else{c.log("NO existing model for id "+e.id+", creating...:");b.push(e)}});if(b.length){c.addHdas(b)}},addHdas:function(a){var b=this;_.each(a,function(c,d){var e=b.hdas.hidToCollectionIndex(c.hid);c.history_id=b.get("id");b.hdas.add(new HistoryDatasetAssociation(c),{at:e,silent:true})});b.hdas.trigger("add",a)},toString:function(){var a=(this.get("name"))?(","+this.get("name")):("");return"History("+this.get("id")+a+")"}});History.UPDATE_DELAY=4000;var HistoryCollection=Backbone.Collection.extend(LoggableMixin).extend({model:History,urlRoot:"api/histories"});
|
||||
@@ -1 +1 @@
|
||||
define(["base","libs/underscore","viz/trackster/slotting","viz/trackster/painters","viz/trackster/tracks","viz/visualization"],function(g,c,h,e,b,d){var a=b.object_from_template;var f=g.Base.extend({initialize:function(j){this.baseURL=j},createButtonMenu:function(){var j=this,k=create_icon_buttons_menu([{icon_class:"plus-button",title:"Add tracks",on_click:function(){d.select_datasets(select_datasets_url,add_track_async_url,{"f-dbkey":view.dbkey},function(l){c.each(l,function(m){view.add_drawable(a(m,view,view))})})}},{icon_class:"block--plus",title:"Add group",on_click:function(){view.add_drawable(new b.DrawableGroup(view,view,{name:"New Group"}))}},{icon_class:"bookmarks",title:"Bookmarks",on_click:function(){parent.force_right_panel(($("div#right").css("right")=="0px"?"hide":"show"))}},{icon_class:"globe",title:"Circster",on_click:function(){window.location=j.baseURL+"visualization/circster?id="+view.vis_id}},{icon_class:"disk--arrow",title:"Save",on_click:function(){show_modal("Saving...","progress");var l=[];$(".bookmark").each(function(){l.push({position:$(this).children(".position").text(),annotation:$(this).children(".annotation").text()})});var m=(view.overview_drawable?view.overview_drawable.name:null),n={view:view.to_dict(),viewport:{chrom:view.chrom,start:view.low,end:view.high,overview:m},bookmarks:l};$.ajax({url:galaxy_paths.get("visualization_url"),type:"POST",dataType:"json",data:{id:view.vis_id,title:view.name,dbkey:view.dbkey,type:"trackster",vis_json:JSON.stringify(n)}}).success(function(o){hide_modal();view.vis_id=o.vis_id;view.has_changes=false;window.history.pushState({},"",o.url+window.location.hash)}).error(function(){show_modal("Could Not Save","Could not save visualization. Please try again later.",{Close:hide_modal})})}},{icon_class:"cross-circle",title:"Close",on_click:function(){window.location=j.baseURL+"visualization/list"}}],{tooltip_config:{placement:"bottom"}});this.buttonMenu=k;return k},add_bookmarks:function(){var j=this,k=this.baseURL;show_modal("Select dataset for new bookmarks","progress");$.ajax({url:this.baseURL+"/visualization/list_histories",data:{"f-dbkey":view.dbkey},error:function(){alert("Grid failed")},success:function(l){show_modal("Select dataset for new bookmarks",l,{Cancel:function(){hide_modal()},Insert:function(){$("input[name=id]:checked,input[name=ldda_ids]:checked").first().each(function(){var m,n=$(this).val();if($(this).attr("name")==="id"){m={hda_id:n}}else{m={ldda_id:n}}$.ajax({url:this.baseURL+"/visualization/bookmarks_from_dataset",data:m,dataType:"json"}).then(function(o){for(i=0;i<o.data.length;i++){var p=o.data[i];j.add_bookmark(p[0],p[1])}})});hide_modal()}})}})},add_bookmark:function(n,l,j){var p=$("#bookmarks-container"),r=$("<div/>").addClass("bookmark").appendTo(p);var s=$("<div/>").addClass("position").appendTo(r),o=$("<a href=''/>").text(n).appendTo(s).click(function(){view.go_to(n);return false}),m=$("<div/>").text(l).appendTo(r);if(j){var q=$("<div/>").addClass("delete-icon-container").prependTo(r).click(function(){r.slideUp("fast");r.remove();view.has_changes=true;return false}),k=$("<a href=''/>").addClass("icon-button delete").appendTo(q);m.make_text_editable({num_rows:3,use_textarea:true,help_text:"Edit bookmark note"}).addClass("annotation")}view.has_changes=true;return r},create_visualization:function(o,j,n,p,m){var l=this,k=new b.TracksterView(o);k.editor=true;$.when(k.load_chroms_deferred).then(function(A){if(j){var y=j.chrom,q=j.start,v=j.end,s=j.overview;if(y&&(q!==undefined)&&v){k.change_chrom(y,q,v)}}else{k.change_chrom(A[0].chrom)}if(n){var t,r,u;for(var w=0;w<n.length;w++){k.add_drawable(a(n[w],k,k))}}k.update_intro_div();var z;for(var w=0;w<k.drawables.length;w++){if(k.drawables[w].name===s){k.set_overview(k.drawables[w]);break}}if(p){var x;for(var w=0;w<p.length;w++){x=p[w];l.add_bookmark(x.position,x.annotation,m)}}k.has_changes=false});return k},init_keyboard_nav:function(j){$(document).keydown(function(k){if($(k.srcElement).is(":input")){return}switch(k.which){case 37:j.move_fraction(0.25);break;case 38:var l=Math.round(j.viewport_container.height()/15);j.viewport_container.scrollTop(j.viewport_container.scrollTop()-20);break;case 39:j.move_fraction(-0.25);break;case 40:var l=Math.round(j.viewport_container.height()/15);j.viewport_container.scrollTop(j.viewport_container.scrollTop()+20);break}})}});return{object_from_template:a,TracksterUI:f}});
|
||||
define(["base","libs/underscore","viz/trackster/slotting","viz/trackster/painters","viz/trackster/tracks","viz/visualization"],function(g,c,h,e,b,d){var a=b.object_from_template;var f=g.Base.extend({initialize:function(j){this.baseURL=j},createButtonMenu:function(){var j=this,k=create_icon_buttons_menu([{icon_class:"plus-button",title:"Add tracks",on_click:function(){d.select_datasets(select_datasets_url,add_track_async_url,{"f-dbkey":view.dbkey},function(l){c.each(l,function(m){view.add_drawable(a(m,view,view))})})}},{icon_class:"block--plus",title:"Add group",on_click:function(){view.add_drawable(new b.DrawableGroup(view,view,{name:"New Group"}))}},{icon_class:"bookmarks",title:"Bookmarks",on_click:function(){parent.force_right_panel(($("div#right").css("right")=="0px"?"hide":"show"))}},{icon_class:"globe",title:"Circster",on_click:function(){window.location=j.baseURL+"visualization/circster?id="+view.vis_id}},{icon_class:"disk--arrow",title:"Save",on_click:function(){show_modal("Saving...","progress");var l=[];$(".bookmark").each(function(){l.push({position:$(this).children(".position").text(),annotation:$(this).children(".annotation").text()})});var m=(view.overview_drawable?view.overview_drawable.name:null),n={view:view.to_dict(),viewport:{chrom:view.chrom,start:view.low,end:view.high,overview:m},bookmarks:l};$.ajax({url:galaxy_paths.get("visualization_url"),type:"POST",dataType:"json",data:{id:view.vis_id,title:view.name,dbkey:view.dbkey,type:"trackster",vis_json:JSON.stringify(n)}}).success(function(o){hide_modal();view.vis_id=o.vis_id;view.has_changes=false;window.history.pushState({},"",o.url+window.location.hash)}).error(function(){show_modal("Could Not Save","Could not save visualization. Please try again later.",{Close:hide_modal})})}},{icon_class:"cross-circle",title:"Close",on_click:function(){window.location=j.baseURL+"visualization/list"}}],{tooltip_config:{placement:"bottom"}});this.buttonMenu=k;return k},add_bookmarks:function(){var j=this,k=this.baseURL;show_modal("Select dataset for new bookmarks","progress");$.ajax({url:this.baseURL+"/visualization/list_histories",data:{"f-dbkey":view.dbkey},error:function(){alert("Grid failed")},success:function(l){show_modal("Select dataset for new bookmarks",l,{Cancel:function(){hide_modal()},Insert:function(){$("input[name=id]:checked,input[name=ldda_ids]:checked").first().each(function(){var m,n=$(this).val();if($(this).attr("name")==="id"){m={hda_id:n}}else{m={ldda_id:n}}$.ajax({url:this.baseURL+"/visualization/bookmarks_from_dataset",data:m,dataType:"json"}).then(function(o){for(i=0;i<o.data.length;i++){var p=o.data[i];j.add_bookmark(p[0],p[1])}})});hide_modal()}})}})},add_bookmark:function(n,l,j){var p=$("#bookmarks-container"),r=$("<div/>").addClass("bookmark").appendTo(p);var s=$("<div/>").addClass("position").appendTo(r),o=$("<a href=''/>").text(n).appendTo(s).click(function(){view.go_to(n);return false}),m=$("<div/>").text(l).appendTo(r);if(j){var q=$("<div/>").addClass("delete-icon-container").prependTo(r).click(function(){r.slideUp("fast");r.remove();view.has_changes=true;return false}),k=$("<a href=''/>").addClass("icon-button delete").appendTo(q);m.make_text_editable({num_rows:3,use_textarea:true,help_text:"Edit bookmark note"}).addClass("annotation")}view.has_changes=true;return r},create_visualization:function(o,j,n,p,m){var l=this,k=new b.TracksterView(o);k.editor=true;$.when(k.load_chroms_deferred).then(function(A){if(j){var y=j.chrom,q=j.start,v=j.end,s=j.overview;if(y&&(q!==undefined)&&v){k.change_chrom(y,q,v)}else{k.change_chrom(A[0].chrom)}}else{k.change_chrom(A[0].chrom)}if(n){var t,r,u;for(var w=0;w<n.length;w++){k.add_drawable(a(n[w],k,k))}}k.update_intro_div();var z;for(var w=0;w<k.drawables.length;w++){if(k.drawables[w].name===s){k.set_overview(k.drawables[w]);break}}if(p){var x;for(var w=0;w<p.length;w++){x=p[w];l.add_bookmark(x.position,x.annotation,m)}}k.has_changes=false});return k},init_keyboard_nav:function(j){$(document).keydown(function(k){if($(k.srcElement).is(":input")){return}switch(k.which){case 37:j.move_fraction(0.25);break;case 38:var l=Math.round(j.viewport_container.height()/15);j.viewport_container.scrollTop(j.viewport_container.scrollTop()-20);break;case 39:j.move_fraction(-0.25);break;case 40:var l=Math.round(j.viewport_container.height()/15);j.viewport_container.scrollTop(j.viewport_container.scrollTop()+20);break}})}});return{object_from_template:a,TracksterUI:f}});
|
||||
+32
-518
@@ -52,23 +52,8 @@
|
||||
</%def>
|
||||
|
||||
<%def name="grid_javascripts()">
|
||||
${h.js("libs/jquery/jquery.autocomplete", "galaxy.autocom_tagging", "libs/jquery/jquery.rating" )}
|
||||
${h.js("libs/jquery/jquery.autocomplete", "galaxy.autocom_tagging", "libs/jquery/jquery.rating", "galaxy.grids" )}
|
||||
<script type="text/javascript">
|
||||
// This is necessary so that, when nested arrays are used in ajax/post/get methods, square brackets ('[]') are
|
||||
// not appended to the identifier of a nested array.
|
||||
jQuery.ajaxSettings.traditional = true;
|
||||
|
||||
## TODO: generalize and move into galaxy.base.js
|
||||
$(document).ready(function() {
|
||||
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"); })
|
||||
});
|
||||
});
|
||||
## TODO: Can this be moved into base.mako? Also, this is history-specific grid code.
|
||||
%if refresh_frames:
|
||||
%if 'masthead' in refresh_frames:
|
||||
@@ -90,7 +75,7 @@
|
||||
}
|
||||
else {
|
||||
// TODO: redirecting to root should be done on the server side so that page
|
||||
// doesn't have to load.
|
||||
// does not have to load.
|
||||
|
||||
// No history frame, so refresh to root to see history.
|
||||
window.top.location.href = "${h.url_for( controller='root' )}";
|
||||
@@ -105,146 +90,21 @@
|
||||
}
|
||||
%endif
|
||||
%endif
|
||||
|
||||
//
|
||||
// Code to handle grid operations: filtering, sorting, paging, and operations.
|
||||
//
|
||||
|
||||
// Operations that are async (AJAX) compatible.
|
||||
var async_ops = {};
|
||||
%for operation in [op for op in grid.operations if op.async_compatible]:
|
||||
async_ops['${operation.label.lower()}'] = "True";
|
||||
%endfor
|
||||
|
||||
// Init operation buttons.
|
||||
function init_operation_buttons() {
|
||||
// Initialize operation buttons.
|
||||
$('input[name=operation]:submit').each(function() {
|
||||
$(this).click( function() {
|
||||
var webapp = $("input[name=webapp]").attr("value");
|
||||
var operation_name = $(this).val();
|
||||
// For some reason, $('input[name=id]:checked').val() does not return all ids for checked boxes.
|
||||
// The code below performs this function.
|
||||
var item_ids = [];
|
||||
$('input[name=id]:checked').each(function() {
|
||||
item_ids.push( $(this).val() );
|
||||
});
|
||||
do_operation(webapp, operation_name, item_ids);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Initialize grid controls
|
||||
function init_grid_controls() {
|
||||
init_operation_buttons();
|
||||
|
||||
// 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');
|
||||
});
|
||||
});
|
||||
|
||||
// Initialize sort links.
|
||||
$('.sort-link').each( function() {
|
||||
$(this).click( function() {
|
||||
set_sort_condition( $(this).attr('sort_key') );
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
// Initialize page links.
|
||||
$('.page-link > a').each( function() {
|
||||
$(this).click( function() {
|
||||
set_page( $(this).attr('page_num') );
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
// Initialize categorical filters.
|
||||
$('.categorical-filter > a').each( function() {
|
||||
$(this).click( function() {
|
||||
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('');
|
||||
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( "${h.url_for( controller='tag', action='tag_autocomplete_data', item_class='History' )}",
|
||||
{ selectFirst: false, autoFill: false, highlight: false, mustMatch: false });
|
||||
}
|
||||
|
||||
var t2 = $("#input-name-filter");
|
||||
if (t2.length) {
|
||||
t2.autocomplete( "${h.url_for( controller='history', action='name_autocomplete_data' )}",
|
||||
{ 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.
|
||||
$('.community_rating_star').rating({});
|
||||
|
||||
// Initialize item menu operations.
|
||||
make_popup_menus();
|
||||
}
|
||||
|
||||
// Needed URLs for grid history searching.
|
||||
var history_tag_autocomplete_url = "${h.url_for( controller='tag', action='tag_autocomplete_data', item_class='History' )}",
|
||||
history_name_autocomplete_url = "${h.url_for( controller='history', action='name_autocomplete_data' )}";
|
||||
|
||||
//
|
||||
// Create grid object.
|
||||
//
|
||||
|
||||
// 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
|
||||
|
||||
// Filter values for categorical filters.
|
||||
var categorical_filters = {};
|
||||
%for column in grid.columns:
|
||||
@@ -253,367 +113,22 @@
|
||||
categorical_filters['${column.key}'] = ${column.key}_filters;
|
||||
%endif
|
||||
%endfor
|
||||
|
||||
// Initialize URL args with filter arguments.
|
||||
var url_args_init = ${h.to_json_string( cur_filter_dict )},
|
||||
url_args = {};
|
||||
|
||||
// Place "f-" in front of all filter arguments.
|
||||
|
||||
for (arg in url_args_init) {
|
||||
url_args["f-" + arg] = url_args_init[arg];
|
||||
}
|
||||
|
||||
// Add sort argument to URL args.
|
||||
url_args['sort'] = "${sort_key}";
|
||||
|
||||
// Add show_item_checkboxes argument to URL args.
|
||||
url_args['show_item_checkboxes'] = ("${context.get('show_item_checkboxes', False)}" === "True");
|
||||
|
||||
// Add async keyword to URL args.
|
||||
url_args['async'] = true;
|
||||
|
||||
// Add page to URL args.
|
||||
url_args['page'] = ${cur_page_num};
|
||||
|
||||
var num_pages = ${num_pages};
|
||||
|
||||
// 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 = url_args['page'];
|
||||
if (cur_page !== null && cur_page !== undefined && cur_page != 'all') {
|
||||
url_args['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;
|
||||
}
|
||||
|
||||
// Update URL arg with new condition.
|
||||
if (append) {
|
||||
// Update or append value.
|
||||
var cur_val = url_args["f-" + name];
|
||||
var new_val;
|
||||
if (cur_val === null || cur_val === undefined) {
|
||||
new_val = value;
|
||||
} else if (typeof(cur_val) == "string") {
|
||||
if (cur_val == "All") {
|
||||
new_val = value;
|
||||
} else {
|
||||
// Replace string with array.
|
||||
var values = [];
|
||||
values[0] = cur_val;
|
||||
values[1] = value;
|
||||
new_val = values;
|
||||
}
|
||||
} else {
|
||||
// Current value is an array.
|
||||
new_val = cur_val;
|
||||
new_val[new_val.length] = value;
|
||||
}
|
||||
url_args["f-" + name] = new_val;
|
||||
} else {
|
||||
// Replace value.
|
||||
url_args["f-" + name] = value;
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
||||
// Remove visible element.
|
||||
$(this).remove();
|
||||
|
||||
// Remove condition from URL args.
|
||||
var cur_val = url_args["f-" + name];
|
||||
if (cur_val === null || cur_val === undefined) {
|
||||
// Unexpected. Throw error?
|
||||
} else if (typeof(cur_val) == "string") {
|
||||
if (cur_val == "All") {
|
||||
// Unexpected. Throw error?
|
||||
} else {
|
||||
// Remove condition.
|
||||
delete url_args["f-" + name];
|
||||
}
|
||||
} else {
|
||||
// Current value is an array.
|
||||
var conditions = cur_val;
|
||||
for (var index = 0; index < conditions.length; index++) {
|
||||
if (conditions[index] == value) {
|
||||
conditions.splice(index, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 = url_args['sort'];
|
||||
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);
|
||||
|
||||
// Need to go back to page 1 if not showing all.
|
||||
var cur_page = url_args['page'];
|
||||
if (cur_page !== null && cur_page !== undefined && cur_page != 'all') {
|
||||
url_args['page'] = 1;
|
||||
}
|
||||
// Update grid.
|
||||
url_args['sort'] = 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 = categorical_filters[name];
|
||||
var cur_value = url_args["f-" + 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.
|
||||
url_args["f-" + 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');
|
||||
var page_num = parseInt( id.split("-")[2] ); // Id has form 'page-link-<page_num>
|
||||
var cur_page = url_args['page'];
|
||||
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.
|
||||
var 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.
|
||||
var 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") {
|
||||
url_args['page'] = new_page;
|
||||
maintain_page_links = false;
|
||||
} else {
|
||||
url_args['page'] = parseInt(new_page);
|
||||
}
|
||||
update_grid(maintain_page_links);
|
||||
}
|
||||
|
||||
// Perform a grid operation.
|
||||
function do_operation(webapp, operation, item_ids) {
|
||||
operation = operation.toLowerCase();
|
||||
|
||||
// Update URL args.
|
||||
url_args["webapp"] = webapp;
|
||||
url_args["operation"] = operation;
|
||||
url_args["id"] = item_ids;
|
||||
|
||||
// If operation cannot be performed asynchronously, redirect to location. Otherwise do operation.
|
||||
var no_async = ( async_ops[operation] === undefined || async_ops[operation] === null);
|
||||
if (no_async) {
|
||||
go_to_URL();
|
||||
} else {
|
||||
update_grid(true);
|
||||
delete url_args['webapp'];
|
||||
delete url_args['operation'];
|
||||
delete url_args['id'];
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
var webapp = 'galaxy';
|
||||
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];
|
||||
} else if (href_parms[index].indexOf('webapp') != -1) {
|
||||
// Found webapp parm; get webapp value.
|
||||
webapp = href_parms[index].split('=')[1];
|
||||
}
|
||||
}
|
||||
// Do operation.
|
||||
do_operation(webapp, operation, id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Navigate window to the URL defined by url_args. This method should be used to short-circuit grid AJAXing.
|
||||
function go_to_URL() {
|
||||
// Not async request.
|
||||
url_args['async'] = false;
|
||||
|
||||
// Build argument string.
|
||||
var arg_str = "";
|
||||
for (var arg in url_args) {
|
||||
arg_str = arg_str + arg + "=" + url_args[arg] + "&";
|
||||
}
|
||||
|
||||
// Go.
|
||||
window.location = encodeURI( "${h.url_for()}?" + arg_str );
|
||||
}
|
||||
|
||||
// Update grid.
|
||||
function update_grid(maintain_page_links) {
|
||||
## If grid is not using async, then go to URL.
|
||||
%if not grid.use_async:
|
||||
go_to_URL();
|
||||
return;
|
||||
%endif
|
||||
|
||||
// If there's an operation in the args, do POST; otherwise, do GET.
|
||||
var operation = url_args['operation'];
|
||||
var method = (operation !== null && operation !== undefined ? "POST" : "GET" );
|
||||
$('.loading-elt-overlay').show(); // Show overlay to indicate loading and prevent user actions.
|
||||
$.ajax({
|
||||
type: method,
|
||||
url: "${h.url_for()}",
|
||||
data: url_args,
|
||||
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();
|
||||
init_operation_buttons();
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function check_all_items() {
|
||||
var chk_all = document.getElementById('check_all');
|
||||
var checks = document.getElementsByTagName('input');
|
||||
//var boxLength = checks.length;
|
||||
var total = 0;
|
||||
if ( chk_all.checked == true ) {
|
||||
for ( i=0; i < checks.length; i++ ) {
|
||||
if ( checks[i].name.indexOf( 'id' ) != -1) {
|
||||
checks[i].checked = true;
|
||||
total++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for ( i=0; i < checks.length; i++ ) {
|
||||
if ( checks[i].name.indexOf( 'id' ) != -1) {
|
||||
checks[i].checked = false
|
||||
}
|
||||
}
|
||||
}
|
||||
init_grid_elements();
|
||||
}
|
||||
|
||||
/** 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: '${h.url_for()}',
|
||||
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},
|
||||
num_pages: ${num_pages}
|
||||
});
|
||||
</script>
|
||||
</%def>
|
||||
|
||||
@@ -700,7 +215,6 @@
|
||||
show_item_checkboxes = True
|
||||
%>
|
||||
<form action="${url()}" method="post" onsubmit="return false;">
|
||||
<input type="hidden" name="webapp" value="${webapp}"/>
|
||||
<table id="grid-table" class="grid">
|
||||
<thead id="grid-table-header">
|
||||
<tr>
|
||||
|
||||
Reference in New Issue
Block a user