Files
galaxy/static/scripts/mvc/dataset/dataset-li-edit.js
T

369 lines
15 KiB
JavaScript

define([
"mvc/dataset/states",
"mvc/dataset/dataset-li",
"mvc/tags",
"mvc/annotations",
"mvc/base-mvc",
"utils/localization"
], function( STATES, DATASET_LI, TAGS, ANNOTATIONS, BASE_MVC, _l ){
//==============================================================================
var _super = DATASET_LI.DatasetListItemView;
/** @class Editing view for DatasetAssociation.
*/
var DatasetListItemEdit = _super.extend(
/** @lends DatasetListItemEdit.prototype */{
/** logger used to record this.log messages, commonly set to console */
//logger : console,
/** set up: options */
initialize : function( attributes ){
_super.prototype.initialize.call( this, attributes );
//TODO: shouldn't this err if false?
this.hasUser = attributes.hasUser;
/** allow user purge of dataset files? */
this.purgeAllowed = attributes.purgeAllowed || false;
//TODO: move to HiddenUntilActivatedViewMixin
/** should the tags editor be shown or hidden initially? */
this.tagsEditorShown = attributes.tagsEditorShown || false;
/** should the tags editor be shown or hidden initially? */
this.annotationEditorShown = attributes.annotationEditorShown || false;
},
// ......................................................................... titlebar actions
/** In this override, add the other two primary actions: edit and delete */
_renderPrimaryActions : function(){
var actions = _super.prototype._renderPrimaryActions.call( this );
if( this.model.get( 'state' ) === STATES.NOT_VIEWABLE ){
return actions;
}
// render the display, edit attr and delete icon-buttons
return _super.prototype._renderPrimaryActions.call( this ).concat([
this._renderEditButton(),
this._renderDeleteButton()
]);
},
//TODO: move titleButtons into state renderers, remove state checks in the buttons
/** Render icon-button to edit the attributes (format, permissions, etc.) this dataset. */
_renderEditButton : function(){
// don't show edit while uploading, in-accessible
// DO show if in error (ala previous history panel)
if( ( this.model.get( 'state' ) === STATES.DISCARDED )
|| ( !this.model.get( 'accessible' ) ) ){
return null;
}
var purged = this.model.get( 'purged' ),
deleted = this.model.get( 'deleted' ),
editBtnData = {
title : _l( 'Edit attributes' ),
href : this.model.urls.edit,
target : this.linkTarget,
faIcon : 'fa-pencil',
classes : 'edit-btn'
};
// disable if purged or deleted and explain why in the tooltip
if( deleted || purged ){
editBtnData.disabled = true;
if( purged ){
editBtnData.title = _l( 'Cannot edit attributes of datasets removed from disk' );
} else if( deleted ){
editBtnData.title = _l( 'Undelete dataset to edit attributes' );
}
// disable if still uploading or new
} else if( _.contains( [ STATES.UPLOAD, STATES.NEW ], this.model.get( 'state' ) ) ){
editBtnData.disabled = true;
editBtnData.title = _l( 'This dataset is not yet editable' );
}
return faIconButton( editBtnData );
},
/** Render icon-button to delete this hda. */
_renderDeleteButton : function(){
// don't show delete if...
if( ( !this.model.get( 'accessible' ) ) ){
return null;
}
var self = this,
deletedAlready = this.model.isDeletedOrPurged();
return faIconButton({
title : !deletedAlready? _l( 'Delete' ) : _l( 'Dataset is already deleted' ),
disabled : deletedAlready,
faIcon : 'fa-times',
classes : 'delete-btn',
onclick : function() {
// ...bler... tooltips being left behind in DOM (hover out never called on deletion)
self.$el.find( '.icon-btn.delete-btn' ).trigger( 'mouseout' );
self.model[ 'delete' ]();
}
});
},
// ......................................................................... details
/** In this override, add tags and annotations controls, make the ? dbkey a link to editing page */
_renderDetails : function(){
//TODO: generalize to be allow different details for each state
var $details = _super.prototype._renderDetails.call( this ),
state = this.model.get( 'state' );
if( !this.model.isDeletedOrPurged() && _.contains([ STATES.OK, STATES.FAILED_METADATA ], state ) ){
this._renderTags( $details );
this._renderAnnotation( $details );
this._makeDbkeyEditLink( $details );
}
//TODO: TRIPLE tap, ugh.
this._setUpBehaviors( $details );
return $details;
},
/** Add less commonly used actions in the details section based on state */
_renderSecondaryActions : function(){
var actions = _super.prototype._renderSecondaryActions.call( this );
switch( this.model.get( 'state' ) ){
case STATES.UPLOAD:
case STATES.NEW:
case STATES.NOT_VIEWABLE:
return actions;
case STATES.ERROR:
// error button comes first
actions.unshift( this._renderErrButton() );
return actions.concat([ this._renderRerunButton() ]);
case STATES.OK:
case STATES.FAILED_METADATA:
return actions.concat([ this._renderRerunButton(), this._renderVisualizationsButton() ]);
}
return actions.concat([ this._renderRerunButton() ]);
},
/** Render icon-button to report an error on this dataset to the galaxy admin. */
_renderErrButton : function(){
return faIconButton({
title : _l( 'View or report this error' ),
href : this.model.urls.report_error,
classes : 'report-error-btn',
target : this.linkTarget,
faIcon : 'fa-bug'
});
},
/** Render icon-button to re-run the job that created this dataset. */
_renderRerunButton : function(){
return faIconButton({
title : _l( 'Run this job again' ),
href : this.model.urls.rerun,
classes : 'rerun-btn',
target : this.linkTarget,
faIcon : 'fa-refresh'
});
},
/** Render an icon-button or popupmenu of links based on the applicable visualizations */
_renderVisualizationsButton : function(){
//TODO: someday - lazyload visualizations
var visualizations = this.model.get( 'visualizations' );
if( ( this.model.isDeletedOrPurged() )
|| ( !this.hasUser )
|| ( !this.model.hasData() )
|| ( _.isEmpty( visualizations ) ) ){
return null;
}
if( !_.isObject( visualizations[0] ) ){
this.warn( 'Visualizations have been switched off' );
return null;
}
var $visualizations = $( this.templates.visualizations( visualizations, this ) );
//HACK: need to re-write those directed at galaxy_main with linkTarget
$visualizations.find( '[target="galaxy_main"]').attr( 'target', this.linkTarget );
// use addBack here to include the root $visualizations elem (for the case of 1 visualization)
this._addScratchBookFn( $visualizations.find( '.visualization-link' ).addBack( '.visualization-link' ) );
return $visualizations;
},
/** add scratchbook functionality to visualization links */
_addScratchBookFn : function( $links ){
var li = this;
$links.click( function( ev ){
if( Galaxy.frame && Galaxy.frame.active ){
Galaxy.frame.add({
title : "Visualization",
type : "url",
content : $( this ).attr( 'href' )
});
ev.preventDefault();
ev.stopPropagation();
}
});
},
//TODO: if possible move these to readonly view - but display the owner's tags/annotation (no edit)
/** Render the tags list/control */
_renderTags : function( $where ){
if( !this.hasUser ){ return; }
var view = this;
this.tagsEditor = new TAGS.TagsEditor({
model : this.model,
el : $where.find( '.tags-display' ),
onshowFirstTime : function(){ this.render(); },
// persist state on the hda view (and not the editor) since these are currently re-created each time
onshow : function(){ view.tagsEditorShown = true; },
onhide : function(){ view.tagsEditorShown = false; },
$activator : faIconButton({
title : _l( 'Edit dataset tags' ),
classes : 'tag-btn',
faIcon : 'fa-tags'
}).appendTo( $where.find( '.actions .right' ) )
});
if( this.tagsEditorShown ){ this.tagsEditor.toggle( true ); }
},
/** Render the annotation display/control */
_renderAnnotation : function( $where ){
if( !this.hasUser ){ return; }
var view = this;
this.annotationEditor = new ANNOTATIONS.AnnotationEditor({
model : this.model,
el : $where.find( '.annotation-display' ),
onshowFirstTime : function(){ this.render(); },
// persist state on the hda view (and not the editor) since these are currently re-created each time
onshow : function(){ view.annotationEditorShown = true; },
onhide : function(){ view.annotationEditorShown = false; },
$activator : faIconButton({
title : _l( 'Edit dataset annotation' ),
classes : 'annotate-btn',
faIcon : 'fa-comment'
}).appendTo( $where.find( '.actions .right' ) )
});
if( this.annotationEditorShown ){ this.annotationEditor.toggle( true ); }
},
/** If the format/dbkey/genome_build isn't set, make the display a link to the edit page */
_makeDbkeyEditLink : function( $details ){
// make the dbkey a link to editing
if( this.model.get( 'metadata_dbkey' ) === '?'
&& !this.model.isDeletedOrPurged() ){
var editableDbkey = $( '<a class="value">?</a>' )
.attr( 'href', this.model.urls.edit )
.attr( 'target', this.linkTarget );
$details.find( '.dbkey .value' ).replaceWith( editableDbkey );
}
},
// ......................................................................... events
/** event map */
events : _.extend( _.clone( _super.prototype.events ), {
'click .undelete-link' : '_clickUndeleteLink',
'click .purge-link' : '_clickPurgeLink',
'click .edit-btn' : function( ev ){ this.trigger( 'edit', this, ev ); },
'click .delete-btn' : function( ev ){ this.trigger( 'delete', this, ev ); },
'click .rerun-btn' : function( ev ){ this.trigger( 'rerun', this, ev ); },
'click .report-err-btn' : function( ev ){ this.trigger( 'report-err', this, ev ); },
'click .visualization-btn' : function( ev ){ this.trigger( 'visualize', this, ev ); },
'click .dbkey a' : function( ev ){ this.trigger( 'edit', this, ev ); }
}),
/** listener for item undelete (in the messages section) */
_clickUndeleteLink : function( ev ){
this.model.undelete();
return false;
},
/** listener for item purge (in the messages section) */
_clickPurgeLink : function( ev ){
//TODO: confirm dialog
this.model.purge();
return false;
},
// ......................................................................... misc
/** string rep */
toString : function(){
var modelString = ( this.model )?( this.model + '' ):( '(no model)' );
return 'HDAEditView(' + modelString + ')';
}
});
// ............................................................................ TEMPLATES
/** underscore templates */
DatasetListItemEdit.prototype.templates = (function(){
//TODO: move to require text! plugin
var warnings = _.extend( {}, _super.prototype.templates.warnings, {
failed_metadata : BASE_MVC.wrapTemplate([
// in this override, provide a link to the edit page
'<% if( dataset.state === "failed_metadata" ){ %>',
'<div class="failed_metadata-warning warningmessagesmall">',
_l( 'An error occurred setting the metadata for this dataset' ),
'<br /><a href="<%= dataset.urls.edit %>" target="<%= view.linkTarget %>">',
_l( 'Set it manually or retry auto-detection' ),
'</a>',
'</div>',
'<% } %>'
], 'dataset' ),
deleted : BASE_MVC.wrapTemplate([
// in this override, provide links to undelete or purge the dataset
'<% if( dataset.deleted && !dataset.purged ){ %>',
// deleted not purged
'<div class="deleted-msg warningmessagesmall">',
_l( 'This dataset has been deleted' ),
'<br /><a class="undelete-link" href="javascript:void(0);">', _l( 'Undelete it' ), '</a>',
'<% if( view.purgeAllowed ){ %>',
'<br /><a class="purge-link" href="javascript:void(0);">',
_l( 'Permanently remove it from disk' ),
'</a>',
'<% } %>',
'</div>',
'<% } %>'
], 'dataset' )
});
var visualizationsTemplate = BASE_MVC.wrapTemplate([
'<% if( visualizations.length === 1 ){ %>',
'<a class="visualization-btn visualization-link icon-btn" href="<%= visualizations[0].href %>"',
' target="<%= visualizations[0].target %>" title="', _l( 'Visualize in' ),
' <%= visualizations[0].html %>">',
'<span class="fa fa-bar-chart-o"></span>',
'</a>',
'<% } else { %>',
'<div class="visualizations-dropdown dropdown">',
'<a class="visualization-btn icon-btn" data-toggle="dropdown" title="', _l( 'Visualize' ), '">',
'<span class="fa fa-bar-chart-o"></span>',
'</a>',
'<ul class="dropdown-menu" role="menu">',
'<% _.each( visualizations, function( visualization ){ %>',
'<li><a class="visualization-link" href="<%= visualization.href %>"',
' target="<%= visualization.target %>">',
'<%= visualization.html %>',
'</a></li>',
'<% }); %>',
'</ul>',
'</div>',
'<% } %>'
], 'visualizations' );
return _.extend( {}, _super.prototype.templates, {
warnings : warnings,
visualizations : visualizationsTemplate
});
}());
//==============================================================================
return {
DatasetListItemEdit : DatasetListItemEdit
};
});