details: http://www.bx.psu.edu/hg/galaxy/rev/c265090bef9d changeset: 3294:c265090bef9d user: jeremy goecks <jeremy.goecks@emory.edu> date: Thu Jan 28 10:33:12 2010 -0500 description: Added framework for annotating histories, hdas, workflows, and workflows steps. Specific additions: (a) annotation tables; and (b) saving annotations on pages. Also fixed bugs: (i) all page history links in Galaxy now use slugs; and (ii) removed 'pages shared with user' header in published pages view. diffstat: lib/galaxy/model/__init__.py | 15 + lib/galaxy/model/mapping.py | 82 +++++- lib/galaxy/model/migrate/versions/0035_item_annotations_and_workflow_step_tags.py | 129 ++++++++++ lib/galaxy/web/base/controller.py | 16 +- lib/galaxy/web/controllers/history.py | 14 +- lib/galaxy/web/controllers/page.py | 44 +++- lib/galaxy/web/controllers/tag.py | 13 +- templates/page/editor.mako | 91 +++--- templates/page/history_annotation_table.mako | 113 ++++---- templates/page/list_published.mako | 20 + 10 files changed, 405 insertions(+), 132 deletions(-) diffs (726 lines): diff -r fef431822a73 -r c265090bef9d lib/galaxy/model/__init__.py --- a/lib/galaxy/model/__init__.py Thu Jan 28 09:05:13 2010 -0500 +++ b/lib/galaxy/model/__init__.py Thu Jan 28 10:33:12 2010 -0500 @@ -1476,9 +1476,24 @@ class WorkflowTagAssociation ( ItemTagAssociation ): pass +class WorkflowStepTagAssociation ( ItemTagAssociation ): + pass + class StoredWorkflowTagAssociation ( ItemTagAssociation ): pass +class HistoryAnnotationAssociation( object ): + pass + +class HistoryDatasetAssociationAnnotationAssociation( object ): + pass + +class StoredWorkflowAnnotationAssociation( object ): + pass + +class WorkflowStepAnnotationAssociation( object ): + pass + class UserPreference ( object ): def __init__( self, name=None, value=None ): self.name = name diff -r fef431822a73 -r c265090bef9d lib/galaxy/model/mapping.py --- a/lib/galaxy/model/mapping.py Thu Jan 28 09:05:13 2010 -0500 +++ b/lib/galaxy/model/mapping.py Thu Jan 28 10:33:12 2010 -0500 @@ -708,6 +708,8 @@ Column( "title", TEXT ), Column( "config", JSONType ) ) + +# Tagging tables. Tag.table = Table( "tag", metadata, Column( "id", Integer, primary_key=True ), @@ -770,6 +772,43 @@ Column( "value", TrimmedString(255), index=True), Column( "user_value", TrimmedString(255), index=True) ) +WorkflowStepTagAssociation.table = Table( "workflow_step_tag_association", metadata, + Column( "id", Integer, primary_key=True ), + Column( "workflow_step_id", Integer, ForeignKey( "workflow_step.id" ), index=True ), + Column( "tag_id", Integer, ForeignKey( "tag.id" ), index=True ), + Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), + Column( "user_tname", Unicode(255), index=True), + Column( "value", Unicode(255), index=True), + Column( "user_value", Unicode(255), index=True) ) + +# Annotation tables. + +HistoryAnnotationAssociation.table = Table( "history_annotation_association", metadata, + Column( "id", Integer, primary_key=True ), + Column( "history_id", Integer, ForeignKey( "history.id" ), index=True ), + Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), + Column( "annotation", TEXT, index=True) ) + +HistoryDatasetAssociationAnnotationAssociation.table = Table( "history_dataset_association_annotation_association", metadata, + Column( "id", Integer, primary_key=True ), + Column( "history_dataset_association_id", Integer, ForeignKey( "history_dataset_association.id" ), index=True ), + Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), + Column( "annotation", TEXT, index=True) ) + +StoredWorkflowAnnotationAssociation.table = Table( "stored_workflow_annotation_association", metadata, + Column( "id", Integer, primary_key=True ), + Column( "stored_workflow_id", Integer, ForeignKey( "stored_workflow.id" ), index=True ), + Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), + Column( "annotation", TEXT, index=True) ) + +WorkflowStepAnnotationAssociation.table = Table( "workflow_step_annotation_association", metadata, + Column( "id", Integer, primary_key=True ), + Column( "workflow_step_id", Integer, ForeignKey( "workflow_step.id" ), index=True ), + Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), + Column( "annotation", TEXT, index=True) ) + +# User tables. + UserPreference.table = Table( "user_preference", metadata, Column( "id", Integer, primary_key=True ), Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), @@ -893,8 +932,9 @@ visible_children=relation( HistoryDatasetAssociation, primaryjoin=( ( HistoryDatasetAssociation.table.c.parent_id == HistoryDatasetAssociation.table.c.id ) & ( HistoryDatasetAssociation.table.c.visible == True ) ) ), - tags=relation(HistoryDatasetAssociationTagAssociation, order_by=HistoryDatasetAssociationTagAssociation.table.c.id, backref='history_tag_associations') - ) ) + tags=relation( HistoryDatasetAssociationTagAssociation, order_by=HistoryDatasetAssociationTagAssociation.table.c.id, backref='history_tag_associations' ), + annotations=relation( HistoryDatasetAssociationAnnotationAssociation, order_by=HistoryDatasetAssociationAnnotationAssociation.table.c.id, backref="hdas" ) ) + ) assign_mapper( context, Dataset, Dataset.table, properties=dict( @@ -930,8 +970,9 @@ properties=dict( galaxy_sessions=relation( GalaxySessionToHistoryAssociation ), datasets=relation( HistoryDatasetAssociation, backref="history", order_by=asc(HistoryDatasetAssociation.table.c.hid) ), active_datasets=relation( HistoryDatasetAssociation, primaryjoin=( ( HistoryDatasetAssociation.table.c.history_id == History.table.c.id ) & ( not_( HistoryDatasetAssociation.table.c.deleted ) ) ), order_by=asc( HistoryDatasetAssociation.table.c.hid ), viewonly=True ), - tags=relation(HistoryTagAssociation, order_by=HistoryTagAssociation.table.c.id, backref="histories") - ) ) + tags=relation( HistoryTagAssociation, order_by=HistoryTagAssociation.table.c.id, backref="histories" ), + annotations=relation( HistoryAnnotationAssociation, order_by=HistoryAnnotationAssociation.table.c.id, backref="histories" ) ) + ) assign_mapper( context, HistoryUserShareAssociation, HistoryUserShareAssociation.table, properties=dict( user=relation( User, backref='histories_shared_by_others' ), @@ -1164,7 +1205,11 @@ ) ) -assign_mapper( context, WorkflowStep, WorkflowStep.table ) +assign_mapper( context, WorkflowStep, WorkflowStep.table, + properties=dict( + tags=relation(WorkflowStepTagAssociation, order_by=WorkflowStepTagAssociation.table.c.id, backref="workflow_steps"), + annotations=relation( WorkflowStepAnnotationAssociation, order_by=WorkflowStepAnnotationAssociation.table.c.id, backref="workflow_steps" ) ) + ) assign_mapper( context, WorkflowStepConnection, WorkflowStepConnection.table, properties=dict( input_step=relation( WorkflowStep, backref="input_connections", cascade="all", @@ -1216,8 +1261,9 @@ latest_workflow=relation( Workflow, post_update=True, primaryjoin=( StoredWorkflow.table.c.latest_workflow_id == Workflow.table.c.id ), lazy=False ), - tags=relation(StoredWorkflowTagAssociation, order_by=StoredWorkflowTagAssociation.table.c.id, backref="stored_workflows") - ) ) + tags=relation( StoredWorkflowTagAssociation, order_by=StoredWorkflowTagAssociation.table.c.id, backref="stored_workflows" ), + annotations=relation( StoredWorkflowAnnotationAssociation, order_by=StoredWorkflowAnnotationAssociation.table.c.id, backref="stored_workflows" ) ) + ) assign_mapper( context, StoredWorkflowUserShareAssociation, StoredWorkflowUserShareAssociation.table, properties=dict( user=relation( User, backref='workflows_shared_by_others' ), @@ -1287,7 +1333,27 @@ assign_mapper( context, StoredWorkflowTagAssociation, StoredWorkflowTagAssociation.table, properties=dict( tag=relation(Tag, backref="tagged_stored_workflows"), user=relation( User ) ) ) - + +assign_mapper( context, WorkflowStepTagAssociation, WorkflowStepTagAssociation.table, + properties=dict( tag=relation(Tag, backref="tagged_workflow_steps"), user=relation( User ) ) + ) + +assign_mapper( context, HistoryAnnotationAssociation, HistoryAnnotationAssociation.table, + properties=dict( history=relation( History ), user=relation( User ) ) + ) + +assign_mapper( context, HistoryDatasetAssociationAnnotationAssociation, HistoryDatasetAssociationAnnotationAssociation.table, + properties=dict( hda=relation( HistoryDatasetAssociation ), user=relation( User ) ) + ) + +assign_mapper( context, StoredWorkflowAnnotationAssociation, StoredWorkflowAnnotationAssociation.table, + properties=dict( stored_workflow=relation( StoredWorkflow ), user=relation( User ) ) + ) + +assign_mapper( context, WorkflowStepAnnotationAssociation, WorkflowStepAnnotationAssociation.table, + properties=dict( workflow_step=relation( WorkflowStep ), user=relation( User ) ) + ) + assign_mapper( context, UserPreference, UserPreference.table, properties = {} ) diff -r fef431822a73 -r c265090bef9d lib/galaxy/model/migrate/versions/0035_item_annotations_and_workflow_step_tags.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/galaxy/model/migrate/versions/0035_item_annotations_and_workflow_step_tags.py Thu Jan 28 10:33:12 2010 -0500 @@ -0,0 +1,129 @@ +""" +Migration script to (a) create tables for annotating objects and (b) create tags for workflow steps. +""" + +from sqlalchemy import * +from sqlalchemy.orm import * +from migrate import * +from migrate.changeset import * + +import logging +log = logging.getLogger( __name__ ) + +metadata = MetaData( migrate_engine ) +db_session = scoped_session( sessionmaker( bind=migrate_engine, autoflush=False, autocommit=True ) ) + +# Annotation tables. + +HistoryAnnotationAssociation_table = Table( "history_annotation_association", metadata, + Column( "id", Integer, primary_key=True ), + Column( "history_id", Integer, ForeignKey( "history.id" ), index=True ), + Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), + Column( "annotation", TEXT, index=True) ) + +HistoryDatasetAssociationAnnotationAssociation_table = Table( "history_dataset_association_annotation_association", metadata, + Column( "id", Integer, primary_key=True ), + Column( "history_dataset_association_id", Integer, ForeignKey( "history_dataset_association.id" ), index=True ), + Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), + Column( "annotation", TEXT, index=True) ) + +StoredWorkflowAnnotationAssociation_table = Table( "stored_workflow_annotation_association", metadata, + Column( "id", Integer, primary_key=True ), + Column( "stored_workflow_id", Integer, ForeignKey( "stored_workflow.id" ), index=True ), + Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), + Column( "annotation", TEXT, index=True) ) + +WorkflowStepAnnotationAssociation_table = Table( "workflow_step_annotation_association", metadata, + Column( "id", Integer, primary_key=True ), + Column( "workflow_step_id", Integer, ForeignKey( "workflow_step.id" ), index=True ), + Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), + Column( "annotation", TEXT, index=True) ) + +# Tagging tables. + +WorkflowStepTagAssociation_table = Table( "workflow_step_tag_association", metadata, + Column( "id", Integer, primary_key=True ), + Column( "workflow_step_id", Integer, ForeignKey( "workflow_step.id" ), index=True ), + Column( "tag_id", Integer, ForeignKey( "tag.id" ), index=True ), + Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), + Column( "user_tname", Unicode(255), index=True), + Column( "value", Unicode(255), index=True), + Column( "user_value", Unicode(255), index=True) ) + +def upgrade(): + print __doc__ + metadata.reflect() + + # Create history_annotation_association table. + try: + HistoryAnnotationAssociation_table.create() + except Exception, e: + print str(e) + log.debug( "Creating history_annotation_association table failed: %s" % str( e ) ) + + # Create history_dataset_association_annotation_association table. + try: + HistoryDatasetAssociationAnnotationAssociation_table.create() + except Exception, e: + print str(e) + log.debug( "Creating history_dataset_association_annotation_association table failed: %s" % str( e ) ) + + # Create stored_workflow_annotation_association table. + try: + StoredWorkflowAnnotationAssociation_table.create() + except Exception, e: + print str(e) + log.debug( "Creating stored_workflow_annotation_association table failed: %s" % str( e ) ) + + # Create workflow_step_annotation_association table. + try: + WorkflowStepAnnotationAssociation_table.create() + except Exception, e: + print str(e) + log.debug( "Creating workflow_step_annotation_association table failed: %s" % str( e ) ) + + # Create workflow_step_tag_association table. + try: + WorkflowStepTagAssociation_table.create() + except Exception, e: + print str(e) + log.debug( "Creating workflow_step_tag_association table failed: %s" % str( e ) ) + +def downgrade(): + metadata.reflect() + + # Drop history_annotation_association table. + try: + HistoryAnnotationAssociation_table.drop() + except Exception, e: + print str(e) + log.debug( "Dropping history_annotation_association table failed: %s" % str( e ) ) + + # Drop history_dataset_association_annotation_association table. + try: + HistoryDatasetAssociationAnnotationAssociation_table.drop() + except Exception, e: + print str(e) + log.debug( "Dropping history_dataset_association_annotation_association table failed: %s" % str( e ) ) + + # Drop stored_workflow_annotation_association table. + try: + StoredWorkflowAnnotationAssociation_table.drop() + except Exception, e: + print str(e) + log.debug( "Dropping stored_workflow_annotation_association table failed: %s" % str( e ) ) + + # Drop workflow_step_annotation_association table. + try: + WorkflowStepAnnotationAssociation_table.drop() + except Exception, e: + print str(e) + log.debug( "Dropping workflow_step_annotation_association table failed: %s" % str( e ) ) + + # Drop workflow_step_tag_association table. + try: + WorkflowStepTagAssociation_table.drop() + except Exception, e: + print str(e) + log.debug( "Dropping workflow_step_tag_association table failed: %s" % str( e ) ) + \ No newline at end of file diff -r fef431822a73 -r c265090bef9d lib/galaxy/web/base/controller.py --- a/lib/galaxy/web/base/controller.py Thu Jan 28 09:05:13 2010 -0500 +++ b/lib/galaxy/web/base/controller.py Thu Jan 28 10:33:12 2010 -0500 @@ -59,6 +59,20 @@ error( "History is not owned by current user" ) return history + def get_class( self, class_name ): + """ Returns the class object that a string denotes. Without this method, we'd have to do eval(<class_name>). """ + if class_name == 'History': + item_class = model.History + elif class_name == 'HistoryDatasetAssociation': + item_class = model.HistoryDatasetAssociation + elif class_name == 'Page': + item_class = model.Page + elif class_name == 'StoredWorkflow': + item_class = model.StoredWorkflow + else: + item_class = None + return item_class + Root = BaseController class SharingStatusColumn( grids.GridColumn ): @@ -79,7 +93,7 @@ return ", ".join( sharing_statuses ) def get_link( self, trans, grid, item ): - if not item.deleted and ( item.users_shared_with or item.importable ): + if not item.deleted and ( item.users_shared_with or item.importable or item.published ): return dict( operation="share or publish", id=item.id ) return None diff -r fef431822a73 -r c265090bef9d lib/galaxy/web/controllers/history.py --- a/lib/galaxy/web/controllers/history.py Thu Jan 28 09:05:13 2010 -0500 +++ b/lib/galaxy/web/controllers/history.py Thu Jan 28 10:33:12 2010 -0500 @@ -367,16 +367,18 @@ trans.sa_session.flush() @web.expose - @web.require_login( "get history name, slug, and owner's username" ) - def get_name_slug_username_async( self, trans, id=None ): - """ Returns the name, slug, and owner's username for a given history. """ + @web.json + @web.require_login( "get history name and link" ) + def get_name_and_link_async( self, trans, id=None ): + """ Returns history's name and link. """ history = self.get_history( trans, id, False ) # To get info: user must own history. if history.user == trans.get_user(): - slug = iff( history.slug, history.slug, "" ) - username = iff ( history.user.username, history.user.username, "" ) - return history.name + "," + slug + "," + username + if self.set_item_slug( trans.sa_session, history ): + trans.sa_session.flush() + return_dict = { "name" : history.name, "link" : "/u/%s/h/%s" % ( history.user.username, history.slug ) } + return return_dict return @web.expose diff -r fef431822a73 -r c265090bef9d lib/galaxy/web/controllers/page.py --- a/lib/galaxy/web/controllers/page.py Thu Jan 28 09:05:13 2010 -0500 +++ b/lib/galaxy/web/controllers/page.py Thu Jan 28 10:33:12 2010 -0500 @@ -2,6 +2,7 @@ from galaxy.web.framework.helpers import time_ago, grids from galaxy.util.sanitize_html import sanitize_html from galaxy.util.odict import odict +from galaxy.util.json import from_json_string import re @@ -193,7 +194,7 @@ return grid else: # Render grid wrapped in panels - return trans.fill_template( "page/index.mako", grid=grid ) + return trans.fill_template( "page/list_published.mako", grid=grid ) @web.expose @@ -370,18 +371,52 @@ @web.expose @web.require_login() - def save( self, trans, id, content ): + def save( self, trans, id, content, annotations ): id = trans.security.decode_id( id ) page = trans.sa_session.query( model.Page ).get( id ) assert page.user == trans.user + # Sanitize content content = sanitize_html( content, 'utf-8', 'text/html' ) - # Add a new revision to the page with the provided content + + # Add a new revision to the page with the provided content. page_revision = model.PageRevision() page_revision.title = page.title page_revision.page = page page.latest_revision = page_revision page_revision.content = content + + # Save annotations. + annotations = from_json_string( annotations ) + for annotation_dict in annotations: + item_id = trans.security.decode_id( annotation_dict[ 'item_id' ] ) + item_class = self.get_class( annotation_dict[ 'item_class' ] ) + item = trans.sa_session.query( item_class ).filter_by( id=item_id ).first() + if not item: + raise RuntimeError( "cannot find annotated item" ) + text = sanitize_html( annotation_dict[ 'text' ], 'utf-8', 'text/html' ) + + # Add/update annotation. + if item_id and item_class and text: + # Get annotation association. + annotation_assoc_class = eval( "model.%sAnnotationAssociation" % item_class.__name__ ) + annotation_assoc = trans.sa_session.query( annotation_assoc_class ).filter_by( user=trans.get_user() ) + if item_class == model.History.__class__: + annotation_assoc = annotation_assoc.filter_by( history=item ) + elif item_class == model.HistoryDatasetAssociation.__class__: + annotation_assoc = annotation_assoc.filter_by( hda=item ) + elif item_class == model.StoredWorkflow.__class__: + annotation_assoc = annotation_assoc.filter_by( stored_workflow=item ) + elif item_class == model.WorkflowStep.__class__: + annotation_assoc = annotation_assoc.filter_by( workflow_step=item ) + annotation_assoc = annotation_assoc.first() + if not annotation_assoc: + # Create association. + annotation_assoc = annotation_assoc_class() + item.annotations.append( annotation_assoc ) + annotation_assoc.user = trans.get_user() + # Set annotation user text. + annotation_assoc.annotation = text trans.sa_session.flush() @web.expose @@ -448,5 +483,4 @@ @web.expose def get_editor_iframe( self, trans ): """ Returns the document for the page editor's iframe. """ - return trans.fill_template( "page/wymiframe.mako" ) - \ No newline at end of file + return trans.fill_template( "page/wymiframe.mako" ) \ No newline at end of file diff -r fef431822a73 -r c265090bef9d lib/galaxy/web/controllers/tag.py --- a/lib/galaxy/web/controllers/tag.py Thu Jan 28 09:05:13 2010 -0500 +++ b/lib/galaxy/web/controllers/tag.py Thu Jan 28 10:33:12 2010 -0500 @@ -70,17 +70,8 @@ if item_id is not None: item = self._get_item( trans, item_class, trans.security.decode_id( item_id ) ) user = trans.get_user() - - # Get item class. TODO: we should have a mapper that goes from class_name to class object. - if item_class == 'History': - item_class = model.History - elif item_class == 'HistoryDatasetAssociation': - item_class = model.HistoryDatasetAssociation - elif item_class == 'Page': - item_class = model.Page - elif item_class == 'StoredWorkflow': - item_class = model.StoredWorkflow - + item_class = self.get_class( item_class ) + q = q.encode('utf-8') if q.find(":") == -1: return self._get_tag_autocomplete_names(trans, q, limit, timestamp, user, item, item_class) diff -r fef431822a73 -r c265090bef9d templates/page/editor.mako --- a/templates/page/editor.mako Thu Jan 28 09:05:13 2010 -0500 +++ b/templates/page/editor.mako Thu Jan 28 10:33:12 2010 -0500 @@ -233,52 +233,31 @@ type: "POST", url: '${h.url_for( controller='history', action='set_accessible_async' )}', data: { id: item_id, accessible: 'True' }, - error: function() { alert('Make history importable failed; id=' + item_id) } + error: function() { alert('Make history accessible failed; id=' + item_id) } }); - - // Insert link. - wym._exec(WYMeditor.CREATE_LINK, sStamp); - var link_text = $("a[href=" + sStamp + "]", wym._doc.body).text(); - if ( - link_text == "" // Firefox. - || - link_text == sStamp // Safari - ) - { - // User selected no text; create link from scratch and use default text. - // Get history name. - $.get( '${h.url_for( controller='history', action='get_name_slug_username_async' )}?id=' + item_id, - function( history_info ) { - // Parse history info. - history_info = history_info.split(","); - var - history_name = history_info[0], - history_slug = history_info[1], - history_user_username = history_info[2]; - - // Build href from history info. - var href; - if (history_slug != "" && history_user_username != "") - { - var href = - '${h.url_for( controller='/history', action='display_by_username_and_slug', username='USERNAME', slug='SLUG' )}'; - href = href.replace('USERNAME', history_user_username); - href = href.replace('SLUG', history_slug); - } - else - var href = '${h.url_for( controller='/history', action='view' )}?id=' + item_id; - wym.insert("<a href='" + href + "'>History '" + history_name + "'</a>"); - }); - } - else - { - // Link created from selected text; add href and title. - $("a[href=" + sStamp + "]", wym._doc.body) - .attr(WYMeditor.HREF, '${h.url_for( controller='history', action='view' )}' + '?id=' + item_id) - .attr(WYMeditor.TITLE, "History" + item_id); - } - + // Insert link. This is done by getting history info and then manipulating wym. + $.getJSON( '${h.url_for( controller='history', action='get_name_and_link_async' )}?id=' + item_id, function( history_info ) { + // Get link text. + wym._exec(WYMeditor.CREATE_LINK, sStamp); + var link_text = $("a[href=" + sStamp + "]", wym._doc.body).text(); + + // Insert link: need to do different actions depending on link text. + if ( + link_text == "" // Firefox. + || + link_text == sStamp // Safari + ) + { + // User selected no text; create link from scratch and use default text. + wym.insert("<a href='" + history_info.link + "'>History '" + history_info.name + "'</a>"); + } + else + { + // Link created from selected text; add href and title. + $("a[href=" + sStamp + "]", wym._doc.body).attr(WYMeditor.HREF, history_info.link).attr(WYMeditor.TITLE, "History" + item_id); + } + }); }); hide_modal(); @@ -393,12 +372,34 @@ var editor = $.wymeditors(0); var save = function ( callback ) { show_modal( "Saving page", "progress" ); - $.ajax( { + // Gather annotations. + var annotations = new Array(); + + $('.annotation', editor._doc.body).each( function() { + var item_class = $(this).attr( 'item_class' ); + var item_id = $(this).attr( 'item_id' ); + var text = $(this).text(); + annotation = { + "item_class" : item_class, + "item_id" : item_id, + "text" : text + }; + annotations[ annotations.length ] = annotation; + }); + + // Remove inserted elements temporarily. + var annotated_history = $('.annotated_item'); + alert(annotated_history); + annotated_history.remove(); + + // Do save. + $.ajax( { url: "${h.url_for( action='save' )}", type: "POST", data: { id: "${trans.security.encode_id(page.id)}", content: editor.xhtml(), + annotations: JSON.stringify(annotations), "_": "true" }, success: function() { diff -r fef431822a73 -r c265090bef9d templates/page/history_annotation_table.mako --- a/templates/page/history_annotation_table.mako Thu Jan 28 09:05:13 2010 -0500 +++ b/templates/page/history_annotation_table.mako Thu Jan 28 10:33:12 2010 -0500 @@ -1,60 +1,61 @@ <%namespace file="../tagging_common.mako" import="render_tagging_element_html" /> <%namespace file="../root/history_common.mako" import="render_dataset" /> -<table> - ## Table header. - <tr> - <th colspan='2'>History '${history.get_display_name()}'</th> - </tr> - <tr> - ## Status messages and tags. - <td colspan='2'> - %if history.deleted: - <div class="warningmessagesmall"> - ${_('This is a deleted history.')} - </div> - %endif - ## Tags come for free with community tagging, so not sure if this is necessary. - ##%if trans.get_user() is not None: - ## Tags: ${render_tagging_element_html( tags=history.tags, editable=False, use_toggle_link=False )} - ##%endif - </td> - </tr> - <tr> - <td colspan="2" class="annotation">Description of History: - <ol> - <li>What was the motivation for this history? - <li>What is the outcome of this history? - <li>What are unresolved questions from this history? - <li>What new questions arise from this history? - </ol> - </td> - </tr> +<div class="annotated_item"> + <table> + ## Table header. + <tr> + <th colspan='2'>History '${history.get_display_name()}'</th> + </tr> + <tr> + ## Status messages and tags. + <td colspan='2'> + %if history.deleted: + <div class="warningmessagesmall"> + ${_('This is a deleted history.')} + </div> + %endif + ## Tags come for free with community tagging, so not sure if this is necessary. + ##%if trans.get_user() is not None: + ## Tags: ${render_tagging_element_html( tags=history.tags, editable=False, use_toggle_link=False )} + ##%endif + </td> + </tr> + <tr> + <td colspan="2" class="annotation" item_class="History" item_id="${trans.security.encode_id( history.id )}">Description of History: + <ol> + <li>What was the motivation for this history? + <li>What is the outcome of this history? + <li>What are unresolved questions from this history? + <li>What new questions arise from this history? + </ol> + </td> + </tr> - ## Table body. For each dataset, there is an area to annotate the dataset. - %if not datasets: - <tr> - <td> - <div class="infomessagesmall" id="emptyHistoryMessage"> - ${_("Your history is empty. Click 'Get Data' on the left pane to start")} - </div> - </td> - </tr> - %else: - ## Render requested datasets. - %for data in datasets: - %if data.visible: - <tr> - <td valign="top"><span class="annotation">Describe this step: why was it done? what data did it produce?</span></td> - ##<td valign="top" class="annotation">Describe this step: why was it done? what data does it produce?</td> - <td> - <div class="historyItemContainer" id="historyItemContainer-${data.id}"> - ${render_dataset( data, data.hid, show_deleted_on_refresh = show_deleted, user_owns_dataset = False )} - </div> - </td> - </tr> - %endif - %endfor - %endif -</table> - \ No newline at end of file + ## Table body. For each dataset, there is an area to annotate the dataset. + %if not datasets: + <tr> + <td> + <div class="infomessagesmall" id="emptyHistoryMessage"> + ${_("Your history is empty. Click 'Get Data' on the left pane to start")} + </div> + </td> + </tr> + %else: + ## Render requested datasets. + %for data in datasets: + %if data.visible: + <tr> + <td valign="top" class="annotation" item_class="HistoryDatasetAssociation" item_id="${trans.security.encode_id( data.id )}">Describe this step: why was it done? what data did it produce?</td> + ##<td valign="top" class="annotation">Describe this step: why was it done? what data does it produce?</td> + <td> + <div class="historyItemContainer" id="historyItemContainer-${data.id}"> + ${render_dataset( data, data.hid, show_deleted_on_refresh = show_deleted, user_owns_dataset = False )} + </div> + </td> + </tr> + %endif + %endfor + %endif + </table> +</div> \ No newline at end of file diff -r fef431822a73 -r c265090bef9d templates/page/list_published.mako --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/page/list_published.mako Thu Jan 28 10:33:12 2010 -0500 @@ -0,0 +1,20 @@ +<%inherit file="/base_panels.mako"/> + +<%def name="init()"> +<% + self.has_left_panel=False + self.has_right_panel=False + self.active_view="page" + self.message_box_visible=False +%> +</%def> + +<%def name="center_panel()"> + + ## <iframe name="galaxy_main" id="galaxy_main" frameborder="0" style="position: absolute; width: 100%; height: 100%;" src="${h.url_for( controller="page", action="list" )}"> </iframe> + + <div style="overflow: auto; height: 100%;"> + <div class="page-container" style="padding: 10px;"> + ${grid} + +</%def>