[hg] galaxy 2980: Refactored grid code to (a) generalize numerou...
details: http://www.bx.psu.edu/hg/galaxy/rev/f520e80ac09c changeset: 2980:f520e80ac09c user: jeremy goecks <jeremy.goecks@emory.edu> date: Fri Nov 06 19:04:13 2009 -0500 description: 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. diffstat: lib/galaxy/model/__init__.py | 2 +- lib/galaxy/web/controllers/dataset.py | 63 ++------------- lib/galaxy/web/controllers/history.py | 129 +++++--------------------------- lib/galaxy/web/controllers/tag.py | 4 +- lib/galaxy/web/framework/helpers/grids.py | 131 +++++++++++++++++++++++++++++++- static/scripts/jquery.wymeditor.js | 92 ++++++++++++++++++++++- static/wymeditor/lang/en.js | 6 +- static/wymeditor/skins/galaxy/icons.png | static/wymeditor/skins/galaxy/skin.css | 1 + templates/dataset/grid.mako | 41 +--------- templates/grid_common.mako | 129 ++++++++++++++++++++++++++++++++ templates/history/grid.mako | 100 +----------------------- 12 files changed, 394 insertions(+), 304 deletions(-) diffs (990 lines): diff -r b54c37f53d53 -r f520e80ac09c lib/galaxy/model/__init__.py --- a/lib/galaxy/model/__init__.py Fri Nov 06 16:52:00 2009 -0500 +++ b/lib/galaxy/model/__init__.py Fri Nov 06 19:04:13 2009 -0500 @@ -246,7 +246,7 @@ # 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') diff -r b54c37f53d53 -r f520e80ac09c lib/galaxy/web/controllers/dataset.py --- a/lib/galaxy/web/controllers/dataset.py Fri Nov 06 16:52:00 2009 -0500 +++ b/lib/galaxy/web/controllers/dataset.py Fri Nov 06 19:04:13 2009 -0500 @@ -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 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 @@ 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 diff -r b54c37f53d53 -r f520e80ac09c lib/galaxy/web/controllers/history.py --- a/lib/galaxy/web/controllers/history.py Fri Nov 06 16:52:00 2009 -0500 +++ b/lib/galaxy/web/controllers/history.py Fri Nov 06 19:04:13 2009 -0500 @@ -2,7 +2,6 @@ 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 @@ 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 @@ else: rval.append( '' ) return rval + class StatusColumn( grids.GridColumn ): def get_value( self, trans, grid, history ): if history.deleted: @@ -66,44 +46,6 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 diff -r b54c37f53d53 -r f520e80ac09c lib/galaxy/web/controllers/tag.py --- a/lib/galaxy/web/controllers/tag.py Fri Nov 06 16:52:00 2009 -0500 +++ b/lib/galaxy/web/controllers/tag.py Fri Nov 06 19:04:13 2009 -0500 @@ -105,7 +105,7 @@ # 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 @@ # 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 + "%")) diff -r b54c37f53d53 -r f520e80ac09c lib/galaxy/web/framework/helpers/grids.py --- a/lib/galaxy/web/framework/helpers/grids.py Fri Nov 06 16:52:00 2009 -0500 +++ b/lib/galaxy/web/framework/helpers/grids.py Fri Nov 06 19:04:13 2009 -0500 @@ -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 @@ 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 @@ 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 @@ 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 ): diff -r b54c37f53d53 -r f520e80ac09c static/scripts/jquery.wymeditor.js --- a/static/scripts/jquery.wymeditor.js Fri Nov 06 16:52:00 2009 -0500 +++ b/static/scripts/jquery.wymeditor.js Fri Nov 06 19:04:13 2009 -0500 @@ -295,6 +295,66 @@ }); +/* + 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 @@ + "<div class='wym_area_right'>" + WYMeditor.CONTAINERS + WYMeditor.CLASSES + + Galaxy.TOOLS + "</div>" + "<div class='wym_area_main'>" + WYMeditor.HTML @@ -384,6 +445,8 @@ + "<h2>{Tools}</h2>" + "<ul>" + WYMeditor.TOOLS_ITEMS + // Add Galaxy Tools. + + Galaxy.TOOLS_ITEMS + "</ul>" + "</div>", @@ -758,6 +821,7 @@ 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 @@ } 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 @@ 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 @@ * @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 @@ 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 @@ dialogHtml = h.replaceAll(dialogHtml, WYMeditor.INDEX, this._index); dialogHtml = this.replaceStrings(dialogHtml); - var doc = wDialog.document; doc.write(dialogHtml); doc.close(); diff -r b54c37f53d53 -r f520e80ac09c static/wymeditor/lang/en.js --- a/static/wymeditor/lang/en.js Fri Nov 06 16:52:00 2009 -0500 +++ b/static/wymeditor/lang/en.js Fri Nov 06 19:04:13 2009 -0500 @@ -40,6 +40,10 @@ Containers: 'Containers', Classes: 'Classes', Status: 'Status', - Source_Code: 'Source code' + Source_Code: 'Source code', + + // Galaxy replacements. + History: 'History', + Dataset: 'Dataset', }; diff -r b54c37f53d53 -r f520e80ac09c static/wymeditor/skins/galaxy/icons.png Binary file static/wymeditor/skins/galaxy/icons.png has changed diff -r b54c37f53d53 -r f520e80ac09c static/wymeditor/skins/galaxy/skin.css --- a/static/wymeditor/skins/galaxy/skin.css Fri Nov 06 16:52:00 2009 -0500 +++ b/static/wymeditor/skins/galaxy/skin.css Fri Nov 06 19:04:13 2009 -0500 @@ -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;} diff -r b54c37f53d53 -r f520e80ac09c templates/dataset/grid.mako --- a/templates/dataset/grid.mako Fri Nov 06 16:52:00 2009 -0500 +++ b/templates/dataset/grid.mako Fri Nov 06 19:04:13 2009 -0500 @@ -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: </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> </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> diff -r b54c37f53d53 -r f520e80ac09c templates/grid_common.mako --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/grid_common.mako Fri Nov 06 19:04:13 2009 -0500 @@ -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> \ No newline at end of file diff -r b54c37f53d53 -r f520e80ac09c templates/history/grid.mako --- a/templates/history/grid.mako Fri Nov 06 16:52:00 2009 -0500 +++ b/templates/history/grid.mako Fri Nov 06 19:04:13 2009 -0500 @@ -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">
participants (1)
-
Greg Von Kuster