diff --git a/lib/galaxy/model/__init__.py b/lib/galaxy/model/__init__.py index 013a16484d4..fc60017c299 100644 --- a/lib/galaxy/model/__init__.py +++ b/lib/galaxy/model/__init__.py @@ -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') diff --git a/lib/galaxy/web/controllers/dataset.py b/lib/galaxy/web/controllers/dataset.py index a472ba8e969..49276fc4fdd 100644 --- a/lib/galaxy/web/controllers/dataset.py +++ b/lib/galaxy/web/controllers/dataset.py @@ -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 = "
" % 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 diff --git a/lib/galaxy/web/controllers/history.py b/lib/galaxy/web/controllers/history.py index a4f4e944bcb..b3cd3cdc8eb 100644 --- a/lib/galaxy/web/controllers/history.py +++ b/lib/galaxy/web/controllers/history.py @@ -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 = "
" % 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 diff --git a/lib/galaxy/web/controllers/tag.py b/lib/galaxy/web/controllers/tag.py index 164e2ffdca0..f8cd6df499f 100644 --- a/lib/galaxy/web/controllers/tag.py +++ b/lib/galaxy/web/controllers/tag.py @@ -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 + "%")) diff --git a/lib/galaxy/web/framework/helpers/grids.py b/lib/galaxy/web/framework/helpers/grids.py index 39f47286958..d8503ce7945 100644 --- a/lib/galaxy/web/framework/helpers/grids.py +++ b/lib/galaxy/web/framework/helpers/grids.py @@ -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 = "
" % 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 --git a/static/scripts/jquery.wymeditor.js b/static/scripts/jquery.wymeditor.js index b13e2d02f66..34c42342cf0 100644 --- a/static/scripts/jquery.wymeditor.js +++ b/static/scripts/jquery.wymeditor.js @@ -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: "
" + + "

" + this.TOOLS + "

" + + "" + + "
", + + // Insert history dialog. + dialogHistoryHtml: "" + + "
" + + "
" + + "" + + "{Link}" + + "
" + + "" + + "" + + "
" + + "
" + + "" + + "" + + "
" + + "
" + + "
" + + "", +}; + /********** JQUERY **********/ @@ -354,6 +414,7 @@ jQuery.fn.wymeditor = function(options) { + "
" + WYMeditor.CONTAINERS + WYMeditor.CLASSES + + Galaxy.TOOLS + "
" + "
" + WYMeditor.HTML @@ -384,6 +445,8 @@ jQuery.fn.wymeditor = function(options) { + "

{Tools}

" + "" + "
", @@ -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(); diff --git a/static/wymeditor/lang/en.js b/static/wymeditor/lang/en.js index 1e351e55509..d878e38d3e9 100644 --- a/static/wymeditor/lang/en.js +++ b/static/wymeditor/lang/en.js @@ -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', }; diff --git a/static/wymeditor/skins/galaxy/icons.png b/static/wymeditor/skins/galaxy/icons.png index c6eb463f117..a9cae0d9d02 100644 Binary files a/static/wymeditor/skins/galaxy/icons.png and b/static/wymeditor/skins/galaxy/icons.png differ diff --git a/static/wymeditor/skins/galaxy/skin.css b/static/wymeditor/skins/galaxy/skin.css index 041334749f1..95bbe0a3db1 100644 --- a/static/wymeditor/skins/galaxy/skin.css +++ b/static/wymeditor/skins/galaxy/skin.css @@ -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 --git a/templates/dataset/grid.mako b/templates/dataset/grid.mako index 0fa0e4aec14..70ca26178d3 100644 --- a/templates/dataset/grid.mako +++ b/templates/dataset/grid.mako @@ -167,43 +167,12 @@ -
-

${grid.title}

+<%namespace file="../grid_common.mako" import="*" /> - ## Print grid filter. -
- Filter:    - %for column in grid.columns: - %if column.filterable: - by ${column.label.lower()}: - ## For now, include special case to handle tags. - %if column.key == "tags": - %if cur_filter_dict[column.key] != "All": - - ${cur_filter_dict[column.key]} - - | - %endif - - | - %endif - - ## Handle other columns. - %for i, filter in enumerate( column.get_accepted_filters() ): - %if i > 0: - | - %endif - %if cur_filter_dict[column.key] == filter.args[column.key]: - ${filter.label} - %else: - ${filter.label} - %endif - %endfor -       - %endif - %endfor -
-
+## Print grid header. +${render_grid_filters()} + +## Print grid.
diff --git a/templates/grid_common.mako b/templates/grid_common.mako new file mode 100644 index 00000000000..78a32c3600c --- /dev/null +++ b/templates/grid_common.mako @@ -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)"> + + <% + column_label = column.label + if column.filterable == "advanced": + column_label = column_label.lower() + %> + + + + + +## Print grid search/filtering UI. +<%def name="render_grid_filters()"> +
+

${grid.title}

+ + ## Default search. +
+
${column_label}: + %if isinstance(column, TextColumn): + + ## 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 ) + %> + + %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": + ${cur_filter_dict[column.key]} + <% filter_all = GridColumnFilter( "", { column.key : "All" } ) %> + + | + %endif + %elif isinstance( column_filter, list ): + %for i, filter in enumerate( column_filter ): + %if i > 0: + , + %endif + ${filter} + <% + new_filter = list( column_filter ) + del new_filter[ i ] + new_column_filter = GridColumnFilter( "", { column.key : h.to_json_string( new_filter ) } ) + %> + + %endfor + + %endif + %endif + + + %else: + %for i, filter in enumerate( column.get_accepted_filters() ): + %if i > 0: + | + %endif + %if cur_filter_dict[column.key] == filter.args[column.key]: + ${filter.label} + %else: + ${filter.label} + %endif + %endfor + %endif +
+ + +
+ + %for column in grid.columns: + %if column.filterable == "default": + ${render_grid_column_filter(column)} + %endif + %endfor +
+
+ ##| + ##<% filter_all = GridColumnFilter( "", { column.key : "All" } ) %> + ##Clear All + | Advanced Search +
+ + + + ## Advanced search. + + + \ No newline at end of file diff --git a/templates/history/grid.mako b/templates/history/grid.mako index 97d8f65bbbf..ecb321e90a7 100644 --- a/templates/history/grid.mako +++ b/templates/history/grid.mako @@ -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} @@ -153,98 +153,12 @@ -
-

${grid.title}

- - ## Search box and more options filter at top of grid. -
- ## 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: - | - %endif - %if column.key in cur_filter_dict and cur_filter_dict[column.key] == filter.args[column.key]: - ${filter.label} - %elif filter.label == "FREETEXT": -
- ${column.label}: - %if column.key in cur_filter_dict and cur_filter_dict[column.key] != "All": - ${cur_filter_dict[column.key]} - <% filter_all = GridColumnFilter( "", { column.key : "All" } ) %> - - | - %endif - - <% use_form = True %> - %else: - ${filter.label} - %endif - %endfor - | Advanced Search - %if use_form: -
- %endif -
- - ## Advanced Search - -
+<%namespace file="../grid_common.mako" import="*" /> + +## Print grid header. +${render_grid_filters()} + +## Print grid.