Refactored grid code to (a) generalize numerous column types and (b) fully support multiple, arbitrary, multi-column categorical and free-text queries. Python code provides support for TextColumn and TagColumn objects, and grids_common.mako provides support for programmatically creating free text and categorical filtering UIs. History and HDA grids have been updated to use the refactored code.

This commit is contained in:
Jeremy Goecks
2009-11-06 19:04:13 -05:00
parent 8879adc01e
commit fbf5616dbc
12 changed files with 394 additions and 304 deletions
+1 -1
View File
@@ -246,7 +246,7 @@ class History( object ):
# This needs to be a list
return [ hda for hda in self.datasets if not hda.dataset.deleted ]
def get_display_name( self ):
## History name can be either a string or a unicode object. If string, convert to unicode object assuming 'utf-8' format.
""" History name can be either a string or a unicode object. If string, convert to unicode object assuming 'utf-8' format. """
history_name = self.name
if isinstance(history_name, str):
history_name = unicode(history_name, 'utf-8')
+10 -53
View File
@@ -1,7 +1,6 @@
import logging, os, string, shutil, re, socket, mimetypes, smtplib, urllib
from galaxy.web.base.controller import *
from galaxy.tags.tag_handler import TagHandler
from galaxy.web.framework.helpers import time_ago, iff, grids
from galaxy import util, datatypes, jobs, web, model
from cgi import escape, FieldStorage
@@ -49,55 +48,7 @@ class HistoryDatasetAssociationListGrid( grids.Grid ):
class HistoryColumn( grids.GridColumn ):
def get_value( self, trans, grid, hda):
return hda.history.name
class StatusColumn( grids.GridColumn ):
def get_value( self, trans, grid, hda ):
if hda.deleted:
return "deleted"
return ""
def get_link( self, trans, grid, hda ):
return None
class TagsColumn( grids.GridColumn ):
def __init__(self, col_name, key, filterable):
grids.GridColumn.__init__(self, col_name, key=key, filterable=filterable)
# Tags cannot be sorted.
self.sortable = False
self.tag_elt_id_gen = 0
def get_value( self, trans, grid, hda ):
self.tag_elt_id_gen += 1
elt_id="tagging-elt" + str( self.tag_elt_id_gen )
div_elt = "<div id=%s></div>" % elt_id
return div_elt + trans.fill_template( "/tagging_common.mako", trans=trans, tagged_item=hda,
elt_id = elt_id, in_form="true", input_size="20", tag_click_fn="add_tag_to_grid_filter" )
def filter( self, db_session, query, column_filter ):
""" Modify query to include only hdas with tags in column_filter. """
if column_filter == "All":
pass
elif column_filter:
# Parse filter to extract multiple tags.
tag_handler = TagHandler()
raw_tags = tag_handler.parse_tags( column_filter.encode("utf-8") )
for name, value in raw_tags.items():
tag = tag_handler.get_tag_by_name( db_session, name )
if tag:
query = query.filter( model.HistoryDatasetAssociation.tags.any( tag_id=tag.id ) )
if value:
query = query.filter( model.HistoryDatasetAssociation.tags.any( value=value.lower() ) )
else:
# Tag doesn't exist; unclear what to do here, but the literal thing to do is add the criterion, which
# will then yield a query that returns no results.
query = query.filter( model.HistoryDatasetAssociation.tags.any( user_tname=name ) )
return query
def get_accepted_filters( self ):
""" Returns a list of accepted filters for this column. """
accepted_filter_labels_and_vals = { "All": "All" }
accepted_filters = []
for label, val in accepted_filter_labels_and_vals.items():
args = { self.key: val }
accepted_filters.append( grids.GridColumnFilter( label, args) )
return accepted_filters
class StatusColumn( grids.GridColumn ):
def get_value( self, trans, grid, hda ):
if hda.deleted:
@@ -118,19 +69,25 @@ class HistoryDatasetAssociationListGrid( grids.Grid ):
template='/dataset/grid.mako'
default_sort_key = "-create_time"
columns = [
grids.GridColumn( "Name", key="name",
grids.TextColumn( "Name", key="name", model_class=model.HistoryDatasetAssociation,
# Link name to dataset's history.
link=( lambda item: iff( item.history.deleted, None, dict( operation="switch", id=item.id ) ) ) ),
link=( lambda item: iff( item.history.deleted, None, dict( operation="switch", id=item.id ) ) ), filterable="advanced" ),
HistoryColumn( "History", key="history",
link=( lambda item: iff( item.history.deleted, None, dict( operation="switch_history", id=item.id ) ) ) ),
TagsColumn( "Tags", key="tags", filterable=True ),
grids.TagsColumn( "Tags", "tags", model.HistoryDatasetAssociation, model.HistoryDatasetAssociationTagAssociation, filterable="advanced" ),
StatusColumn( "Status", key="deleted", attach_popup=False ),
grids.GridColumn( "Created", key="create_time", format=time_ago ),
grids.GridColumn( "Last Updated", key="update_time", format=time_ago ),
]
columns.append(
grids.MulticolFilterColumn(
"Search",
cols_to_filter=[ columns[0], columns[2] ],
key="free-text-search", visible=False, filterable="default" )
)
operations = []
standard_filters = []
default_filter = dict( deleted="False", tags="All" )
default_filter = dict( name="All", deleted="False", tags="All" )
preserve_state = False
use_paging = True
num_rows_per_page = 50
+20 -109
View File
@@ -2,7 +2,6 @@ from galaxy.web.base.controller import *
from galaxy.web.framework.helpers import time_ago, iff, grids
from galaxy import util
from galaxy.model.mapping import desc
from galaxy.model import History
from galaxy.model.orm import *
from galaxy.util.json import *
from galaxy.util.odict import odict
@@ -19,30 +18,10 @@ SUCCESS, INFO, WARNING, ERROR = "done", "info", "warning", "error"
class HistoryListGrid( grids.Grid ):
# Custom column types
class NameColumn( grids.GridColumn ):
def __init( self, key, link, attach_popup, filterable ):
grids.GridColumn.__init__(self, key, link, attach_popup)
def get_value( self, trans, grid, history ):
class NameColumn( grids.TextColumn ):
def get_value(self, trans, grid, history):
return history.get_display_name()
def filter( self, db_session, query, column_filter ):
""" Modify query to filter histories by name. """
if column_filter == "All":
pass
elif column_filter:
query = query.filter( func.lower( History.name ).like( "%" + column_filter.lower() + "%" ) )
return query
def get_accepted_filters( self ):
""" Returns a list of accepted filters for this column. """
accepted_filter_labels_and_vals = odict()
accepted_filter_labels_and_vals["FREETEXT"] = "FREETEXT"
accepted_filters = []
for label, val in accepted_filter_labels_and_vals.iteritems():
args = { self.key: val }
accepted_filters.append( grids.GridColumnFilter( label, args) )
return accepted_filters
class DatasetsByStateColumn( grids.GridColumn ):
def get_value( self, trans, grid, history ):
rval = []
@@ -53,6 +32,7 @@ class HistoryListGrid( grids.Grid ):
else:
rval.append( '' )
return rval
class StatusColumn( grids.GridColumn ):
def get_value( self, trans, grid, history ):
if history.deleted:
@@ -66,44 +46,6 @@ class HistoryListGrid( grids.Grid ):
if item.users_shared_with or item.importable:
return dict( operation="sharing" )
return None
class TagsColumn( grids.GridColumn ):
def __init__( self, col_name, key, filterable ):
grids.GridColumn.__init__(self, col_name, key=key, filterable=filterable)
# Tags cannot be sorted.
self.sortable = False
self.tag_elt_id_gen = 0
def get_value( self, trans, grid, history ):
self.tag_elt_id_gen += 1
elt_id="tagging-elt" + str( self.tag_elt_id_gen )
div_elt = "<div id=%s></div>" % elt_id
return div_elt + trans.fill_template( "/tagging_common.mako", trans=trans, tagged_item=history,
elt_id = elt_id, in_form="true", input_size="20", tag_click_fn="add_tag_to_grid_filter" )
def filter( self, db_session, query, column_filter ):
""" Modify query to filter histories by tag. """
if column_filter == "All":
pass
elif column_filter:
# Parse filter to extract multiple tags.
tag_handler = TagHandler()
raw_tags = tag_handler.parse_tags( column_filter.encode("utf-8") )
for name, value in raw_tags.items():
if name:
# Search for tag names.
query = query.filter( History.tags.any( func.lower( model.HistoryTagAssociation.user_tname ).like( "%" + name.lower() + "%" ) ) )
if value:
# Search for tag values.
query = query.filter( History.tags.any( func.lower( model.HistoryTagAssociation.user_value ).like( "%" + value.lower() + "%" ) ) )
return query
def get_accepted_filters( self ):
""" Returns a list of accepted filters for this column. """
accepted_filter_labels_and_vals = odict()
accepted_filter_labels_and_vals["FREETEXT"] = "FREETEXT"
accepted_filters = []
for label, val in accepted_filter_labels_and_vals.iteritems():
args = { self.key: val }
accepted_filters.append( grids.GridColumnFilter( label, args) )
return accepted_filters
class DeletedColumn( grids.GridColumn ):
def get_accepted_filters( self ):
@@ -122,12 +64,12 @@ class HistoryListGrid( grids.Grid ):
pass
elif column_filter:
if column_filter == "private":
query = query.filter( History.users_shared_with == None )
query = query.filter( History.importable == False )
query = query.filter( model.History.users_shared_with == None )
query = query.filter( model.History.importable == False )
elif column_filter == "shared":
query = query.filter( History.users_shared_with != None )
query = query.filter( model.History.users_shared_with != None )
elif column_filter == "importable":
query = query.filter( History.importable == True )
query = query.filter( model.History.importable == True )
return query
def get_accepted_filters( self ):
""" Returns a list of accepted filters for this column. """
@@ -141,43 +83,6 @@ class HistoryListGrid( grids.Grid ):
args = { self.key: val }
accepted_filters.append( grids.GridColumnFilter( label, args) )
return accepted_filters
class FreeTextSearchColumn( grids.GridColumn ):
def filter( self, db_session, query, column_filter ):
""" Modify query to search tags and history names. """
if column_filter == "All":
pass
elif column_filter:
# Build tags filter.
tag_handler = TagHandler()
raw_tags = tag_handler.parse_tags( column_filter.encode("utf-8") )
tags_filter = None
for name, value in raw_tags.items():
if name:
# Search for tag names.
tags_filter = History.tags.any( func.lower( model.HistoryTagAssociation.user_tname ).like( "%" + name.lower() + "%" ) )
if value:
# Search for tag values.
tags_filter = and_( tags_filter, func.lower( History.tags.any( model.HistoryTagAssociation.user_value ).like( "%" + value.lower() + "%" ) ) )
# Build history name filter.
history_name_filter = func.lower( History.name ).like( "%" + column_filter.lower() + "%" )
# Apply filters to query.
if tags_filter:
query = query.filter( or_( tags_filter, history_name_filter ) )
else:
query = query.filter( history_name_filter )
return query
def get_accepted_filters( self ):
""" Returns a list of accepted filters for this column. """
accepted_filter_labels_and_vals = odict()
accepted_filter_labels_and_vals["FREETEXT"] = "FREETEXT"
accepted_filters = []
for label, val in accepted_filter_labels_and_vals.iteritems():
args = { self.key: val }
accepted_filters.append( grids.GridColumnFilter( label, args) )
return accepted_filters
# Grid definition
title = "Saved Histories"
@@ -185,19 +90,25 @@ class HistoryListGrid( grids.Grid ):
template='/history/grid.mako'
default_sort_key = "-create_time"
columns = [
NameColumn( "Name", key="name",
NameColumn( "Name", key="name", model_class=model.History,
link=( lambda history: iff( history.deleted, None, dict( operation="switch", id=history.id ) ) ),
attach_popup=True, filterable=True ),
attach_popup=True, filterable="advanced" ),
DatasetsByStateColumn( "Datasets (by state)", ncells=4 ),
TagsColumn( "Tags", key="tags", filterable=True),
grids.TagsColumn( "Tags", "tags", model.History, model.HistoryTagAssociation, filterable="advanced"),
StatusColumn( "Status", attach_popup=False ),
grids.GridColumn( "Created", key="create_time", format=time_ago ),
grids.GridColumn( "Last Updated", key="update_time", format=time_ago ),
# Columns that are valid for filtering but are not visible.
DeletedColumn( "Deleted", key="deleted", visible=False, filterable=True ),
SharingColumn( "Shared", key="shared", visible=False, filterable=True ),
FreeTextSearchColumn( "Search", key="free-text-search", visible=False ) # Not filterable because it's the default search.
DeletedColumn( "Deleted", key="deleted", visible=False, filterable="advanced" ),
SharingColumn( "Shared", key="shared", visible=False, filterable="advanced" ),
]
columns.append(
grids.MulticolFilterColumn(
"Search",
cols_to_filter=[ columns[0], columns[2] ],
key="free-text-search", visible=False, filterable="default" )
)
operations = [
grids.GridOperation( "Switch", allow_multiple=False, condition=( lambda item: not item.deleted ) ),
grids.GridOperation( "Share", condition=( lambda item: not item.deleted ) ),
@@ -464,7 +375,7 @@ class HistoryController( BaseController ):
return
ac_data = ""
for history in trans.sa_session.query( History ).filter_by( user=user ).filter( func.lower( History.name ) .like(q.lower() + "%") ):
for history in trans.sa_session.query( model.History ).filter_by( user=user ).filter( func.lower( model.History.name ) .like(q.lower() + "%") ):
ac_data = ac_data + history.name + "\n"
return ac_data
+2 -2
View File
@@ -105,7 +105,7 @@ class TagsController ( BaseController ):
# Build select statement.
cols_to_select = [ item_tag_assoc_class.table.c.tag_id, func.count('*') ]
from_obj = item_tag_assoc_class.table.join(item_class.table).join(Tag)
from_obj = item_tag_assoc_class.table.join(item_class.table).join(Tag.table)
where_clause = and_(self._get_column_for_filtering_item_by_user_id(item_class)==trans.get_user().id,
Tag.table.c.name.like(q + "%"))
order_by = [ func.count("*").desc() ]
@@ -154,7 +154,7 @@ class TagsController ( BaseController ):
# Build select statement.
cols_to_select = [ item_tag_assoc_class.table.c.value, func.count('*') ]
from_obj = item_tag_assoc_class.table.join(item_class.table).join(Tag)
from_obj = item_tag_assoc_class.table.join(item_class.table).join(Tag.table)
where_clause = and_(self._get_column_for_filtering_item_by_user_id(item_class)==trans.get_user().id,
Tag.table.c.id==tag.id,
item_tag_assoc_class.table.c.value.like(tag_value + "%"))
+125 -6
View File
@@ -1,6 +1,7 @@
from galaxy.model import *
from galaxy.model.orm import *
from galaxy.tags.tag_handler import TagHandler
from galaxy.web import url_for
from galaxy.util.json import from_json_string, to_json_string
@@ -87,18 +88,51 @@ class Grid( object ):
column_filter = kwargs.get( "f-" + column.key )
elif column.key in base_filter:
column_filter = base_filter.get( column.key )
# Method (1) combines a mix of strings and lists of strings into a single string and (2) attempts to de-jsonify all strings.
def from_json_string_recurse(item):
decoded_list = []
if isinstance( item, basestring):
try:
# Not clear what we're decoding, so recurse to ensure that we catch everything.
decoded_item = from_json_string( item )
if isinstance( decoded_item, list):
decoded_list = from_json_string_recurse( decoded_item )
else:
decoded_list = [ str( decoded_item ) ]
except ValueError:
decoded_list = [ str( item ) ]
elif isinstance( item, list):
return_val = []
for element in item:
a_list = from_json_string_recurse( element )
decoded_list = decoded_list + a_list
return decoded_list
# If column filter found, apply it.
if column_filter is not None:
# TextColumns may have a mix of json and strings.
if isinstance( column, TextColumn ):
column_filter = from_json_string_recurse( column_filter )
if len( column_filter ) == 1:
column_filter = column_filter[0]
# Update query.
query = column.filter( trans.sa_session, query, column_filter )
# Upate current filter dict.
cur_filter_dict[ column.key ] = column_filter
# Carry filter along to newly generated urls; make sure filter is a string so
# Carry filter along to newly generated urls; make sure filter is a string so
# that we can encode to UTF-8 and thus handle user input to filters.
if not isinstance( column_filter, basestring ):
column_filter = unicode(column_filter)
extra_url_args[ "f-" + column.key ] = column_filter.encode("utf-8")
if isinstance( column_filter, list ):
# Filter is a list; process each item.
for filter in column_filter:
if not isinstance( filter, basestring ):
filter = unicode( filter ).encode("utf-8")
extra_url_args[ "f-" + column.key ] = to_json_string( column_filter )
else:
# Process singleton filter.
if not isinstance( column_filter, basestring ):
column_filter = unicode(column_filter)
extra_url_args[ "f-" + column.key ] = column_filter.encode("utf-8")
# Process sort arguments.
sort_key = sort_order = None
@@ -218,9 +252,12 @@ class Grid( object ):
return query
class GridColumn( object ):
def __init__( self, label, key=None, method=None, format=None, link=None, attach_popup=False, visible=True, ncells=1, filterable=False ):
def __init__( self, label, key=None, model_class=None, method=None, format=None, link=None, attach_popup=False, visible=True, ncells=1,
# Valid values for filterable are ['default', 'advanced', None]
filterable=None ):
self.label = label
self.key = key
self.model_class = model_class
self.method = method
self.format = format
self.link = link
@@ -265,6 +302,88 @@ class GridColumn( object ):
args = { self.key: val }
accepted_filters.append( GridColumnFilter( val, args) )
return accepted_filters
# Generic column that employs freetext and, hence, supports freetext, case-independent filtering.
class TextColumn( GridColumn ):
def filter( self, db_session, query, column_filter ):
""" Modify query to filter using free text, case independence. """
if column_filter == "All":
pass
elif column_filter:
query = query.filter( self.get_filter( column_filter ) )
return query
def get_filter( self, column_filter ):
""" Returns a SQLAlchemy criterion derived from column_filter. """
# This is a pretty ugly way to get the key attribute of model_class. TODO: Can this be fixed?
model_class_key_field = eval( "self.model_class." + self.key )
if isinstance( column_filter, basestring ):
return func.lower( model_class_key_field ).like( "%" + column_filter.lower() + "%" )
elif isinstance( column_filter, list ):
composite_filter = True
for filter in column_filter:
composite_filter = and_( composite_filter, func.lower( model_class_key_field ).like( "%" + filter.lower() + "%" ) )
return composite_filter
# Generic column that supports tagging.
class TagsColumn( TextColumn ):
def __init__( self, col_name, key, model_class, model_tag_association_class, filterable ):
GridColumn.__init__(self, col_name, key=key, model_class=model_class, filterable=filterable)
self.model_tag_association_class = model_tag_association_class
# Tags cannot be sorted.
self.sortable = False
self.tag_elt_id_gen = 0
def get_value( self, trans, grid, item ):
self.tag_elt_id_gen += 1
elt_id="tagging-elt" + str( self.tag_elt_id_gen )
div_elt = "<div id=%s></div>" % elt_id
return div_elt + trans.fill_template( "/tagging_common.mako", trans=trans, tagged_item=item,
elt_id = elt_id, in_form="true", input_size="20", tag_click_fn="add_tag_to_grid_filter" )
def filter( self, db_session, query, column_filter ):
""" Modify query to filter model_class by tag. Multiple filters are ANDed. """
if column_filter == "All":
pass
elif column_filter:
query = query.filter( self.get_filter( column_filter ) )
return query
def get_filter( self, column_filter ):
# Parse filter to extract multiple tags.
tag_handler = TagHandler()
if isinstance( column_filter, list ):
# Collapse list of tags into a single string; this is redundant but effective. TODO: fix this by iterating over tags.
column_filter = ",".join( column_filter )
raw_tags = tag_handler.parse_tags( column_filter.encode("utf-8") )
filter = True
for name, value in raw_tags.items():
if name:
# Search for tag names.
filter = and_( filter, self.model_class.tags.any( func.lower( self.model_tag_association_class.user_tname ).like( "%" + name.lower() + "%" ) ) )
if value:
# Search for tag values.
filter = and_( filter, self.model_class.tags.any( func.lower( self.model_tag_association_class.user_value ).like( "%" + value.lower() + "%" ) ) )
return filter
# Column that performs multicolumn filtering.
class MulticolFilterColumn( TextColumn ):
def __init__( self, col_name, cols_to_filter, key, visible, filterable="default" ):
GridColumn.__init__( self, col_name, key=key, visible=visible, filterable=filterable)
self.cols_to_filter = cols_to_filter
def filter( self, db_session, query, column_filter ):
""" Modify query to filter model_class by tag. Multiple filters are ANDed. """
if column_filter == "All":
return query
if isinstance( column_filter, list):
composite_filter = True
for filter in column_filter:
part_composite_filter = False
for column in self.cols_to_filter:
part_composite_filter = or_( part_composite_filter, column.get_filter( filter ) )
composite_filter = and_( composite_filter, part_composite_filter )
else:
composite_filter = False
for column in self.cols_to_filter:
composite_filter = or_( composite_filter, column.get_filter( column_filter ) )
return query.filter( composite_filter )
class GridOperation( object ):
def __init__( self, label, key=None, condition=None, allow_multiple=True, allow_popup=True, target=None, url_args=None ):
+89 -3
View File
@@ -295,6 +295,66 @@ jQuery.extend(WYMeditor, {
});
/*
Galaxy code that integrates into the WYM Editor.
*/
var Galaxy =
{
/*
Galaxy constants for WYM Editor:
TOOLS - A string replaced by the galaxy toolbar's HTML.
TOOLS_ITEMS - A string replaced by the galaxy toolbar items.
INSERT_HISTORY - Command: open the insert history dialog.
INSERT_DATASET - Command: open the insert dataset dialog.
DIALOG_HISTORY - A dialog to insert a history.
DIALOG_DATASET - A dialog to insert a dataset.
*/
TOOLS : "{Galaxy_Tools}",
TOOLS_ITEMS : "{Galaxy_Tools_Items}",
INSERT_HISTORY : "InsertHistory",
INSERT_DATASET : "InsertDataset",
DIALOG_HISTORY : "DialogHistory",
DIALOG_DATASET : "DialogDataset",
// Tool items overview.
toolsItems: [
{'name': "InsertHistory", 'title': 'History', 'css': 'galaxy_tools_insert_history_link'},
{'name': "InsertDataset", 'title': 'Dataset', 'css': 'galaxy_dataset'}
],
// Tools HTML.
toolsHtml: "<div class='wym_tools wym_section'>"
+ "<h2>" + this.TOOLS + "</h2>"
+ "<ul>"
+ this.TOOLS_ITEMS
+ "</ul>"
+ "</div>",
// Insert history dialog.
dialogHistoryHtml: "<body class='wym_dialog wym_dialog_history'"
+ " onload='WYMeditor.INIT_DIALOG(" + WYMeditor.INDEX + ")'"
+ ">"
+ "<form>"
+ "<fieldset>"
+ "<input type='hidden' class='wym_dialog_type' value='"
+ this.DIALOG_HISTORY
+ "' />"
+ "<legend>{Link}</legend>"
+ "<div class='row'>"
+ "<label>{Title}</label>"
+ "<input type='text' class='wym_title' value='' size='40' />"
+ "</div>"
+ "<div class='row row-indent'>"
+ "<input class='wym_submit' type='button'"
+ " value='{Add}' />"
+ "<input class='wym_cancel' type='button'"
+ "value='{Cancel}' />"
+ "</div>"
+ "</fieldset>"
+ "</form>"
+ "</body>",
};
/********** JQUERY **********/
@@ -354,6 +414,7 @@ jQuery.fn.wymeditor = function(options) {
+ "<div class='wym_area_right'>"
+ WYMeditor.CONTAINERS
+ WYMeditor.CLASSES
+ Galaxy.TOOLS
+ "</div>"
+ "<div class='wym_area_main'>"
+ WYMeditor.HTML
@@ -384,6 +445,8 @@ jQuery.fn.wymeditor = function(options) {
+ "<h2>{Tools}</h2>"
+ "<ul>"
+ WYMeditor.TOOLS_ITEMS
// Add Galaxy Tools.
+ Galaxy.TOOLS_ITEMS
+ "</ul>"
+ "</div>",
@@ -758,6 +821,7 @@ WYMeditor.editor.prototype.init = function() {
boxHtml = h.replaceAll(boxHtml, WYMeditor.LOGO, this._options.logoHtml);
boxHtml = h.replaceAll(boxHtml, WYMeditor.TOOLS, this._options.toolsHtml);
boxHtml = h.replaceAll(boxHtml, Galaxy.TOOLS, Galaxy.toolsHtml);
boxHtml = h.replaceAll(boxHtml, WYMeditor.CONTAINERS,this._options.containersHtml);
boxHtml = h.replaceAll(boxHtml, WYMeditor.CLASSES, this._options.classesHtml);
boxHtml = h.replaceAll(boxHtml, WYMeditor.HTML, this._options.htmlHtml);
@@ -781,6 +845,24 @@ WYMeditor.editor.prototype.init = function() {
}
boxHtml = h.replaceAll(boxHtml, WYMeditor.TOOLS_ITEMS, sTools);
// Construct Galaxy tools list.
var galaxyTools = eval(Galaxy.toolsItems);
sTools = "";
for(var i = 0; i < galaxyTools.length; i++) {
var galaxyTool = galaxyTools[i];
if(galaxyTool.name && galaxyTool.title) {
var sTool = this._options.toolsItemHtml;
var sTool = h.replaceAll(sTool, WYMeditor.TOOL_NAME, galaxyTool.name);
sTool = h.replaceAll(sTool, WYMeditor.TOOL_TITLE, this._options.stringDelimiterLeft
+ galaxyTool.title
+ this._options.stringDelimiterRight);
sTool = h.replaceAll(sTool, WYMeditor.TOOL_CLASS, galaxyTool.css);
sTools += sTool;
}
}
boxHtml = h.replaceAll(boxHtml, Galaxy.TOOLS_ITEMS, sTools);
//construct classes list
var aClasses = eval(this._options.classesItems);
@@ -947,6 +1029,10 @@ WYMeditor.editor.prototype.exec = function(cmd) {
this.dialog(WYMeditor.PREVIEW, this._options.dialogFeaturesPreview);
break;
case Galaxy.INSERT_HISTORY:
this.dialog(Galaxy.DIALOG_HISTORY);
break;
default:
this._exec(cmd);
break;
@@ -1153,7 +1239,6 @@ WYMeditor.editor.prototype.update = function() {
* @description Opens a dialog box
*/
WYMeditor.editor.prototype.dialog = function( dialogType, dialogFeatures, bodyHtml ) {
var features = dialogFeatures || this._wym._options.dialogFeatures;
var wDialog = window.open('', 'dialog', features);
@@ -1178,11 +1263,13 @@ WYMeditor.editor.prototype.dialog = function( dialogType, dialogFeatures, bodyHt
case(WYMeditor.PREVIEW):
sBodyHtml = this._options.dialogPreviewHtml;
break;
case(Galaxy.DIALOG_HISTORY):
sBodyHtml = Galaxy.dialogHistoryHtml;
break;
default:
sBodyHtml = bodyHtml;
}
var h = WYMeditor.Helper;
//construct the dialog
@@ -1197,7 +1284,6 @@ WYMeditor.editor.prototype.dialog = function( dialogType, dialogFeatures, bodyHt
dialogHtml = h.replaceAll(dialogHtml, WYMeditor.INDEX, this._index);
dialogHtml = this.replaceStrings(dialogHtml);
var doc = wDialog.document;
doc.write(dialogHtml);
doc.close();
+5 -1
View File
@@ -40,6 +40,10 @@ WYMeditor.STRINGS['en'] = {
Containers: 'Containers',
Classes: 'Classes',
Status: 'Status',
Source_Code: 'Source code'
Source_Code: 'Source code',
// Galaxy replacements.
History: 'History',
Dataset: 'Dataset',
};
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

+1
View File
@@ -109,6 +109,7 @@
.wym_skin_galaxy .wym_buttons li.wym_tools_paste a { background-position: 0 -552px;}
.wym_skin_galaxy .wym_buttons li.wym_tools_html a { background-position: 0 -193px;}
.wym_skin_galaxy .wym_buttons li.wym_tools_preview a { background-position: 0 -408px;}
.wym_skin_galaxy .wym_buttons li.galaxy_tools_insert_history_link a { background-position: 0 -622px;}
/*DECORATION*/
.wym_skin_galaxy .wym_section h2 { background: #f0f0f0; border: solid gray; border-width: 0 0 1px;}
+5 -36
View File
@@ -167,43 +167,12 @@
</style>
</%def>
<div class="grid-header">
<h2>${grid.title}</h2>
<%namespace file="../grid_common.mako" import="*" />
## Print grid filter.
<form name="dataset_actions" action="javascript:add_tag_to_grid_filter($('#input-tag-filter').attr('value'))" method="get" >
<strong>Filter:&nbsp;&nbsp;&nbsp;</strong>
%for column in grid.columns:
%if column.filterable:
<span> by ${column.label.lower()}:</span>
## For now, include special case to handle tags.
%if column.key == "tags":
%if cur_filter_dict[column.key] != "All":
<span class="filter" "style='font-style: italic'">
${cur_filter_dict[column.key]}
</span>
<span>|</span>
%endif
<input id="input-tag-filter" name="f-tags" type="text" value="" size="15"/>
<span>|</span>
%endif
## Handle other columns.
%for i, filter in enumerate( column.get_accepted_filters() ):
%if i > 0:
<span>|</span>
%endif
%if cur_filter_dict[column.key] == filter.args[column.key]:
<span class="filter" "style='font-style: italic'">${filter.label}</span>
%else:
<span class="filter"><a href="${url( filter.get_url_args() )}">${filter.label}</a></span>
%endif
%endfor
<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
%endif
%endfor
</form>
</div>
## Print grid header.
${render_grid_filters()}
## Print grid.
<form name="dataset_actions" action="${url()}" method="post" >
<table class="grid">
<thead>
+129
View File
@@ -0,0 +1,129 @@
<%! from galaxy.web.framework.helpers.grids import TextColumn, GridColumnFilter %>
## Render a filter UI for a grid column. Filter is rendered as a table row.
<%def name="render_grid_column_filter(column)">
<tr>
<%
column_label = column.label
if column.filterable == "advanced":
column_label = column_label.lower()
%>
<td align="left" style="padding-left: 10px">${column_label}:</td>
<td>
%if isinstance(column, TextColumn):
<form name="history_actions" action="${url( dict() )}"
method="get" >
## Carry forward filtering criteria with hidden inputs.
%for temp_column in grid.columns:
%if temp_column.key in cur_filter_dict:
<% value = cur_filter_dict[ temp_column.key ] %>
%if value != "All":
<%
if isinstance( temp_column, TextColumn ):
value = h.to_json_string( value )
%>
<input type="hidden" id="${temp_column.key}" name="f-${temp_column.key}" value='${value}'/>
%endif
%endif
%endfor
## Print current filtering criteria and links to delete.
%if column.key in cur_filter_dict:
<% column_filter = cur_filter_dict[column.key] %>
%if isinstance( column_filter, basestring ):
%if column_filter != "All":
<span style="font-style: italic">${cur_filter_dict[column.key]}</span>
<% filter_all = GridColumnFilter( "", { column.key : "All" } ) %>
<a href="${url( filter_all.get_url_args() )}"><img src="${h.url_for('/static/images/delete_tag_icon_gray.png')}"/></a>
|
%endif
%elif isinstance( column_filter, list ):
%for i, filter in enumerate( column_filter ):
%if i > 0:
,
%endif
<span style="font-style: italic">${filter}</span>
<%
new_filter = list( column_filter )
del new_filter[ i ]
new_column_filter = GridColumnFilter( "", { column.key : h.to_json_string( new_filter ) } )
%>
<a href="${url( new_column_filter.get_url_args() )}"><img src="${h.url_for('/static/images/delete_tag_icon_gray.png')}"/></a>
%endfor
%endif
%endif
<span><input id="input-${column.key}-filter" name="f-${column.key}" type="text" value="" size="15"/></span>
</form>
%else:
%for i, filter in enumerate( column.get_accepted_filters() ):
%if i > 0:
<span>|</span>
%endif
%if cur_filter_dict[column.key] == filter.args[column.key]:
<span class="filter" style="font-style: italic">${filter.label}</span>
%else:
<span class="filter"><a href="${url( filter.get_url_args() )}">${filter.label}</a></span>
%endif
%endfor
%endif
</td>
</tr>
</%def>
## Print grid search/filtering UI.
<%def name="render_grid_filters()">
<div class="grid-header">
<h2>${grid.title}</h2>
## Default search.
<div>
<table><tr>
<td>
<table>
%for column in grid.columns:
%if column.filterable == "default":
${render_grid_column_filter(column)}
%endif
%endfor
</table>
</td>
<td>
##|
##<% filter_all = GridColumnFilter( "", { column.key : "All" } ) %>
##<a href="${url( filter_all.get_url_args() )}">Clear All</a>
| <a href="" onclick="javascript:$('#more-search-options').slideToggle('fast');return false;">Advanced Search</a>
</td>
</tr></table>
</div>
## Advanced search.
<div id="more-search-options" style="display: none; padding-top: 5px">
<table style="border: 1px solid gray;">
<tr><td style="text-align: left" colspan="100">
Advanced Search |
<a href=""# onclick="javascript:$('#more-search-options').slideToggle('fast');return false;">Close</a> |
## Link to clear all filters.
<%
no_filter = GridColumnFilter("Clear All", default_filter_dict)
%>
<a href="${url( no_filter.get_url_args() )}">${no_filter.label}</a>
</td></tr>
%for column in grid.columns:
%if column.filterable == "advanced":
## Show div if current filter has value that is different from the default filter.
%if column.key in cur_filter_dict and column.key in default_filter_dict and \
cur_filter_dict[column.key] != default_filter_dict[column.key]:
<script type="text/javascript">
$('#more-search-options').css("display", "block");
</script>
%endif
${render_grid_column_filter(column)}
%endif
%endfor
</table>
</div>
</div>
</%def>
+7 -93
View File
@@ -1,4 +1,4 @@
<%! from galaxy.web.framework.helpers.grids import GridColumnFilter %>
<%! from galaxy.web.framework.helpers.grids import TextColumn, GridColumnFilter %>
<%inherit file="/base.mako"/>
<%def name="title()">${grid.title}</%def>
@@ -153,98 +153,12 @@
</style>
</%def>
<div class="grid-header">
<h2>${grid.title}</h2>
## Search box and more options filter at top of grid.
<div>
## Grid search. TODO: use more elegant way to get free text search column.
<% column = grid.columns[-1] %>
<% use_form = False %>
%for i, filter in enumerate( column.get_accepted_filters() ):
%if i > 0:
<span>|</span>
%endif
%if column.key in cur_filter_dict and cur_filter_dict[column.key] == filter.args[column.key]:
<span class="filter" "style='font-style: italic'">${filter.label}</span>
%elif filter.label == "FREETEXT":
<form name="history_actions"
action="javascript:add_condition_to_grid_filter($('#input-${column.key}-filter').attr('name'),$('#input-${column.key}-filter').attr('value'),false)"
method="get" >
${column.label}:
%if column.key in cur_filter_dict and cur_filter_dict[column.key] != "All":
<span style="font-style: italic">${cur_filter_dict[column.key]}</span>
<% filter_all = GridColumnFilter( "", { column.key : "All" } ) %>
<a href="${url( filter_all.get_url_args() )}"><img src="${h.url_for('/static/images/delete_tag_icon_gray.png')}"/></a>
|
%endif
<span><input id="input-${column.key}-filter" name="${column.key}" type="text" value="" size="15"/></span>
<% use_form = True %>
%else:
<span class="filter"><a href="${url( filter.get_url_args() )}">${filter.label}</a></span>
%endif
%endfor
| <a href="" onclick="javascript:$('#more-search-options').slideToggle('fast');return false;">Advanced Search</a>
%if use_form:
</form>
%endif
</div>
## Advanced Search
<div id="more-search-options" style="display: none; padding-top: 5px">
<table style="border: 1px solid gray;">
<tr><td style="text-align: left" colspan="100">
Advanced Search |
<a href=""# onclick="javascript:$('#more-search-options').slideToggle('fast');return false;">Close</a> |
## Link to clear all filters.
<%
no_filter = GridColumnFilter("Clear All", default_filter_dict)
%>
<a href="${url( no_filter.get_url_args() )}">${no_filter.label}</a>
</td></tr>
%for column in grid.columns:
%if column.filterable:
<tr>
## Show div if current filter has value that is different from the default filter.
%if cur_filter_dict[column.key] != default_filter_dict[column.key]:
<script type="text/javascript">
$('#more-search-options').css("display", "block");
</script>
%endif
<td style="padding-left: 10px">${column.label.lower()}:</td>
<td>
<% use_form = False %>
%for i, filter in enumerate( column.get_accepted_filters() ):
%if i > 0:
<span>|</span>
%endif
%if cur_filter_dict[column.key] == filter.args[column.key]:
<span class="filter" style="font-style: italic">${filter.label}</span>
%elif filter.label == "FREETEXT":
<form name="history_actions" action="javascript:add_condition_to_grid_filter($('#input-${column.key}-filter').attr('name'),$('#input-${column.key}-filter').attr('value'),true)"
method="get" >
%if column.key in cur_filter_dict and cur_filter_dict[column.key] != "All":
<span style="font-style: italic">${cur_filter_dict[column.key]}</span>
<% filter_all = GridColumnFilter( "", { column.key : "All" } ) %>
<a href="${url( filter_all.get_url_args() )}"><img src="${h.url_for('/static/images/delete_tag_icon_gray.png')}"/></a>
|
%endif
<span><input id="input-${column.key}-filter" name="${column.key}" type="text" value="" size="15"/></span>
<% use_form = True %>
%else:
<span class="filter"><a href="${url( filter.get_url_args() )}">${filter.label}</a></span>
%endif
%endfor
%if use_form:
</form>
%endif
</td>
</tr>
%endif
%endfor
</table>
</div>
</div>
<%namespace file="../grid_common.mako" import="*" />
## Print grid header.
${render_grid_filters()}
## Print grid.
<form name="history_actions" action="${url()}" method="post" >
<input type="hidden" name="page" value="${cur_page_num}">
<table class="grid">