diff --git a/static/scripts/mvc/collection/dataset-collection-edit.js b/static/scripts/mvc/collection/collection-li-edit.js similarity index 64% rename from static/scripts/mvc/collection/dataset-collection-edit.js rename to static/scripts/mvc/collection/collection-li-edit.js index 4d49335b3ab..49cd6ce4c0e 100644 --- a/static/scripts/mvc/collection/dataset-collection-edit.js +++ b/static/scripts/mvc/collection/collection-li-edit.js @@ -1,8 +1,7 @@ define([ - "mvc/dataset/states", - "mvc/collection/dataset-collection-base", + "mvc/collection/collection-li", "utils/localization" -], function( STATES, DC_BASE_VIEW, _l ){ +], function( DC_LI, _l ){ //============================================================================== /* @@ -11,29 +10,24 @@ NOTE: not much going on here. Until we find out what operations a user will need */ //============================================================================== -var _super = DC_BASE_VIEW.DCBaseView; -/** @class Editing view for DatasetCollection. - * @name DatasetCollectionEditView - * - * @augments DCBaseView - * @constructs +var _super = DC_LI.DCListItemView; +/** @class Editing view for DatasetCollectionElement. */ -var DCEditView = _super.extend({ +var DCEListItemEdit = _super.extend({ /** logger used to record this.log messages, commonly set to console */ - // comment this out to suppress log output //logger : console, // ......................................................................... misc /** string rep */ toString : function(){ var modelString = ( this.model )?( this.model + '' ):( '(no model)' ); - return 'DCEditView(' + modelString + ')'; + return 'DCEListItemEdit(' + modelString + ')'; } }); //============================================================================== return { - DCEditView : DCEditView + DCEListItemEdit : DCEListItemEdit }; }); diff --git a/static/scripts/mvc/collection/dataset-collection-base.js b/static/scripts/mvc/collection/collection-li.js similarity index 83% rename from static/scripts/mvc/collection/dataset-collection-base.js rename to static/scripts/mvc/collection/collection-li.js index a121acb08d0..3aba237b1be 100644 --- a/static/scripts/mvc/collection/dataset-collection-base.js +++ b/static/scripts/mvc/collection/collection-li.js @@ -1,5 +1,5 @@ define([ - "mvc/dataset/dataset-list-element", + "mvc/dataset/dataset-li", "mvc/base-mvc", "utils/localization" ], function( DATASET_LI, BASE_MVC, _l ){ @@ -8,7 +8,7 @@ define([ var ListItemView = BASE_MVC.ListItemView; /** @class Read only view for DatasetCollection. */ -var DCBaseView = ListItemView.extend({ +var DCListItemView = ListItemView.extend({ //TODO: may not be needed /** logger used to record this.log messages, commonly set to console */ @@ -22,7 +22,7 @@ var DCBaseView = ListItemView.extend({ /** set up */ initialize : function( attributes ){ if( attributes.logger ){ this.logger = this.model.logger = attributes.logger; } - this.log( 'DCBaseView.initialize:', attributes ); + this.log( this + '(DCListItemView).initialize:', attributes ); ListItemView.prototype.initialize.call( this, attributes ); }, @@ -60,13 +60,13 @@ var DCBaseView = ListItemView.extend({ /** String representation */ toString : function(){ var modelString = ( this.model )?( this.model + '' ):( '(no model)' ); - return 'DCBaseView(' + modelString + ')'; + return 'DCListItemView(' + modelString + ')'; } }); // ............................................................................ TEMPLATES /** underscore templates */ -DCBaseView.prototype.templates = (function(){ +DCListItemView.prototype.templates = (function(){ // use element identifier var titleBarTemplate = BASE_MVC.wrapTemplate([ @@ -87,8 +87,8 @@ DCBaseView.prototype.templates = (function(){ //============================================================================== /** @class Read only view for DatasetCollectionElement. */ -var DCEBaseView = ListItemView.extend({ -//TODO: this might be expendable - compacted with HDADCEBaseView +var DCEListItemView = ListItemView.extend({ +//TODO: this might be expendable - compacted with HDAListItemView /** logger used to record this.log messages, commonly set to console */ // comment this out to suppress log output @@ -102,7 +102,7 @@ var DCEBaseView = ListItemView.extend({ /** */ initialize : function( attributes ){ if( attributes.logger ){ this.logger = this.model.logger = attributes.logger; } - this.log( 'DCEBaseView.initialize:', attributes ); + this.log( 'DCEListItemView.initialize:', attributes ); ListItemView.prototype.initialize.call( this, attributes ); }, @@ -110,13 +110,13 @@ var DCEBaseView = ListItemView.extend({ /** String representation */ toString : function(){ var modelString = ( this.model )?( this.model + '' ):( '(no model)' ); - return 'DCEBaseView(' + modelString + ')'; + return 'DCEListItemView(' + modelString + ')'; } }); // ............................................................................ TEMPLATES /** underscore templates */ -DCEBaseView.prototype.templates = (function(){ +DCEListItemView.prototype.templates = (function(){ // use the element identifier here - since that will persist and the user will need it var titleBarTemplate = BASE_MVC.wrapTemplate([ @@ -135,20 +135,20 @@ DCEBaseView.prototype.templates = (function(){ //============================================================================== -/** @class Read only view for a DatasetCollectionElement that is also an HDA. +/** @class Read only view for a DatasetCollectionElement that is also an DatasetAssociation + * (a dataset contained in a dataset collection). */ -var DatasetDCEBaseView = DATASET_LI.DatasetListItemView.extend({ +var DatasetDCEListItemView = DATASET_LI.DatasetListItemView.extend({ className : DATASET_LI.DatasetListItemView.prototype.className + " dataset-collection-element", /** logger used to record this.log messages, commonly set to console */ - // comment this out to suppress log output //logger : console, /** */ initialize : function( attributes ){ if( attributes.logger ){ this.logger = this.model.logger = attributes.logger; } - this.log( 'DatasetDCEBaseView.initialize:', attributes ); + this.log( 'DatasetDCEListItemView.initialize:', attributes ); DATASET_LI.DatasetListItemView.prototype.initialize.call( this, attributes ); }, @@ -156,13 +156,13 @@ var DatasetDCEBaseView = DATASET_LI.DatasetListItemView.extend({ /** String representation */ toString : function(){ var modelString = ( this.model )?( this.model + '' ):( '(no model)' ); - return 'DatasetDCEBaseView(' + modelString + ')'; + return 'DatasetDCEListItemView(' + modelString + ')'; } }); // ............................................................................ TEMPLATES /** underscore templates */ -DatasetDCEBaseView.prototype.templates = (function(){ +DatasetDCEListItemView.prototype.templates = (function(){ // use the element identifier here and not the dataset name //TODO:?? can we steal the DCE titlebar? @@ -180,13 +180,14 @@ DatasetDCEBaseView.prototype.templates = (function(){ }); }()); + //============================================================================== /** @class Read only view for a DatasetCollectionElement that is also a DatasetCollection * (a nested DC). */ -var NestedDCDCEBaseView = DCBaseView.extend({ +var NestedDCDCEListItemView = DCListItemView.extend({ - className : DCBaseView.prototype.className + " dataset-collection-element", + className : DCListItemView.prototype.className + " dataset-collection-element", /** logger used to record this.log messages, commonly set to console */ // comment this out to suppress log output @@ -194,7 +195,7 @@ var NestedDCDCEBaseView = DCBaseView.extend({ /** In this override, add the state as a class for use with state-based CSS */ _swapNewRender : function( $newRender ){ - DATASET_LI.DatasetListItemView.prototype._swapNewRender.call( this, $newRender ); + DCListItemView.prototype._swapNewRender.call( this, $newRender ); //TODO: model currently has no state var state = this.model.get( 'state' ) || 'ok'; //if( this.model.has( 'state' ) ){ @@ -207,16 +208,16 @@ var NestedDCDCEBaseView = DCBaseView.extend({ /** String representation */ toString : function(){ var modelString = ( this.model )?( this.model + '' ):( '(no model)' ); - return 'NestedDCDCEBaseView(' + modelString + ')'; + return 'NestedDCDCEListItemView(' + modelString + ')'; } }); //============================================================================== return { - DCBaseView : DCBaseView, - DCEBaseView : DCEBaseView, - DatasetDCEBaseView : DatasetDCEBaseView, - NestedDCDCEBaseView : NestedDCDCEBaseView + DCListItemView : DCListItemView, + DCEListItemView : DCEListItemView, + DatasetDCEListItemView : DatasetDCEListItemView, + NestedDCDCEListItemView : NestedDCDCEListItemView }; }); diff --git a/static/scripts/mvc/collection/collection-model.js b/static/scripts/mvc/collection/collection-model.js index d803329f602..10c0e676560 100644 --- a/static/scripts/mvc/collection/collection-model.js +++ b/static/scripts/mvc/collection/collection-model.js @@ -2,7 +2,7 @@ define([ "mvc/dataset/dataset-model", "mvc/base-mvc", "utils/localization" -], function( DATASET, BASE_MVC, _l ){ +], function( DATASET_MODEL, BASE_MVC, _l ){ //============================================================================== /* Notes: @@ -118,13 +118,13 @@ var DCECollection = Backbone.Collection.extend( BASE_MVC.LoggableMixin ).extend( //============================================================================== /** @class Backbone model for a dataset collection element that is a dataset (HDA). */ -var DatasetDCE = DATASET.DatasetAssociation.extend( BASE_MVC.mixin( DatasetCollectionElementMixin, +var DatasetDCE = DATASET_MODEL.DatasetAssociation.extend( BASE_MVC.mixin( DatasetCollectionElementMixin, /** @lends DatasetDCE.prototype */{ /** logger used to record this.log messages, commonly set to console */ //logger : console, - defaults : _.extend( {}, DATASET.DatasetAssociation.prototype.defaults, DatasetCollectionElementMixin.defaults ), + defaults : _.extend( {}, DATASET_MODEL.DatasetAssociation.prototype.defaults, DatasetCollectionElementMixin.defaults ), // because all objects have constructors (as this hashmap would even if this next line wasn't present) // the constructor in hcontentMixin won't be attached by BASE_MVC.mixin to this model @@ -132,7 +132,7 @@ var DatasetDCE = DATASET.DatasetAssociation.extend( BASE_MVC.mixin( DatasetColle /** call the mixin constructor */ constructor : function( attributes, options ){ this.debug( '\t DatasetDCE.constructor:', attributes, options ); - //DATASET.DatasetAssociation.prototype.constructor.call( this, attributes, options ); + //DATASET_MODEL.DatasetAssociation.prototype.constructor.call( this, attributes, options ); DatasetCollectionElementMixin.constructor.call( this, attributes, options ); }, @@ -140,7 +140,7 @@ var DatasetDCE = DATASET.DatasetAssociation.extend( BASE_MVC.mixin( DatasetColle /** set up */ initialize : function( attributes, options ){ this.debug( this + '(DatasetDCE).initialize:', attributes, options ); - DATASET.DatasetAssociation.prototype.initialize.call( this, attributes, options ); + DATASET_MODEL.DatasetAssociation.prototype.initialize.call( this, attributes, options ); }, /** String representation. */ diff --git a/static/scripts/mvc/collection/collection-panel.js b/static/scripts/mvc/collection/collection-panel.js index 5d2e13df3ef..fb5ab11da9f 100644 --- a/static/scripts/mvc/collection/collection-panel.js +++ b/static/scripts/mvc/collection/collection-panel.js @@ -1,20 +1,15 @@ define([ - "mvc/collection/dataset-collection-base", + "mvc/collection/collection-model", + "mvc/collection/collection-li", "mvc/base-mvc", "utils/localization" -], function( DC_BASE, BASE_MVC, _l ){ +], function( DC_MODEL, DC_LI, BASE_MVC, _l ){ /* ============================================================================= TODO: ============================================================================= */ // ============================================================================= /** @class non-editable, read-only View/Controller for a dataset collection. - * @name CollectionPanel - * - * @augments Backbone.View - * @borrows LoggableMixin#logger as #logger - * @borrows LoggableMixin#log as #log - * @constructs */ var CollectionPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend( /** @lends CollectionPanel.prototype */{ @@ -29,8 +24,8 @@ var CollectionPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend( /** (in ms) that jquery effects will use */ fxSpeed : 'fast', - DatasetDCEViewClass : DC_BASE.DatasetDCEBaseView, - NestedDCEViewClass : DC_BASE.NestedDCEBaseView, + DatasetDCEViewClass : DC_LI.DatasetDCEListItemView, + NestedDCDCEViewClass : DC_LI.NestedDCDCEListItemView, // ......................................................................... SET UP /** Set up the view, set up storage, bind listeners to HistoryContents events @@ -44,9 +39,13 @@ var CollectionPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend( } this.log( this + '.initialize:', attributes ); + this.linkTarget = attributes.linkTarget || '_blank'; + this.hasUser = attributes.hasUser; this.panelStack = []; this.parentName = attributes.parentName; + + //window.collectionPanel = this; }, /** create any event listeners for the panel @@ -70,7 +69,7 @@ var CollectionPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend( }, // ------------------------------------------------------------------------ panel rendering - /** Render urls, historyPanel body, and hdas (if any are shown) + /** Render panel * @fires: rendered when the panel is attached and fully visible * @see Backbone.View#render */ @@ -122,7 +121,7 @@ var CollectionPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend( return this; }, - /** render with history data + /** render with collection data * @returns {jQuery} dom fragment as temporary container to be swapped out later */ renderModel : function( ){ @@ -139,7 +138,7 @@ var CollectionPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend( return $newRender; }, - /** Set up HistoryPanel js/widget behaviours */ + /** Set up js/widget behaviours */ _setUpBehaviours : function( $where ){ //TODO: these should be either sub-MVs, or handled by events $where = $where || this.$el; @@ -152,16 +151,16 @@ var CollectionPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend( $container : function(){ return ( this.findContainerFn )?( this.findContainerFn.call( this ) ):( this.$el.parent() ); }, - /** where hdaViews are attached */ + /** where list content views are attached */ $datasetsList : function( $where ){ return ( $where || this.$el ).find( '.datasets-list' ); }, // ------------------------------------------------------------------------ sub-views - /** Set up/render a view for each HDA to be shown, init with model and listeners. - * HDA views are cached to the map this.hdaViews (using the model.id as key). - * @param {jQuery} $whereTo what dom element to prepend the HDA views to - * @returns the number of visible hda views + /** Set up/render a view for each DCE to be shown, init with model and listeners. + * DCE views are cached to the map this.contentViews (using the model.id as key). + * @param {jQuery} $whereTo what dom element to prepend the DCE views to + * @returns the number of visible DCE views */ renderContents : function( $whereTo ){ //this.debug( 'renderContents, elements:', this.model.elements ); @@ -172,7 +171,7 @@ var CollectionPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend( contentViews = {}, //NOTE: no filtering here visibleContents = this.model.getVisibleContents(); - this.log( 'renderContents, visibleContents:', visibleContents, $whereTo ); + //this.debug( 'renderContents, visibleContents:', visibleContents, $whereTo ); this.$datasetsList( $whereTo ).empty(); if( visibleContents && visibleContents.length ){ @@ -192,8 +191,8 @@ var CollectionPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend( //this.debug( 'content json:', JSON.stringify( content, null, ' ' ) ); var contentView = null, ContentClass = this._getContentClass( content ); - this.debug( 'ContentClass:', ContentClass ); - this.debug( 'content:', content ); + //this.debug( 'content:', content ); + //this.debug( 'ContentClass:', ContentClass ); contentView = new ContentClass({ model : content, linkTarget : this.linkTarget, @@ -201,20 +200,20 @@ var CollectionPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend( hasUser : this.hasUser, logger : this.logger }); - this.debug( 'contentView:', contentView ); + //this.debug( 'contentView:', contentView ); this._setUpContentListeners( contentView ); return contentView; }, /** */ _getContentClass : function( content ){ - this.debug( this + '._getContentClass:', content ); - this.debug( 'DCEViewClass:', this.DCEViewClass ); + //this.debug( this + '._getContentClass:', content ); +//TODO: subclasses use DCEViewClass - but are currently unused - decide switch( content.get( 'element_type' ) ){ case 'hda': - return this.DCEViewClass; + return this.DatasetDCEViewClass; case 'dataset_collection': - return this.DCEViewClass; + return this.NestedDCDCEViewClass; } throw new TypeError( 'Unknown element type:', content.get( 'element_type' ) ); }, @@ -232,14 +231,16 @@ var CollectionPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend( /** */ _addCollectionPanel : function( collectionView ){ +//TODO: a bit hackish var currPanel = this, collectionModel = collectionView.model; - this.debug( 'collection panel (stack), collectionView:', collectionView ); - this.debug( 'collection panel (stack), collectionModel:', collectionModel ); + //this.debug( 'collection panel (stack), collectionView:', collectionView ); + //this.debug( 'collection panel (stack), collectionModel:', collectionModel ); var panel = new PairCollectionPanel({ model : collectionModel, - parentName : this.model.get( 'name' ) + parentName : this.model.get( 'name' ), + linkTarget : this.linkTarget }); currPanel.panelStack.push( panel ); @@ -277,7 +278,7 @@ var CollectionPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend( 'click .navigation .back' : 'close' }, - /** */ + /** close/remove this collection panel */ close : function( event ){ this.$el.remove(); this.trigger( 'close' ); @@ -334,7 +335,8 @@ CollectionPanel.templates = CollectionPanel.prototype.templates = (function(){ /** @class non-editable, read-only View/Controller for a dataset collection. */ var ListCollectionPanel = CollectionPanel.extend({ - DCEViewClass : DC_BASE.DatasetDCEBaseView, + //TODO: not strictly needed - due to switch in CollectionPanel._getContentClass + DatasetDCEViewClass : DC_LI.DatasetDCEListItemView, // ........................................................................ misc /** string rep */ @@ -360,7 +362,8 @@ var PairCollectionPanel = ListCollectionPanel.extend({ /** @class non-editable, read-only View/Controller for a dataset collection. */ var ListOfPairsCollectionPanel = CollectionPanel.extend({ - DCEViewClass : DC_BASE.NestedDCDCEBaseView, + //TODO: not strictly needed - due to switch in CollectionPanel._getContentClass + NestedDCDCEViewClass : DC_LI.NestedDCDCEListItemView, // ........................................................................ misc /** string rep */ diff --git a/static/scripts/mvc/dataset/editable-dataset-list-element.js b/static/scripts/mvc/dataset/dataset-li-edit.js similarity index 97% rename from static/scripts/mvc/dataset/editable-dataset-list-element.js rename to static/scripts/mvc/dataset/dataset-li-edit.js index ceffe04324c..4a3e5685147 100644 --- a/static/scripts/mvc/dataset/editable-dataset-list-element.js +++ b/static/scripts/mvc/dataset/dataset-li-edit.js @@ -1,6 +1,6 @@ define([ "mvc/dataset/states", - "mvc/dataset/dataset-list-element", + "mvc/dataset/dataset-li", "mvc/tags", "mvc/annotations", "mvc/base-mvc", @@ -9,15 +9,9 @@ define([ //============================================================================== var _super = DATASET_LI.DatasetListItemView; /** @class Editing view for DatasetAssociation. - * @name EditableDatasetListItemView - * - * @augments HDABaseView - * @borrows LoggableMixin#logger as #logger - * @borrows LoggableMixin#log as #log - * @constructs */ -var EditableDatasetListItemView = _super.extend( -/** @lends EditableDatasetListItemView.prototype */{ +var DatasetListItemEdit = _super.extend( +/** @lends DatasetListItemEdit.prototype */{ /** logger used to record this.log messages, commonly set to console */ //logger : console, @@ -285,7 +279,7 @@ var EditableDatasetListItemView = _super.extend( // ............................................................................ TEMPLATES /** underscore templates */ -EditableDatasetListItemView.prototype.templates = (function(){ +DatasetListItemEdit.prototype.templates = (function(){ //TODO: move to require text! plugin var warnings = _.extend( {}, _super.prototype.templates.warnings, { @@ -352,6 +346,6 @@ EditableDatasetListItemView.prototype.templates = (function(){ //============================================================================== return { - EditableDatasetListItemView : EditableDatasetListItemView + DatasetListItemEdit : DatasetListItemEdit }; }); diff --git a/static/scripts/mvc/dataset/dataset-list-element.js b/static/scripts/mvc/dataset/dataset-li.js similarity index 99% rename from static/scripts/mvc/dataset/dataset-list-element.js rename to static/scripts/mvc/dataset/dataset-li.js index a6345b18ab2..0c06e013d3d 100644 --- a/static/scripts/mvc/dataset/dataset-list-element.js +++ b/static/scripts/mvc/dataset/dataset-li.js @@ -13,7 +13,6 @@ var DatasetListItemView = _super.extend( /** @lends DatasetListItemView.prototype */{ /** logger used to record this.log messages, commonly set to console */ - // comment this out to suppress log output //logger : console, className : _super.prototype.className + " dataset", diff --git a/static/scripts/mvc/dataset/dataset-model.js b/static/scripts/mvc/dataset/dataset-model.js index a85437fee79..65f5e014051 100644 --- a/static/scripts/mvc/dataset/dataset-model.js +++ b/static/scripts/mvc/dataset/dataset-model.js @@ -74,11 +74,10 @@ var DatasetAssociation = Backbone.Model.extend( BASE_MVC.LoggableMixin ).extend( 'meta_download' : 'dataset/get_metadata_file?hda_id=' + id + '&metadata_name=' }; //TODO: global - if( galaxy_config && galaxy_config.root ){ - _.each( urls, function( key, value ){ - urls[ key ] = galaxy_config.root + value; - }); - } + var root = ( galaxy_config && galaxy_config.root )?( galaxy_config.root ):( '/' ); + _.each( urls, function( value, key ){ + urls[ key ] = root + value; + }); this.urls = urls; return urls; }, diff --git a/static/scripts/mvc/dataset/hda-edit.js b/static/scripts/mvc/history/hda-li-edit.js similarity index 77% rename from static/scripts/mvc/dataset/hda-edit.js rename to static/scripts/mvc/history/hda-li-edit.js index c2e4c3fa49b..65c0348c593 100644 --- a/static/scripts/mvc/dataset/hda-edit.js +++ b/static/scripts/mvc/history/hda-li-edit.js @@ -1,15 +1,15 @@ define([ - "mvc/dataset/editable-dataset-list-element", - "mvc/dataset/hda-base", + "mvc/dataset/dataset-li-edit", + "mvc/history/hda-li", "mvc/base-mvc", "utils/localization" -], function( DATASET_EDIT, HDA_BASE, BASE_MVC, _l ){ +], function( DATASET_LI_EDIT, HDA_LI, BASE_MVC, _l ){ //============================================================================== -var _super = DATASET_EDIT.EditableDatasetListItemView; +var _super = DATASET_LI_EDIT.DatasetListItemEdit; /** @class Editing view for HistoryDatasetAssociation. */ -var HDAEditView = _super.extend( -/** @lends HDAEditView.prototype */{ +var HDAListItemEdit = _super.extend( +/** @lends HDAListItemEdit.prototype */{ /** logger used to record this.log messages, commonly set to console */ //logger : console, @@ -26,14 +26,14 @@ var HDAEditView = _super.extend( /** string rep */ toString : function(){ var modelString = ( this.model )?( this.model + '' ):( '(no model)' ); - return 'HDAEditView(' + modelString + ')'; + return 'HDAListItemEdit(' + modelString + ')'; } }); // ............................................................................ TEMPLATES /** underscore templates */ -HDAEditView.prototype.templates = (function(){ +HDAListItemEdit.prototype.templates = (function(){ //TODO: move to require text! plugin var warnings = _.extend( {}, _super.prototype.templates.warnings, { @@ -49,8 +49,8 @@ HDAEditView.prototype.templates = (function(){ }); return _.extend( {}, _super.prototype.templates, { - //NOTE: *steal* the HDABaseView titleBar - titleBar : HDA_BASE.HDABaseView.prototype.templates.titleBar, + //NOTE: *steal* the HDAListItemView titleBar + titleBar : HDA_LI.HDAListItemView.prototype.templates.titleBar, warnings : warnings }); }()); @@ -58,6 +58,6 @@ HDAEditView.prototype.templates = (function(){ //============================================================================== return { - HDAEditView : HDAEditView + HDAListItemEdit : HDAListItemEdit }; }); diff --git a/static/scripts/mvc/dataset/hda-base.js b/static/scripts/mvc/history/hda-li.js similarity index 90% rename from static/scripts/mvc/dataset/hda-base.js rename to static/scripts/mvc/history/hda-li.js index 02bc664ba3b..8eae89c9d75 100644 --- a/static/scripts/mvc/dataset/hda-base.js +++ b/static/scripts/mvc/history/hda-li.js @@ -1,5 +1,5 @@ define([ - "mvc/dataset/dataset-list-element", + "mvc/dataset/dataset-li", "mvc/base-mvc", "utils/localization" ], function( DATASET_LI, BASE_MVC, _l ){ @@ -11,8 +11,8 @@ var _super = DATASET_LI.DatasetListItemView; * the primary thing this class does (currently) is override templates * to render the HID. */ -var HDABaseView = _super.extend( -/** @lends HDABaseView.prototype */{ +var HDAListItemView = _super.extend( +/** @lends HDAListItemView.prototype */{ /** logger used to record this.log messages, commonly set to console */ //logger : console, @@ -27,13 +27,13 @@ var HDABaseView = _super.extend( /** String representation */ toString : function(){ var modelString = ( this.model )?( this.model + '' ):( '(no model)' ); - return 'HDABaseView(' + modelString + ')'; + return 'HDAListItemView(' + modelString + ')'; } }); // ............................................................................ TEMPLATES /** underscore templates */ -HDABaseView.prototype.templates = (function(){ +HDAListItemView.prototype.templates = (function(){ //TODO: move to require text! plugin var titleBarTemplate = BASE_MVC.wrapTemplate([ @@ -69,6 +69,6 @@ HDABaseView.prototype.templates = (function(){ //============================================================================== return { - HDABaseView : HDABaseView + HDAListItemView : HDAListItemView }; }); diff --git a/static/scripts/mvc/dataset/hda-model.js b/static/scripts/mvc/history/hda-model.js similarity index 95% rename from static/scripts/mvc/dataset/hda-model.js rename to static/scripts/mvc/history/hda-model.js index c6fb695f740..7dc1fc4ba38 100644 --- a/static/scripts/mvc/dataset/hda-model.js +++ b/static/scripts/mvc/history/hda-model.js @@ -1,6 +1,6 @@ define([ "mvc/dataset/dataset-model", - "mvc/history/history-content-base", + "mvc/history/history-content-model", "mvc/base-mvc", "utils/localization" ], function( DATASET, HISTORY_CONTENT, BASE_MVC, _l ){ @@ -13,7 +13,6 @@ var HistoryDatasetAssociation = _super.extend( BASE_MVC.mixin( hcontentMixin, /** @lends HistoryDatasetAssociation.prototype */{ /** logger used to record this.log messages, commonly set to console */ - // comment this out to suppress log output //logger : console, // because all objects have constructors (as this hashmap would even if this next line wasn't present) diff --git a/static/scripts/mvc/collection/hdca-edit.js b/static/scripts/mvc/history/hdca-li-edit.js similarity index 88% rename from static/scripts/mvc/collection/hdca-edit.js rename to static/scripts/mvc/history/hdca-li-edit.js index 1c506a12951..a34814f0a9f 100644 --- a/static/scripts/mvc/collection/hdca-edit.js +++ b/static/scripts/mvc/history/hdca-li-edit.js @@ -1,13 +1,13 @@ define([ "mvc/dataset/states", - "mvc/collection/hdca-base", + "mvc/history/hdca-li", "utils/localization" -], function( STATES, HDCA_BASE, _l ){ +], function( STATES, HDCA_LI, _l ){ //============================================================================== -var _super = HDCA_BASE.HDCABaseView; +var _super = HDCA_LI.HDCAListItemView; /** @class Editing view for HistoryDatasetCollectionAssociation. */ -var HDCAEditView = _super.extend({ +var HDCAListItemEdit = _super.extend({ /** logger used to record this.log messages, commonly set to console */ //logger : console, @@ -44,12 +44,12 @@ var HDCAEditView = _super.extend({ /** string rep */ toString : function(){ var modelString = ( this.model )?( this.model + '' ):( '(no model)' ); - return 'HDCAEditView(' + modelString + ')'; + return 'HDCAListItemEdit(' + modelString + ')'; } }); //============================================================================== return { - HDCAEditView : HDCAEditView + HDCAListItemEdit : HDCAListItemEdit }; }); diff --git a/static/scripts/mvc/collection/hdca-base.js b/static/scripts/mvc/history/hdca-li.js similarity index 86% rename from static/scripts/mvc/collection/hdca-base.js rename to static/scripts/mvc/history/hdca-li.js index 380cea5773a..5261332fd2f 100644 --- a/static/scripts/mvc/collection/hdca-base.js +++ b/static/scripts/mvc/history/hdca-li.js @@ -1,15 +1,15 @@ define([ "mvc/dataset/states", - "mvc/collection/dataset-collection-base", + "mvc/collection/collection-li", "mvc/base-mvc", "utils/localization" -], function( STATES, DC_BASE, BASE_MVC, _l ){ +], function( STATES, DC_LI, BASE_MVC, _l ){ /* global Backbone */ //============================================================================== -var _super = DC_BASE.DCBaseView; +var _super = DC_LI.DCListItemView; /** @class Read only view for HistoryDatasetCollectionAssociation (a dataset collection inside a history). */ -var HDCABaseView = _super.extend({ +var HDCAListItemView = _super.extend({ /** logger used to record this.log messages, commonly set to console */ //logger : console, @@ -33,12 +33,12 @@ var HDCABaseView = _super.extend({ /** String representation */ toString : function(){ var modelString = ( this.model )?( this.model + '' ):( '(no model)' ); - return 'HDCABaseView(' + modelString + ')'; + return 'HDCAListItemView(' + modelString + ')'; } }); /** underscore templates */ -HDCABaseView.prototype.templates = (function(){ +HDCAListItemView.prototype.templates = (function(){ // could steal this from hda-base (or use mixed content) var titleBarTemplate = BASE_MVC.wrapTemplate([ @@ -62,6 +62,6 @@ HDCABaseView.prototype.templates = (function(){ //============================================================================== return { - HDCABaseView : HDCABaseView + HDCAListItemView : HDCAListItemView }; }); diff --git a/static/scripts/mvc/collection/hdca-model.js b/static/scripts/mvc/history/hdca-model.js similarity index 97% rename from static/scripts/mvc/collection/hdca-model.js rename to static/scripts/mvc/history/hdca-model.js index cd624e14c15..363e49dacc8 100644 --- a/static/scripts/mvc/collection/hdca-model.js +++ b/static/scripts/mvc/history/hdca-model.js @@ -1,8 +1,8 @@ define([ - "mvc/history/history-content-base", "mvc/collection/collection-model", + "mvc/history/history-content-model", "utils/localization" -], function( HISTORY_CONTENT, DC_MODEL, _l ){ +], function( DC_MODEL, HISTORY_CONTENT, _l ){ /*============================================================================== Models for DatasetCollections contained within a history. diff --git a/static/scripts/mvc/history/history-content-base-view.js b/static/scripts/mvc/history/history-content-base-view.js deleted file mode 100644 index 6c7e2f9090e..00000000000 --- a/static/scripts/mvc/history/history-content-base-view.js +++ /dev/null @@ -1,44 +0,0 @@ -define([ - "mvc/base-mvc", - "utils/localization" -], function( BASE_MVC, _l ){ -/* global Backbone */ -//============================================================================== -/** @class Read only view for history content views to mixin/extend. - * Functionality here should be history-centric. - */ -var HistoryContentViewMixin = { - //PRECONDITION: expects to be mixed into an BASE_MVC.ExpandableView - initialize : function( attributes ){ - - } - -//TODO: render title with HID -//TODO: render based on visiblility (HDA only) - -}; - -//NOTE: no templates, they're defined at the leaves of the hierarchy -//TODO:?? you sure about that? - -//============================================================================== -/** @class Read only view for history content views to extend. - * @name HistoryContentBaseView - * - * @augments Backbone.View - * @borrows LoggableMixin#logger as #logger - * @borrows LoggableMixin#log as #log - * @constructs - */ -var HistoryContentBaseView = BASE_MVC.ExpandableView.extend( -/** @lends HistoryContentBaseView.prototype */HistoryContentViewMixin ); - -//TODO: not sure base view class is warranted or even wise - - -//============================================================================== - return { - HistoryContentViewMixin : HistoryContentViewMixin, - HistoryContentBaseView : HistoryContentBaseView - }; -}); diff --git a/static/scripts/mvc/history/history-content-base.js b/static/scripts/mvc/history/history-content-model.js similarity index 100% rename from static/scripts/mvc/history/history-content-base.js rename to static/scripts/mvc/history/history-content-model.js diff --git a/static/scripts/mvc/history/history-contents.js b/static/scripts/mvc/history/history-contents.js index 9c52dc02522..43f272d1174 100644 --- a/static/scripts/mvc/history/history-contents.js +++ b/static/scripts/mvc/history/history-contents.js @@ -1,7 +1,7 @@ define([ - "mvc/history/history-content-base", - "mvc/dataset/hda-model", - "mvc/collection/hdca-model", + "mvc/history/history-content-model", + "mvc/history/hda-model", + "mvc/history/hdca-model", "mvc/base-mvc", "utils/localization" ], function( HISTORY_CONTENT, HDA_MODEL, HDCA_MODEL, BASE_MVC, _l ){ diff --git a/static/scripts/mvc/history/annotated-history-panel.js b/static/scripts/mvc/history/history-panel-annotated.js similarity index 96% rename from static/scripts/mvc/history/annotated-history-panel.js rename to static/scripts/mvc/history/history-panel-annotated.js index feb2d1c5446..2da20797e38 100644 --- a/static/scripts/mvc/history/annotated-history-panel.js +++ b/static/scripts/mvc/history/history-panel-annotated.js @@ -1,13 +1,13 @@ define([ - "mvc/dataset/hda-base", - "mvc/history/readonly-history-panel", + "mvc/history/history-panel", + "mvc/history/hda-li", "utils/localization" -], function( HDA_BASE, READONLY_HPANEL, _l ){ +], function( HPANEL, HDA_LI, _l ){ /* ============================================================================= TODO: ============================================================================= */ -var _super = READONLY_HPANEL.ReadOnlyHistoryPanel; +var _super = HPANEL.ReadOnlyHistoryPanel; // used in history/display.mako and history/embed.mako /** @class View/Controller for a tabular view of the history model. * @name AnnotatedHistoryPanel @@ -31,8 +31,9 @@ var AnnotatedHistoryPanel = _super.extend( className : 'annotated-history-panel', + //TODO:?? possibly into own annotated class /** class to use for constructing the HDA views */ - HDAViewClass : HDA_BASE.HDABaseView, + //HDAViewClass : HDA_LI.HDAListItemView, // ------------------------------------------------------------------------ panel rendering /** render with history data diff --git a/static/scripts/mvc/history/current-history-panel.js b/static/scripts/mvc/history/history-panel-edit-current.js similarity index 98% rename from static/scripts/mvc/history/current-history-panel.js rename to static/scripts/mvc/history/history-panel-edit-current.js index 6475c91ce9a..48ae3479450 100644 --- a/static/scripts/mvc/history/current-history-panel.js +++ b/static/scripts/mvc/history/history-panel-edit-current.js @@ -1,10 +1,9 @@ define([ - "mvc/dataset/hda-edit", - "mvc/history/history-panel", + "mvc/history/history-panel-edit", "mvc/collection/collection-panel", "mvc/base-mvc", "utils/localization" -], function( HDA_EDIT, HISTORY_PANEL, DC_PANEL, BASE_MVC, _l ){ +], function( HPANEL_EDIT, DC_PANEL, BASE_MVC, _l ){ // ============================================================================ /** session storage for history panel preferences (and to maintain state) */ @@ -31,7 +30,7 @@ HistoryPanelPrefs.storageKey = function storageKey(){ TODO: ============================================================================= */ -var _super = HISTORY_PANEL.HistoryPanel; +var _super = HPANEL_EDIT.HistoryPanel; // used in root/index.mako /** @class View/Controller for the user's current history model as used in the history * panel (current right hand panel) of the analysis page. @@ -318,7 +317,8 @@ var CurrentHistoryPanel = _super.extend( var panel = new ( this._getCollectionPanelClass( collectionModel ) )({ model : collectionModel, HDAViewClass : this.HDAViewClass, - parentName : this.model.get( 'name' ) + parentName : this.model.get( 'name' ), + linkTarget : this.linkTarget }); historyView.panelStack.push( panel ); diff --git a/static/scripts/mvc/history/history-panel-edit.js b/static/scripts/mvc/history/history-panel-edit.js new file mode 100644 index 00000000000..1944e52f5dd --- /dev/null +++ b/static/scripts/mvc/history/history-panel-edit.js @@ -0,0 +1,503 @@ +define([ + "mvc/history/history-panel", + "mvc/history/history-contents", + "mvc/dataset/states", + "mvc/history/hda-model", + "mvc/history/hda-li-edit", + "mvc/history/hdca-li-edit", + "mvc/tags", + "mvc/annotations", + "utils/localization" +], function( + HPANEL, + HISTORY_CONTENTS, + STATES, + HDA_MODEL, + HDA_LI_EDIT, + HDCA_LI_EDIT, + TAGS, + ANNOTATIONS, + _l +){ +/* ============================================================================= +TODO: + +============================================================================= */ +var _super = HPANEL.ReadOnlyHistoryPanel; +// base class for current-history-panel and used as-is in history/view.mako +/** @class Editable View/Controller for the history model. + * @name HistoryPanel + * + * Allows: + * (everything ReadOnlyHistoryPanel allows) + * changing the name + * displaying and editing tags and annotations + * multi-selection and operations on mulitple hdas + * + * @augments Backbone.View + * @borrows LoggableMixin#logger as #logger + * @borrows LoggableMixin#log as #log + * @constructs + */ +var HistoryPanel = _super.extend( +/** @lends HistoryPanel.prototype */{ + + /** logger used to record this.log messages, commonly set to console */ + //logger : console, + + /** class to use for constructing the HistoryDatasetAssociation views */ + HDAViewClass : HDA_LI_EDIT.HDAListItemEdit, + /** class to use for constructing the HistoryDatasetCollectionAssociation views */ + HDCAViewClass : HDCA_LI_EDIT.HDCAListItemEdit, + + // ......................................................................... SET UP + /** Set up the view, set up storage, bind listeners to HistoryContents events + * @param {Object} attributes + */ + initialize : function( attributes ){ + attributes = attributes || {}; + + // ---- set up instance vars + /** selected hda ids */ + this.selectedHdaIds = []; + /** last selected hda */ + this.lastSelectedViewId = null; + + /** editor for tags - sub-view */ + this.tagsEditor = null; + /** editor for annotations - sub-view */ + this.annotationEditor = null; + + /** allow user purge of dataset files? */ + this.purgeAllowed = attributes.purgeAllowed || false; + + // states/modes the panel can be in + /** is the panel currently showing the dataset selection controls? */ + this.selecting = attributes.selecting || false; + this.annotationEditorShown = attributes.annotationEditorShown || false; + this.tagsEditorShown = attributes.tagsEditorShown || false; + + _super.prototype.initialize.call( this, attributes ); + }, + + // ------------------------------------------------------------------------ panel rendering + /** listening for history and HDA events */ + _setUpModelEventHandlers : function(){ + _super.prototype._setUpModelEventHandlers.call( this ); + + this.model.on( 'change:nice_size', this.updateHistoryDiskSize, this ); + + this.model.contents.on( 'change:deleted', this._handleHdaDeletionChange, this ); + this.model.contents.on( 'change:visible', this._handleHdaVisibleChange, this ); + this.model.contents.on( 'change:purged', function( hda ){ + // hafta get the new nice-size w/o the purged hda + this.model.fetch(); + }, this ); + }, + + // ------------------------------------------------------------------------ panel rendering + /** render with history data + * In this override, add tags, annotations, and multi select + * @returns {jQuery} dom fragment as temporary container to be swapped out later + */ + renderModel : function( ){ +//TODO: can't call ReadOnlyHistoryPanel? + var $newRender = $( '
' ); + + $newRender.append( HistoryPanel.templates.historyPanel( this.model.toJSON() ) ); + this.$emptyMessage( $newRender ).text( this.emptyMsg ); + if( Galaxy && Galaxy.currUser && Galaxy.currUser.id && Galaxy.currUser.id === this.model.get( 'user_id' ) ){ + this._renderTags( $newRender ); + this._renderAnnotation( $newRender ); + } + // search and select available to both anon/logged-in users + $newRender.find( '.history-secondary-actions' ).prepend( this._renderSelectButton() ); + $newRender.find( '.history-dataset-actions' ).toggle( this.selecting ); + $newRender.find( '.history-secondary-actions' ).prepend( this._renderSearchButton() ); + + this._setUpBehaviours( $newRender ); + + // render hda views (if any and any shown (show_deleted/hidden) + this.renderHdas( $newRender ); + return $newRender; + }, + + /** render the tags sub-view controller */ + _renderTags : function( $where ){ + var panel = this; + this.tagsEditor = new TAGS.TagsEditor({ + model : this.model, + el : $where.find( '.history-controls .tags-display' ), + onshowFirstTime : function(){ this.render(); }, + // show hide hda view tag editors when this is shown/hidden + onshow : function(){ + panel.toggleHDATagEditors( true, panel.fxSpeed ); + }, + onhide : function(){ + panel.toggleHDATagEditors( false, panel.fxSpeed ); + }, + $activator : faIconButton({ + title : _l( 'Edit history tags' ), + classes : 'history-tag-btn', + faIcon : 'fa-tags' + }).appendTo( $where.find( '.history-secondary-actions' ) ) + }); + }, + /** render the annotation sub-view controller */ + _renderAnnotation : function( $where ){ + var panel = this; + this.annotationEditor = new ANNOTATIONS.AnnotationEditor({ + model : this.model, + el : $where.find( '.history-controls .annotation-display' ), + onshowFirstTime : function(){ this.render(); }, + // show hide hda view annotation editors when this is shown/hidden + onshow : function(){ + panel.toggleHDAAnnotationEditors( true, panel.fxSpeed ); + }, + onhide : function(){ + panel.toggleHDAAnnotationEditors( false, panel.fxSpeed ); + }, + $activator : faIconButton({ + title : _l( 'Edit history annotation' ), + classes : 'history-annotate-btn', + faIcon : 'fa-comment' + }).appendTo( $where.find( '.history-secondary-actions' ) ) + }); + }, + + /** button for starting select mode */ + _renderSelectButton : function( $where ){ + return faIconButton({ + title : _l( 'Operations on multiple datasets' ), + classes : 'history-select-btn', + faIcon : 'fa-check-square-o' + }); + }, + + /** Set up HistoryPanel js/widget behaviours + * In this override, add the multi select popup menu and make the name editable + */ + _setUpBehaviours : function( $where ){ + $where = $where || this.$el; + _super.prototype._setUpBehaviours.call( this, $where ); + + // anon users shouldn't have access to any of the following + if( !this.model ){ + return; + } + + // set up the pupup for actions available when multi selecting + this._setUpDatasetActionsPopup( $where ); + + // anon users shouldn't have access to any of the following + if( ( !Galaxy.currUser || Galaxy.currUser.isAnonymous() ) + || ( Galaxy.currUser.id !== this.model.get( 'user_id' ) ) ){ + return; + } + + var panel = this; + $where.find( '.history-name' ) + .attr( 'title', _l( 'Click to rename history' ) ).tooltip({ placement: 'bottom' }) + .make_text_editable({ + on_finish: function( newName ){ + var previousName = panel.model.get( 'name' ); + if( newName && newName !== previousName ){ + panel.$el.find( '.history-name' ).text( newName ); + panel.model.save({ name: newName }) + .fail( function(){ + panel.$el.find( '.history-name' ).text( panel.model.previous( 'name' ) ); + }); + } else { + panel.$el.find( '.history-name' ).text( previousName ); + } + } + }); + }, + + /** return a new popup menu for choosing a multi selection action + * ajax calls made for multiple datasets are queued + */ + _setUpDatasetActionsPopup : function( $where ){ + var panel = this, + actions = [ + { html: _l( 'Hide datasets' ), func: function(){ + var action = HDA_MODEL.HistoryDatasetAssociation.prototype.hide; + panel.getSelectedHdaCollection().ajaxQueue( action ); + } + }, + { html: _l( 'Unhide datasets' ), func: function(){ + var action = HDA_MODEL.HistoryDatasetAssociation.prototype.unhide; + panel.getSelectedHdaCollection().ajaxQueue( action ); + } + }, + { html: _l( 'Delete datasets' ), func: function(){ + var action = HDA_MODEL.HistoryDatasetAssociation.prototype['delete']; + panel.getSelectedHdaCollection().ajaxQueue( action ); + } + }, + { html: _l( 'Undelete datasets' ), func: function(){ + var action = HDA_MODEL.HistoryDatasetAssociation.prototype.undelete; + panel.getSelectedHdaCollection().ajaxQueue( action ); + } + } ]; + if( panel.purgeAllowed ){ + actions.push({ + html: _l( 'Permanently delete datasets' ), func: function(){ + if( confirm( _l( 'This will permanently remove the data in your datasets. Are you sure?' ) ) ){ + var action = HDA_MODEL.HistoryDatasetAssociation.prototype.purge; + panel.getSelectedHdaCollection().ajaxQueue( action ); + } + } + }); + } + actions.push( { + html: _l( 'Build Dataset List (Experimental)' ), func: function() { + panel.getSelectedHdaCollection().promoteToHistoryDatasetCollection( panel.model, "list" ); + } + }); + actions.push( { + // TODO: Only show quick pair if two things selected. + html: _l( 'Build Dataset Pair (Experimental)' ), func: function() { + panel.getSelectedHdaCollection().promoteToHistoryDatasetCollection( panel.model, "paired" ); + } + }); + actions.push( { + // TODO: Only show quick pair if two things selected. + html: _l( 'Build List of Dataset Pairs (Experimental)' ), + func: _.bind( panel._showPairedCollectionModal, panel ) + }); + return new PopupMenu( $where.find( '.history-dataset-action-popup-btn' ), actions ); + }, + + _showPairedCollectionModal : function(){ + var panel = this, + datasets = panel.getSelectedHdaCollection().toJSON().filter( function( content ){ + return content.history_content_type === 'dataset' + && content.state === STATES.OK; + }); + if( datasets.length ){ + require([ 'mvc/collection/paired-collection-creator' ], function( creator ){ + window.creator = creator.pairedCollectionCreatorModal( datasets, { + historyId : panel.model.id + }); + }); + } else { + //Galaxy.modal.show({ + // body : _l( 'No valid datasets were selected' ), + // buttons : { + // 'Ok': function(){ Galaxy.modal.hide(); } + // } + //}); + } + }, + + // ------------------------------------------------------------------------ hda sub-views + /** If this hda is deleted and we're not showing deleted hdas, remove the view + * @param {HistoryDataAssociation} the hda to check + */ + _handleHdaDeletionChange : function( hda ){ + if( hda.get( 'deleted' ) && !this.storage.get( 'show_deleted' ) ){ + this.removeHdaView( this.hdaViews[ hda.id ] ); + } // otherwise, the hdaView rendering should handle it + }, + + + /** If this hda is hidden and we're not showing hidden hdas, remove the view + * @param {HistoryDataAssociation} the hda to check + */ + _handleHdaVisibleChange : function( hda ){ + if( hda.hidden() && !this.storage.get( 'show_hidden' ) ){ + this.removeHdaView( this.hdaViews[ hda.id ] ); + } // otherwise, the hdaView rendering should handle it + }, + + _getContentOptions : function( content ){ + var options = _super.prototype._getContentOptions.call( this, content ); + _.extend( options, { + selectable : this.selecting, + purgeAllowed : this.purgeAllowed, + tagsEditorShown : ( this.tagsEditor && !this.tagsEditor.hidden ), + annotationEditorShown : ( this.annotationEditor && !this.annotationEditor.hidden ) + }); + return options; + }, + + /** Set up HistoryPanel listeners for HDAView events. Currently binds: + * HDAView#body-visible, HDAView#body-hidden to store expanded states + * @param {HDAView} hdaView HDAView (base or edit) to listen to + */ + _setUpHdaListeners : function( hdaView ){ + var historyView = this; + _super.prototype._setUpHdaListeners.call( this, hdaView ); + + // maintain a list of hdas that are selected + hdaView.on( 'selected', function( hdaView, event ){ + if( !event ){ return; } + //console.debug( 'selected', event ); + var selectedIds = []; + //console.debug( historyView.lastSelectedViewId, historyView.hdaViews[ historyView.lastSelectedViewId ] ); + + // shift will select a range, but not set lastSelectedViewId + if( ( event.shiftKey ) + && ( historyView.lastSelectedViewId && _.has( historyView.hdaViews, historyView.lastSelectedViewId ) ) ){ + var lastSelectedView = historyView.hdaViews[ historyView.lastSelectedViewId ]; + selectedIds = historyView.selectDatasetRange( hdaView, lastSelectedView ) + .map( function( view ){ return view.model.id; }); + + // only + } else { + var id = hdaView.model.id; + historyView.lastSelectedViewId = id; + //console.debug( 'lastSelectedViewId:', historyView.lastSelectedViewId ); + selectedIds = [ id ]; + } + //console.debug( 'selectedIds:', selectedIds ); + historyView.selectedHdaIds = _.union( historyView.selectedHdaIds, selectedIds ); + //TODO: might want to use getSelectedHdaViews instead managing these lists with ops + //console.debug( 'selected', historyView.selectedHdaIds ); + }); + hdaView.on( 'de-selected', function( hdaView, event ){ + //console.debug( 'de-selected', event ); + var id = hdaView.model.id; + historyView.selectedHdaIds = _.without( historyView.selectedHdaIds, id ); + //console.debug( 'de-selected', historyView.selectedHdaIds ); + }); + }, + + /** toggle the visibility of each hdaView's tagsEditor applying all the args sent to this function */ + toggleHDATagEditors : function( showOrHide ){ + var args = arguments; + _.each( this.hdaViews, function( hdaView ){ + if( hdaView.tagsEditor ){ + hdaView.tagsEditor.toggle.apply( hdaView.tagsEditor, args ); + } + }); + }, + + /** toggle the visibility of each hdaView's annotationEditor applying all the args sent to this function */ + toggleHDAAnnotationEditors : function( showOrHide ){ + var args = arguments; + _.each( this.hdaViews, function( hdaView ){ + if( hdaView.annotationEditor ){ + hdaView.annotationEditor.toggle.apply( hdaView.annotationEditor, args ); + } + }); + }, + + /** Remove a view from the panel and if the panel is now empty, re-render + * @param {Int} the id of the hdaView to remove + */ + removeHdaView : function( hdaView ){ + if( !hdaView ){ return; } + + var panel = this; + hdaView.$el.fadeOut( panel.fxSpeed, function(){ + hdaView.off(); + hdaView.remove(); + delete panel.hdaViews[ hdaView.model.id ]; + if( _.isEmpty( panel.hdaViews ) ){ + panel.trigger( 'empty-history', panel ); + panel._renderEmptyMsg(); + } + }); + }, + + // ------------------------------------------------------------------------ panel events + /** event map */ + events : _.extend( _.clone( _super.prototype.events ), { + 'click .history-select-btn' : 'toggleSelectors', + 'click .history-select-all-datasets-btn' : 'selectAllDatasets', + 'click .history-deselect-all-datasets-btn' : 'deselectAllDatasets' + }), + + /** Update the history size display (curr. upper right of panel). + */ + updateHistoryDiskSize : function(){ + this.$el.find( '.history-size' ).text( this.model.get( 'nice_size' ) ); + }, + + // ........................................................................ multi-select of hdas +//TODO: to toggle showOrHide pattern + /** show selectors on all visible hdas and associated controls */ + showSelectors : function( speed ){ + speed = ( speed !== undefined )?( speed ):( this.fxSpeed ); + this.selecting = true; + this.$( '.history-dataset-actions' ).slideDown( speed ); + _.each( this.hdaViews, function( view ){ + view.showSelector(); + }); + this.selectedHdaIds = []; + this.lastSelectedViewId = null; + }, + + /** hide selectors on all visible hdas and associated controls */ + hideSelectors : function( speed ){ + speed = ( speed !== undefined )?( speed ):( this.fxSpeed ); + this.selecting = false; + this.$( '.history-dataset-actions' ).slideUp( speed ); + _.each( this.hdaViews, function( view ){ + view.hideSelector(); + }); + this.selectedHdaIds = []; + this.lastSelectedViewId = null; + }, + + /** show or hide selectors on all visible hdas and associated controls */ + toggleSelectors : function(){ + if( !this.selecting ){ + this.showSelectors(); + } else { + this.hideSelectors(); + } + }, + + /** select all visible hdas */ + selectAllDatasets : function( event ){ + _.each( this.hdaViews, function( view ){ + view.select( event ); + }); + }, + + /** deselect all visible hdas */ + deselectAllDatasets : function( event ){ + this.lastSelectedViewId = null; + _.each( this.hdaViews, function( view ){ + view.deselect( event ); + }); + }, + + /** select a range of datasets between A and B */ + selectDatasetRange : function( viewA, viewB ){ + var range = this.hdaViewRange( viewA, viewB ); + _.each( range, function( view ){ + view.select(); + }); + return range; + }, + + /** return an array of all currently selected hdas */ + getSelectedHdaViews : function(){ + return _.filter( this.hdaViews, function( v ){ + return v.selected; + }); + }, + + /** return an HdaCollection of the models of all currenly selected hdas */ + getSelectedHdaCollection : function(){ + return new HISTORY_CONTENTS.HistoryContents( _.map( this.getSelectedHdaViews(), function( hdaView ){ + return hdaView.model; + }), { historyId: this.model.id }); + }, + + // ........................................................................ misc + /** Return a string rep of the history */ + toString : function(){ + return 'HistoryPanel(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')'; + } +}); + +//============================================================================== + return { + HistoryPanel : HistoryPanel + }; +}); diff --git a/static/scripts/mvc/history/history-panel.js b/static/scripts/mvc/history/history-panel.js index add96017367..18f69dd3c14 100644 --- a/static/scripts/mvc/history/history-panel.js +++ b/static/scripts/mvc/history/history-panel.js @@ -1,137 +1,511 @@ define([ - "mvc/dataset/states", - "mvc/dataset/hda-model", - "mvc/dataset/hda-base", - "mvc/dataset/hda-edit", - "mvc/dataset/dataset-list-element", - "mvc/dataset/editable-dataset-list-element", - "mvc/collection/dataset-collection-base", - "mvc/collection/dataset-collection-edit", - "mvc/collection/hdca-base", - "mvc/collection/hdca-edit", - "mvc/history/history-contents", - "mvc/history/readonly-history-panel", - "mvc/tags", - "mvc/annotations", + "mvc/history/history-model", + "mvc/history/hda-li", + "mvc/history/hdca-li", + "mvc/user/user-model", + "mvc/base-mvc", "utils/localization" -], function( - STATES, - HDA_MODEL, - HDA_BASE, - HDA_EDIT, - DATASET_LI, - EDIT_DATASET_LI, - DC_BASE, - DC_EDIT, - HDCA_BASE, - HDCA_EDIT, - HISTORY_CONTENTS, - READONLY_PANEL, - TAGS, - ANNOTATIONS, - _l -){ +], function( HISTORY_MODEL, HDA_LI, HDCA_LI, USER, BASE_MVC, _l ){ +// ============================================================================ +/** session storage for individual history preferences */ +var HistoryPrefs = BASE_MVC.SessionStorageModel.extend({ + defaults : { +//TODO:?? expandedHdas to array? + expandedHdas : {}, + //TODO:?? move to user? + show_deleted : false, + show_hidden : false + //TODO: add scroll position? + }, + /** add an hda id to the hash of expanded hdas */ + addExpandedHda : function( model ){ + var key = 'expandedHdas'; + this.save( key, _.extend( this.get( key ), _.object([ model.id ], [ model.get( 'id' ) ]) ) ); + }, + /** remove an hda id from the hash of expanded hdas */ + removeExpandedHda : function( model ){ + var key = 'expandedHdas'; + this.save( key, _.omit( this.get( key ), model.id ) ); + }, + toString : function(){ + return 'HistoryPrefs(' + this.id + ')'; + } +}); +// class lvl for access w/o instantiation +HistoryPrefs.storageKeyPrefix = 'history:'; + +/** key string to store each histories settings under */ +HistoryPrefs.historyStorageKey = function historyStorageKey( historyId ){ + if( !historyId ){ + throw new Error( 'HistoryPrefs.historyStorageKey needs valid id: ' + historyId ); + } + // single point of change + return ( HistoryPrefs.storageKeyPrefix + historyId ); +}; +/** return the existing storage for the history with the given id (or create one if it doesn't exist) */ +HistoryPrefs.get = function get( historyId ){ + return new HistoryPrefs({ id: HistoryPrefs.historyStorageKey( historyId ) }); +}; +/** clear all history related items in sessionStorage */ +HistoryPrefs.clearAll = function clearAll( historyId ){ + for( var key in sessionStorage ){ + if( key.indexOf( HistoryPrefs.storageKeyPrefix ) === 0 ){ + sessionStorage.removeItem( key ); + } + } +}; + + /* ============================================================================= TODO: ============================================================================= */ -var _super = READONLY_PANEL.ReadOnlyHistoryPanel; -// base class for current-history-panel and used as-is in history/view.mako -/** @class Editable View/Controller for the history model. +// base model and used as-is in history/view.mako +/** @class non-editable, read-only View/Controller for a history model. * @name HistoryPanel * * Allows: - * (everything ReadOnlyHistoryPanel allows) + * changing the loaded history + * searching hdas + * displaying data, info, and download + * Does not allow: * changing the name - * displaying and editing tags and annotations - * multi-selection and operations on mulitple hdas * * @augments Backbone.View * @borrows LoggableMixin#logger as #logger * @borrows LoggableMixin#log as #log * @constructs */ -var HistoryPanel = _super.extend( -/** @lends HistoryPanel.prototype */{ +var ReadOnlyHistoryPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend( +/** @lends ReadOnlyHistoryPanel.prototype */{ /** logger used to record this.log messages, commonly set to console */ // comment this out to suppress log output //logger : console, /** class to use for constructing the HDA views */ - //HDAViewClass : DATASET_LI.DatasetListItemView, - //HDAViewClass : EDIT_DATASET_LI.EditableDatasetListItemView, - //HDAViewClass : HDA_BASE.HDABaseView, - HDAViewClass : HDA_EDIT.HDAEditView, + HDAViewClass : HDA_LI.HDAListItemView, + HDCAViewClass : HDCA_LI.HDCAListItemView, - //HDCAViewClass : DC_BASE.DCBaseView, - //HDCAViewClass : DC_EDIT.DCEditView, - //HDCAViewClass : HDCA_BASE.HDCABaseView, - HDCAViewClass : HDCA_EDIT.HDCAEditView, + tagName : 'div', + className : 'history-panel', + + /** (in ms) that jquery effects will use */ + fxSpeed : 'fast', + + /** string to display when the model has no hdas */ + emptyMsg : _l( 'This history is empty' ), + /** string to no hdas match the search terms */ + noneFoundMsg : _l( 'No matching datasets found' ), // ......................................................................... SET UP /** Set up the view, set up storage, bind listeners to HistoryContents events - * @param {Object} attributes + * @param {Object} attributes optional settings for the panel */ initialize : function( attributes ){ attributes = attributes || {}; + // set the logger if requested + if( attributes.logger ){ + this.logger = attributes.logger; + } + this.log( this + '.initialize:', attributes ); - // ---- set up instance vars - /** selected hda ids */ - this.selectedHdaIds = []; - /** last selected hda */ - this.lastSelectedViewId = null; + // ---- instance vars + // control contents/behavior based on where (and in what context) the panel is being used + /** where should pages from links be displayed? (default to new tab/window) */ + this.linkTarget = attributes.linkTarget || '_blank'; + /** how quickly should jquery fx run? */ + this.fxSpeed = _.has( attributes, 'fxSpeed' )?( attributes.fxSpeed ):( this.fxSpeed ); - /** editor for tags - sub-view */ - this.tagsEditor = null; - /** editor for annotations - sub-view */ - this.annotationEditor = null; + /** filters for displaying hdas */ + this.filters = []; + this.searchFor = ''; - /** allow user purge of dataset files? */ - this.purgeAllowed = attributes.purgeAllowed || false; + /** a function to locate the container to scroll to effectively scroll the panel */ +//TODO: rename + this.findContainerFn = attributes.findContainerFn; + // generally this is $el.parent() - but may be $el or $el.parent().parent() depending on the context - // states/modes the panel can be in - /** is the panel currently showing the dataset selection controls? */ - this.selecting = attributes.selecting || false; - this.annotationEditorShown = attributes.annotationEditorShown || false; - this.tagsEditorShown = attributes.tagsEditorShown || false; + // ---- sub views and saved elements + /** map of hda model ids to hda views */ + this.hdaViews = {}; + /** loading indicator */ + this.indicator = new LoadingIndicator( this.$el ); - _super.prototype.initialize.call( this, attributes ); + // ----- set up panel listeners, handle models passed on init, and call any ready functions + this._setUpListeners(); + // don't render when setting the first time + var modelOptions = _.pick( attributes, 'initiallyExpanded', 'show_deleted', 'show_hidden' ); + this.setModel( this.model, modelOptions, false ); +//TODO: remove? + if( attributes.onready ){ + attributes.onready.call( this ); + } }, - // ------------------------------------------------------------------------ panel rendering + /** create any event listeners for the panel + * @fires: rendered:initial on the first render + * @fires: empty-history when switching to a history with no HDAs or creating a new history + */ + _setUpListeners : function(){ + this.on( 'error', function( model, xhr, options, msg, details ){ + this.errorHandler( model, xhr, options, msg, details ); + }); + + this.on( 'loading-history', function(){ + // show the loading indicator when loading a new history starts... + this._showLoadingIndicator( 'loading history...', 40 ); + }); + this.on( 'loading-done', function(){ + // ...hiding it again when loading is done (or there's been an error) + this._hideLoadingIndicator( 40 ); + if( _.isEmpty( this.hdaViews ) ){ + this.trigger( 'empty-history', this ); + } + }); + + // throw the first render up as a diff namespace using once (for outside consumption) + this.once( 'rendered', function(){ + this.trigger( 'rendered:initial', this ); + return false; + }); + + // debugging + if( this.logger ){ + this.on( 'all', function( event ){ + this.log( this + '', arguments ); + }, this ); + } + return this; + }, + + //TODO: see base-mvc + //onFree : function(){ + // _.each( this.hdaViews, function( view, modelId ){ + // view.free(); + // }); + // this.hdaViews = null; + //}, + + // ........................................................................ error handling + /** Event handler for errors (from the panel, the history, or the history's HDAs) + * @param {Model or View} model the (Backbone) source of the error + * @param {XMLHTTPRequest} xhr any ajax obj. assoc. with the error + * @param {Object} options the options map commonly used with bbone ajax + * @param {String} msg optional message passed to ease error location + * @param {Object} msg optional object containing error details + */ + errorHandler : function( model, xhr, options, msg, details ){ + this.error( model, xhr, options, msg, details ); +//TODO: getting JSON parse errors from jq migrate + + // interrupted ajax + if( xhr && xhr.status === 0 && xhr.readyState === 0 ){ + + // bad gateway + } else if( xhr && xhr.status === 502 ){ +//TODO: gmail style 'reconnecting in Ns' + + // otherwise, show an error message inside the panel + } else { + var parsed = this._parseErrorMessage( model, xhr, options, msg, details ); + // it's possible to have a triggered error before the message container is rendered - wait for it to show + if( !this.$messages().is( ':visible' ) ){ + this.once( 'rendered', function(){ + this.displayMessage( 'error', parsed.message, parsed.details ); + }); + } else { + this.displayMessage( 'error', parsed.message, parsed.details ); + } + } + }, + + /** Parse an error event into an Object usable by displayMessage based on the parameters + * note: see errorHandler for more info on params + */ + _parseErrorMessage : function( model, xhr, options, msg, details ){ + var user = Galaxy.currUser, + // add the args (w/ some extra info) into an obj + parsed = { + message : this._bePolite( msg ), + details : { + user : ( user instanceof USER.User )?( user.toJSON() ):( user + '' ), + source : ( model instanceof Backbone.Model )?( model.toJSON() ):( model + '' ), + xhr : xhr, + options : ( xhr )?( _.omit( options, 'xhr' ) ):( options ) + } + }; + // add any extra details passed in + _.extend( parsed.details, details || {} ); + // fancy xhr.header parsing (--> obj) + if( xhr && _.isFunction( xhr.getAllResponseHeaders ) ){ + var responseHeaders = xhr.getAllResponseHeaders(); + responseHeaders = _.compact( responseHeaders.split( '\n' ) ); + responseHeaders = _.map( responseHeaders, function( header ){ + return header.split( ': ' ); + }); + parsed.details.xhr.responseHeaders = _.object( responseHeaders ); + } + return parsed; + }, + + /** Modify an error message to be fancy and wear a monocle. */ + _bePolite : function( msg ){ + msg = msg || _l( 'An error occurred while getting updates from the server' ); + return msg + '. ' + _l( 'Please contact a Galaxy administrator if the problem persists' ) + '.'; + }, + + // ------------------------------------------------------------------------ loading history/hda models + //NOTE: all the following fns replace the existing history model with a new model + // (in the following 'details' refers to the full set of hda api data (urls, display_apps, misc_info, etc.) + // - hdas w/o details will have summary data only (name, hid, deleted, visible, state, etc.)) + + /** loads a history & hdas w/ details (but does not make them the current history) */ + loadHistoryWithHDADetails : function( historyId, attributes, historyFn, hdaFn ){ + //this.info( 'loadHistoryWithHDADetails:', historyId, attributes, historyFn, hdaFn ); + var hdaDetailIds = function( historyData ){ + // will be called to get hda ids that need details from the api +//TODO: non-visible HDAs are getting details loaded... either stop loading them at all or filter ids thru isVisible + return _.values( HistoryPrefs.get( historyData.id ).get( 'expandedHdas' ) ); + }; + return this.loadHistory( historyId, attributes, historyFn, hdaFn, hdaDetailIds ); + }, + + /** loads a history & hdas w/ NO details (but does not make them the current history) */ + loadHistory : function( historyId, attributes, historyFn, hdaFn, hdaDetailIds ){ + var panel = this; + attributes = attributes || {}; + + panel.trigger( 'loading-history', panel ); + //this.info( 'loadHistory:', historyId, attributes, historyFn, hdaFn, hdaDetailIds ); + var xhr = HISTORY_MODEL.History.getHistoryData( historyId, { + historyFn : historyFn, + hdaFn : hdaFn, + hdaDetailIds : attributes.initiallyExpanded || hdaDetailIds + }); + + return panel._loadHistoryFromXHR( xhr, attributes ) + .fail( function( xhr, where, history ){ + // throw an error up for the error handler +//TODO: difficult to localize - use template + panel.trigger( 'error', panel, xhr, attributes, _l( 'An error was encountered while ' + where ), + { historyId: historyId, history: history || {} }); + }) + .always( function(){ + // bc _hideLoadingIndicator relies on this firing + panel.trigger( 'loading-done', panel ); + }); + }, + + /** given an xhr that will provide both history and hda data, pass data to set model or handle xhr errors */ + _loadHistoryFromXHR : function( xhr, attributes ){ + var panel = this; + xhr.then( function( historyJSON, hdaJSON ){ + panel.JSONToModel( historyJSON, hdaJSON, attributes ); + }); + xhr.fail( function( xhr, where ){ + // always render - whether we get a model or not + panel.render(); + }); + return xhr; + }, + + + /** create a new history model from JSON and call setModel on it */ + JSONToModel : function( newHistoryJSON, newHdaJSON, attributes ){ + this.log( 'JSONToModel:', newHistoryJSON, newHdaJSON, attributes ); +//TODO: Maybe better in History? + attributes = attributes || {}; + //this.log( 'JSONToModel:', newHistoryJSON, newHdaJSON.length, attributes ); + +// // set up the new model and render +// if( Galaxy && Galaxy.currUser ){ +////TODO: global +// newHistoryJSON.user = Galaxy.currUser.toJSON(); +// } + var model = new HISTORY_MODEL.History( newHistoryJSON, newHdaJSON, attributes ); + this.setModel( model ); + return this; + }, + + /** release/free/shutdown old models and set up panel for new models + * @fires new-model with the panel as parameter + */ + setModel : function( model, attributes, render ){ + attributes = attributes || {}; + render = ( render !== undefined )?( render ):( true ); + this.log( 'setModel:', model, attributes, render ); + + this.freeModel(); + this.selectedHdaIds = []; + + if( model ){ + // set up the new model with user, logger, storage, events +// if( Galaxy && Galaxy.currUser ){ +////TODO: global +// model.user = Galaxy.currUser.toJSON(); +// } + this.model = model; + if( this.logger ){ + this.model.logger = this.logger; + } + this._setUpWebStorage( attributes.initiallyExpanded, attributes.show_deleted, attributes.show_hidden ); + this._setUpModelEventHandlers(); + this.trigger( 'new-model', this ); + } + + if( render ){ +//TODO: remove? + this.render(); + } + return this; + }, + + /** free the current model and all listeners for it, free any hdaViews for the model */ + freeModel : function(){ + // stop/release the previous model, and clear cache to hda sub-views + if( this.model ){ + this.model.clearUpdateTimeout(); + this.stopListening( this.model ); + this.stopListening( this.model.contents ); + //TODO: see base-mvc + //this.model.free(); + } + this.freeHdaViews(); + return this; + }, + + /** free any hdaViews the panel has */ + freeHdaViews : function(){ + this.hdaViews = {}; + return this; + }, + + // ------------------------------------------------------------------------ browser stored prefs + /** Set up client side storage. Currently PersistanStorage keyed under 'HistoryPanel.' + * @param {Object} initiallyExpanded + * @param {Boolean} show_deleted whether to show deleted HDAs (overrides stored) + * @param {Boolean} show_hidden + * @see PersistentStorage + */ + _setUpWebStorage : function( initiallyExpanded, show_deleted, show_hidden ){ + //this.log( '_setUpWebStorage', initiallyExpanded, show_deleted, show_hidden ); + this.storage = new HistoryPrefs({ + id: HistoryPrefs.historyStorageKey( this.model.get( 'id' ) ) + }); + + // expanded Hdas is a map of hda.ids -> a boolean repr'ing whether this hda's body is already expanded + // store any pre-expanded ids passed in + if( _.isObject( initiallyExpanded ) ){ + this.storage.set( 'exandedHdas', initiallyExpanded ); + } + + // get the show_deleted/hidden settings giving priority to values passed in, using web storage otherwise + // if the page has specifically requested show_deleted/hidden, these will be either true or false + // (as opposed to undefined, null) - and we give priority to that setting + if( _.isBoolean( show_deleted ) ){ + this.storage.set( 'show_deleted', show_deleted ); + } + if( _.isBoolean( show_hidden ) ){ + this.storage.set( 'show_hidden', show_hidden ); + } + + this.trigger( 'new-storage', this.storage, this ); + this.log( this + ' (init\'d) storage:', this.storage.get() ); + return this; + }, + + // ------------------------------------------------------------------------ history/hda event listening /** listening for history and HDA events */ _setUpModelEventHandlers : function(){ - _super.prototype._setUpModelEventHandlers.call( this ); + // ---- hdas + // bind events from the model's hda collection + // note: don't listen to the hdas for errors, history will pass that to us + //this.model.contents.on( 'reset', this.addAll, this ); + this.model.contents.on( 'add', this.addContentView, this ); - this.model.on( 'change:nice_size', this.updateHistoryDiskSize, this ); - - this.model.contents.on( 'change:deleted', this._handleHdaDeletionChange, this ); - this.model.contents.on( 'change:visible', this._handleHdaVisibleChange, this ); - this.model.contents.on( 'change:purged', function( hda ){ - // hafta get the new nice-size w/o the purged hda - this.model.fetch(); + // on a model error - bounce it up to the panel and remove it from the model + this.model.on( 'error error:contents', function( model, xhr, options, msg ){ + this.errorHandler( model, xhr, options, msg ); }, this ); + return this; }, // ------------------------------------------------------------------------ panel rendering + /** Render urls, historyPanel body, and hdas (if any are shown) + * @fires: rendered when the panel is attached and fully visible + * @see Backbone.View#render + */ + render : function( speed, callback ){ + this.log( 'render:', speed, callback ); + // send a speed of 0 to have no fade in/out performed + speed = ( speed === undefined )?( this.fxSpeed ):( speed ); + var panel = this, + $newRender; + + // handle the possibility of no model (can occur if fetching the model returns an error) + if( this.model ){ + $newRender = this.renderModel(); + } else { + $newRender = this.renderWithoutModel(); + } + + // fade out existing, swap with the new, fade in, set up behaviours + $( panel ).queue( 'fx', [ + function( next ){ + if( speed && panel.$el.is( ':visible' ) ){ + panel.$el.fadeOut( speed, next ); + } else { + next(); + } + }, + function( next ){ + // swap over from temp div newRender + panel.$el.empty(); + if( $newRender ){ + panel.$el.append( $newRender.children() ); + } + next(); + }, + function( next ){ + if( speed && !panel.$el.is( ':visible' ) ){ + panel.$el.fadeIn( speed, next ); + } else { + next(); + } + }, + function( next ){ + //TODO: ideally, these would be set up before the fade in (can't because of async save text) + if( callback ){ callback.call( this ); } + panel.trigger( 'rendered', this ); + next(); + } + ]); + return this; + }, + + /** render without history data + * @returns {jQuery} dom fragment with message container only + */ + renderWithoutModel : function( ){ + // we'll always need the message container + var $newRender = $( '
' ), + $msgContainer = $( '
' ).addClass( 'message-container' ) + .css({ 'margin': '4px' }); + return $newRender.append( $msgContainer ); + }, + /** render with history data - * In this override, add tags, annotations, and multi select * @returns {jQuery} dom fragment as temporary container to be swapped out later */ renderModel : function( ){ -//TODO: can't call ReadOnlyHistoryPanel? + // tmp div for final swap in render var $newRender = $( '
' ); - $newRender.append( HistoryPanel.templates.historyPanel( this.model.toJSON() ) ); + // render based on anonymity, set up behaviors + $newRender.append( ReadOnlyHistoryPanel.templates.historyPanel( this.model.toJSON() ) ); this.$emptyMessage( $newRender ).text( this.emptyMsg ); - if( Galaxy && Galaxy.currUser && Galaxy.currUser.id && Galaxy.currUser.id === this.model.get( 'user_id' ) ){ - this._renderTags( $newRender ); - this._renderAnnotation( $newRender ); - } // search and select available to both anon/logged-in users - $newRender.find( '.history-secondary-actions' ).prepend( this._renderSelectButton() ); - $newRender.find( '.history-dataset-actions' ).toggle( this.selecting ); $newRender.find( '.history-secondary-actions' ).prepend( this._renderSearchButton() ); this._setUpBehaviours( $newRender ); @@ -141,204 +515,131 @@ var HistoryPanel = _super.extend( return $newRender; }, - /** render the tags sub-view controller */ - _renderTags : function( $where ){ - var panel = this; - this.tagsEditor = new TAGS.TagsEditor({ - model : this.model, - el : $where.find( '.history-controls .tags-display' ), - onshowFirstTime : function(){ this.render(); }, - // show hide hda view tag editors when this is shown/hidden - onshow : function(){ - panel.toggleHDATagEditors( true, panel.fxSpeed ); - }, - onhide : function(){ - panel.toggleHDATagEditors( false, panel.fxSpeed ); - }, - $activator : faIconButton({ - title : _l( 'Edit history tags' ), - classes : 'history-tag-btn', - faIcon : 'fa-tags' - }).appendTo( $where.find( '.history-secondary-actions' ) ) - }); - }, - /** render the annotation sub-view controller */ - _renderAnnotation : function( $where ){ - var panel = this; - this.annotationEditor = new ANNOTATIONS.AnnotationEditor({ - model : this.model, - el : $where.find( '.history-controls .annotation-display' ), - onshowFirstTime : function(){ this.render(); }, - // show hide hda view annotation editors when this is shown/hidden - onshow : function(){ - panel.toggleHDAAnnotationEditors( true, panel.fxSpeed ); - }, - onhide : function(){ - panel.toggleHDAAnnotationEditors( false, panel.fxSpeed ); - }, - $activator : faIconButton({ - title : _l( 'Edit history annotation' ), - classes : 'history-annotate-btn', - faIcon : 'fa-comment' - }).appendTo( $where.find( '.history-secondary-actions' ) ) - }); - }, - - /** button for starting select mode */ - _renderSelectButton : function( $where ){ - return faIconButton({ - title : _l( 'Operations on multiple datasets' ), - classes : 'history-select-btn', - faIcon : 'fa-check-square-o' - }); - }, - - /** Set up HistoryPanel js/widget behaviours - * In this override, add the multi select popup menu and make the name editable - */ - _setUpBehaviours : function( $where ){ - $where = $where || this.$el; - _super.prototype._setUpBehaviours.call( this, $where ); - - // anon users shouldn't have access to any of the following - if( !this.model ){ - return; - } - - // set up the pupup for actions available when multi selecting - this._setUpDatasetActionsPopup( $where ); - - // anon users shouldn't have access to any of the following - if( ( !Galaxy.currUser || Galaxy.currUser.isAnonymous() ) - || ( Galaxy.currUser.id !== this.model.get( 'user_id' ) ) ){ - return; - } - - var panel = this; - $where.find( '.history-name' ) - .attr( 'title', _l( 'Click to rename history' ) ).tooltip({ placement: 'bottom' }) - .make_text_editable({ - on_finish: function( newName ){ - var previousName = panel.model.get( 'name' ); - if( newName && newName !== previousName ){ - panel.$el.find( '.history-name' ).text( newName ); - panel.model.save({ name: newName }) - .fail( function(){ - panel.$el.find( '.history-name' ).text( panel.model.previous( 'name' ) ); - }); - } else { - panel.$el.find( '.history-name' ).text( previousName ); - } - } - }); - }, - - /** return a new popup menu for choosing a multi selection action - * ajax calls made for multiple datasets are queued - */ - _setUpDatasetActionsPopup : function( $where ){ + /** render the empty/none-found message */ + _renderEmptyMsg : function( $whereTo ){ var panel = this, - actions = [ - { html: _l( 'Hide datasets' ), func: function(){ - var action = HDA_MODEL.HistoryDatasetAssociation.prototype.hide; - panel.getSelectedHdaCollection().ajaxQueue( action ); - } - }, - { html: _l( 'Unhide datasets' ), func: function(){ - var action = HDA_MODEL.HistoryDatasetAssociation.prototype.unhide; - panel.getSelectedHdaCollection().ajaxQueue( action ); - } - }, - { html: _l( 'Delete datasets' ), func: function(){ - var action = HDA_MODEL.HistoryDatasetAssociation.prototype['delete']; - panel.getSelectedHdaCollection().ajaxQueue( action ); - } - }, - { html: _l( 'Undelete datasets' ), func: function(){ - var action = HDA_MODEL.HistoryDatasetAssociation.prototype.undelete; - panel.getSelectedHdaCollection().ajaxQueue( action ); - } - } ]; - if( panel.purgeAllowed ){ - actions.push({ - html: _l( 'Permanently delete datasets' ), func: function(){ - if( confirm( _l( 'This will permanently remove the data in your datasets. Are you sure?' ) ) ){ - var action = HDA_MODEL.HistoryDatasetAssociation.prototype.purge; - panel.getSelectedHdaCollection().ajaxQueue( action ); - } - } - }); - } - actions.push( { - html: _l( 'Build Dataset List (Experimental)' ), func: function() { - panel.getSelectedHdaCollection().promoteToHistoryDatasetCollection( panel.model, "list" ); - } - }); - actions.push( { - // TODO: Only show quick pair if two things selected. - html: _l( 'Build Dataset Pair (Experimental)' ), func: function() { - panel.getSelectedHdaCollection().promoteToHistoryDatasetCollection( panel.model, "paired" ); - } - }); - actions.push( { - // TODO: Only show quick pair if two things selected. - html: _l( 'Build List of Dataset Pairs (Experimental)' ), - func: _.bind( panel._showPairedCollectionModal, panel ) - }); - return new PopupMenu( $where.find( '.history-dataset-action-popup-btn' ), actions ); - }, + $emptyMsg = panel.$emptyMessage( $whereTo ); + + if( !_.isEmpty( panel.hdaViews ) ){ + $emptyMsg.hide(); + + } else if( panel.searchFor ){ + $emptyMsg.text( panel.noneFoundMsg ).show(); - _showPairedCollectionModal : function(){ - var panel = this, - datasets = panel.getSelectedHdaCollection().toJSON().filter( function( content ){ - return content.history_content_type === 'dataset' - && content.state === STATES.OK; - }); - if( datasets.length ){ - require([ 'mvc/collection/paired-collection-creator' ], function( creator ){ - window.creator = creator.pairedCollectionCreatorModal( datasets, { - historyId : panel.model.id - }); - }); } else { - //Galaxy.modal.show({ - // body : _l( 'No valid datasets were selected' ), - // buttons : { - // 'Ok': function(){ Galaxy.modal.hide(); } - // } - //}); + $emptyMsg.text( panel.emptyMsg ).show(); } + return this; + }, + + /** button for opening search */ + _renderSearchButton : function( $where ){ + return faIconButton({ + title : _l( 'Search datasets' ), + classes : 'history-search-btn', + faIcon : 'fa-search' + }); + }, + + /** Set up HistoryPanel js/widget behaviours */ + _setUpBehaviours : function( $where ){ + //TODO: these should be either sub-MVs, or handled by events + $where = $where || this.$el; + $where.find( '[title]' ).tooltip({ placement: 'bottom' }); + this._setUpSearchInput( $where.find( '.history-search-controls .history-search-input' ) ); + return this; + }, + + // ------------------------------------------------------------------------ sub-$element shortcuts + /** the scroll container for this panel - can be $el, $el.parent(), or grandparent depending on context */ + $container : function(){ + return ( this.findContainerFn )?( this.findContainerFn.call( this ) ):( this.$el.parent() ); + }, + /** where hdaViews are attached */ + $datasetsList : function( $where ){ + return ( $where || this.$el ).find( '.datasets-list' ); + }, + /** container where panel messages are attached */ + $messages : function( $where ){ + return ( $where || this.$el ).find( '.message-container' ); + }, + /** the message displayed when no hdaViews can be shown (no hdas, none matching search) */ + $emptyMessage : function( $where ){ + return ( $where || this.$el ).find( '.empty-history-message' ); }, // ------------------------------------------------------------------------ hda sub-views - /** If this hda is deleted and we're not showing deleted hdas, remove the view - * @param {HistoryDataAssociation} the hda to check + /** Set up/render a view for each HDA to be shown, init with model and listeners. + * HDA views are cached to the map this.hdaViews (using the model.id as key). + * @param {jQuery} $whereTo what dom element to prepend the HDA views to + * @returns the number of visible hda views */ - _handleHdaDeletionChange : function( hda ){ - if( hda.get( 'deleted' ) && !this.storage.get( 'show_deleted' ) ){ - this.removeHdaView( this.hdaViews[ hda.id ] ); - } // otherwise, the hdaView rendering should handle it + renderHdas : function( $whereTo ){ + $whereTo = $whereTo || this.$el; + var panel = this, + newHdaViews = {}, + // only render the shown hdas + //TODO: switch to more general filtered pattern + visibleHdas = this.model.contents.getVisible( + this.storage.get( 'show_deleted' ), + this.storage.get( 'show_hidden' ), + this.filters + ); + //this.log( 'renderHdas, visibleHdas:', visibleHdas, $whereTo ); +//TODO: prepend to sep div, add as one + + this.$datasetsList( $whereTo ).empty(); + + if( visibleHdas.length ){ + visibleHdas.each( function( hda ){ + // render it (NOTE: reverse order, newest on top (prepend)) + var hdaId = hda.id, + hdaView = panel._createContentView( hda ); + newHdaViews[ hdaId ] = hdaView; + // persist selection + if( _.contains( panel.selectedHdaIds, hdaId ) ){ + hdaView.selected = true; + } + panel.attachContentView( hdaView.render(), $whereTo ); + }); + } + this.hdaViews = newHdaViews; + this._renderEmptyMsg( $whereTo ); + return this.hdaViews; }, - - /** If this hda is hidden and we're not showing hidden hdas, remove the view - * @param {HistoryDataAssociation} the hda to check + /** Create an HDA view for the given HDA and set up listeners (but leave attachment for addHdaView) + * @param {HistoryDatasetAssociation} hda */ - _handleHdaVisibleChange : function( hda ){ - if( hda.hidden() && !this.storage.get( 'show_hidden' ) ){ - this.removeHdaView( this.hdaViews[ hda.id ] ); - } // otherwise, the hdaView rendering should handle it + _createContentView : function( content ){ + var ContentClass = this._getContentClass( content ), + options = _.extend( this._getContentOptions( content ), { + model : content + }), + contentView = new ContentClass( options ); + this._setUpHdaListeners( contentView ); + return contentView; + }, + + _getContentClass : function( content ){ + var contentType = content.get( "history_content_type" ); + switch( contentType ){ + case 'dataset': + return this.HDAViewClass; + case 'dataset_collection': + return this.HDCAViewClass; + } + throw new TypeError( 'Unknown history_content_type: ' + contentType ); }, _getContentOptions : function( content ){ - var options = _super.prototype._getContentOptions.call( this, content ); - _.extend( options, { - selectable : this.selecting, - purgeAllowed : this.purgeAllowed, - tagsEditorShown : ( this.tagsEditor && !this.tagsEditor.hidden ), - annotationEditorShown : ( this.annotationEditor && !this.annotationEditor.hidden ) - }); - return options; + return { + linkTarget : this.linkTarget, + expanded : !!this.storage.get( 'expandedHdas' )[ content.id ], + //draggable : true, + hasUser : this.model.ownedByCurrUser(), + logger : this.logger + }; }, /** Set up HistoryPanel listeners for HDAView events. Currently binds: @@ -346,177 +647,474 @@ var HistoryPanel = _super.extend( * @param {HDAView} hdaView HDAView (base or edit) to listen to */ _setUpHdaListeners : function( hdaView ){ - var historyView = this; - _super.prototype._setUpHdaListeners.call( this, hdaView ); - - // maintain a list of hdas that are selected - hdaView.on( 'selected', function( hdaView, event ){ - if( !event ){ return; } - //console.debug( 'selected', event ); - var selectedIds = []; - //console.debug( historyView.lastSelectedViewId, historyView.hdaViews[ historyView.lastSelectedViewId ] ); - - // shift will select a range, but not set lastSelectedViewId - if( ( event.shiftKey ) - && ( historyView.lastSelectedViewId && _.has( historyView.hdaViews, historyView.lastSelectedViewId ) ) ){ - var lastSelectedView = historyView.hdaViews[ historyView.lastSelectedViewId ]; - selectedIds = historyView.selectDatasetRange( hdaView, lastSelectedView ) - .map( function( view ){ return view.model.id; }); - - // only - } else { - var id = hdaView.model.id; - historyView.lastSelectedViewId = id; - //console.debug( 'lastSelectedViewId:', historyView.lastSelectedViewId ); - selectedIds = [ id ]; - } - //console.debug( 'selectedIds:', selectedIds ); - historyView.selectedHdaIds = _.union( historyView.selectedHdaIds, selectedIds ); - //TODO: might want to use getSelectedHdaViews instead managing these lists with ops - //console.debug( 'selected', historyView.selectedHdaIds ); - }); - hdaView.on( 'de-selected', function( hdaView, event ){ - //console.debug( 'de-selected', event ); - var id = hdaView.model.id; - historyView.selectedHdaIds = _.without( historyView.selectedHdaIds, id ); - //console.debug( 'de-selected', historyView.selectedHdaIds ); - }); - }, - - /** toggle the visibility of each hdaView's tagsEditor applying all the args sent to this function */ - toggleHDATagEditors : function( showOrHide ){ - var args = arguments; - _.each( this.hdaViews, function( hdaView ){ - if( hdaView.tagsEditor ){ - hdaView.tagsEditor.toggle.apply( hdaView.tagsEditor, args ); - } - }); - }, - - /** toggle the visibility of each hdaView's annotationEditor applying all the args sent to this function */ - toggleHDAAnnotationEditors : function( showOrHide ){ - var args = arguments; - _.each( this.hdaViews, function( hdaView ){ - if( hdaView.annotationEditor ){ - hdaView.annotationEditor.toggle.apply( hdaView.annotationEditor, args ); - } - }); - }, - - /** Remove a view from the panel and if the panel is now empty, re-render - * @param {Int} the id of the hdaView to remove - */ - removeHdaView : function( hdaView ){ - if( !hdaView ){ return; } - var panel = this; - hdaView.$el.fadeOut( panel.fxSpeed, function(){ - hdaView.off(); - hdaView.remove(); - delete panel.hdaViews[ hdaView.model.id ]; - if( _.isEmpty( panel.hdaViews ) ){ - panel.trigger( 'empty-history', panel ); - panel._renderEmptyMsg(); + hdaView.on( 'error', function( model, xhr, options, msg ){ + panel.errorHandler( model, xhr, options, msg ); + }); + // maintain a list of hdas whose bodies are expanded + hdaView.on( 'expanded', function( view ){ + panel.storage.addExpandedHda( view.model ); + }); + hdaView.on( 'collapsed', function( view ){ + panel.storage.removeExpandedHda( view.model ); + }); + return this; + }, + + /** attach an hdaView to the panel */ + attachContentView : function( hdaView, $whereTo ){ + $whereTo = $whereTo || this.$el; + var $datasetsList = this.$datasetsList( $whereTo ); + $datasetsList.prepend( hdaView.$el ); + return this; + }, + + /** Add an hda view to the panel for the given hda + * @param {HistoryDatasetAssociation} hda + */ + addContentView : function( hda ){ + this.log( 'add.' + this, hda ); + var panel = this; + + // don't add the view if it wouldn't be visible accrd. to current settings + if( !hda.isVisible( this.storage.get( 'show_deleted' ), this.storage.get( 'show_hidden' ) ) ){ + return panel; + } + + // create and prepend to current el, if it was empty fadeout the emptyMsg first + $({}).queue([ + function fadeOutEmptyMsg( next ){ + var $emptyMsg = panel.$emptyMessage(); + if( $emptyMsg.is( ':visible' ) ){ + $emptyMsg.fadeOut( panel.fxSpeed, next ); + } else { + next(); + } + }, + function createAndPrepend( next ){ + var hdaView = panel._createContentView( hda ); + panel.hdaViews[ hda.id ] = hdaView; + hdaView.render().$el.hide(); + panel.scrollToTop(); + panel.attachContentView( hdaView ); + hdaView.$el.slideDown( panel.fxSpeed ); + } + ]); + return panel; + }, + +//TODO: removeHdaView? + /** Set up/render a view for each HDA to be shown, init with model and listeners. + * HDA views are cached to the map this.hdaViews (using the model.id as key). + * @param {jQuery} $whereTo what dom element to prepend the HDA views to + * @returns the number of visible hda views + */ + views : function( at ){ + var panel = this, + visibleHdas = this.model.contents.getVisible( + this.storage.get( 'show_deleted' ), + this.storage.get( 'show_hidden' ), + this.filters + ); + if( at !== undefined ){ + return panel.hdaViews[ visibleHdas.at( at ).id ]; + } + return visibleHdas.map( function( hda ){ + return panel.hdaViews[ hda.id ]; + }); + }, + + /** convenience alias to the model. Updates the hda list only (not the history) */ + refreshContents : function( detailIds, options ){ + if( this.model ){ + return this.model.refresh( detailIds, options ); + } + // may have callbacks - so return an empty promise + return $.when(); + }, + + ///** use underscore's findWhere to find a view where the model matches the terms + // * note: finds and returns the _first_ matching + // */ + //findHdaView : function( terms ){ + // if( !this.model || !this.model.contents.length ){ return undefined; } + // var model = this.model.contents.findWhere( terms ); + // return ( model )?( this.hdaViews[ model.id ] ):( undefined ); + //}, + + hdaViewRange : function( viewA, viewB ){ + if( viewA === viewB ){ return [ viewA ]; } + //TODO: would probably be better if we cache'd the views as an ordered list (as well as a map) + var panel = this, + withinSet = false, + set = []; + this.model.contents.getVisible( + this.storage.get( 'show_deleted' ), + this.storage.get( 'show_hidden' ), + this.filters + ).each( function( hda ){ + //console.debug( 'checking: ', hda.get( 'name' ) ); + if( withinSet ){ + //console.debug( '\t\t adding: ', hda.get( 'name' ) ); + set.push( panel.hdaViews[ hda.id ] ); + if( hda === viewA.model || hda === viewB.model ){ + //console.debug( '\t found last: ', hda.get( 'name' ) ); + withinSet = false; + } + } else { + if( hda === viewA.model || hda === viewB.model ){ + //console.debug( 'found first: ', hda.get( 'name' ) ); + withinSet = true; + set.push( panel.hdaViews[ hda.id ] ); + } } }); + return set; }, // ------------------------------------------------------------------------ panel events /** event map */ - events : _.extend( _.clone( _super.prototype.events ), { - 'click .history-select-btn' : 'toggleSelectors', - 'click .history-select-all-datasets-btn' : 'selectAllDatasets', - 'click .history-deselect-all-datasets-btn' : 'deselectAllDatasets' - }), + events : { + // allow (error) messages to be clicked away +//TODO: switch to common close (X) idiom + 'click .message-container' : 'clearMessages', + 'click .history-search-btn' : 'toggleSearchControls' + }, - /** Update the history size display (curr. upper right of panel). + /** Collapse all hda bodies and clear expandedHdas in the storage */ + collapseAllHdaBodies : function(){ + _.each( this.hdaViews, function( item ){ + item.collapse(); + }); + this.storage.set( 'expandedHdas', {} ); + return this; + }, + + /** Handle the user toggling the deleted visibility by: + * (1) storing the new value in the persistent storage + * (2) re-rendering the history + * @returns {Boolean} new show_deleted setting */ - updateHistoryDiskSize : function(){ - this.$el.find( '.history-size' ).text( this.model.get( 'nice_size' ) ); + toggleShowDeleted : function( show ){ + show = ( show !== undefined )?( show ):( !this.storage.get( 'show_deleted' ) ); + this.storage.set( 'show_deleted', show ); + this.renderHdas(); + return this.storage.get( 'show_deleted' ); }, - // ........................................................................ multi-select of hdas -//TODO: to toggle showOrHide pattern - /** show selectors on all visible hdas and associated controls */ - showSelectors : function( speed ){ - speed = ( speed !== undefined )?( speed ):( this.fxSpeed ); - this.selecting = true; - this.$( '.history-dataset-actions' ).slideDown( speed ); - _.each( this.hdaViews, function( view ){ - view.showSelector(); - }); - this.selectedHdaIds = []; - this.lastSelectedViewId = null; + /** Handle the user toggling the deleted visibility by: + * (1) storing the new value in the persistent storage + * (2) re-rendering the history + * @returns {Boolean} new show_hidden setting + */ + toggleShowHidden : function( show ){ + show = ( show !== undefined )?( show ):( !this.storage.get( 'show_hidden' ) ); + this.storage.set( 'show_hidden', show ); + this.renderHdas(); + return this.storage.get( 'show_hidden' ); }, - /** hide selectors on all visible hdas and associated controls */ - hideSelectors : function( speed ){ - speed = ( speed !== undefined )?( speed ):( this.fxSpeed ); - this.selecting = false; - this.$( '.history-dataset-actions' ).slideUp( speed ); - _.each( this.hdaViews, function( view ){ - view.hideSelector(); - }); - this.selectedHdaIds = []; - this.lastSelectedViewId = null; - }, + // ........................................................................ hda search & filters + /** render a search input for filtering datasets shown + * (see the search section in the HDA model for implementation of the actual searching) + * return will start the search + * esc will clear the search + * clicking the clear button will clear the search + * uses searchInput in ui.js + */ + _setUpSearchInput : function( $where ){ + var panel = this, + inputSelector = '.history-search-input'; - /** show or hide selectors on all visible hdas and associated controls */ - toggleSelectors : function(){ - if( !this.selecting ){ - this.showSelectors(); + function onFirstSearch( searchFor ){ + //this.log( 'onFirstSearch', searchFor, panel ); + if( panel.model.contents.haveDetails() ){ + panel.searchHdas( searchFor ); + return; + } + panel.$el.find( inputSelector ).searchInput( 'toggle-loading' ); + panel.model.contents.fetchAllDetails({ silent: true }) + .always( function(){ + panel.$el.find( inputSelector ).searchInput( 'toggle-loading' ); + }) + .done( function(){ + panel.searchHdas( searchFor ); + }); + } + $where.searchInput({ + initialVal : panel.searchFor, + name : 'history-search', + placeholder : 'search datasets', + classes : 'history-search', + onfirstsearch : onFirstSearch, + onsearch : _.bind( this.searchHdas, this ), + onclear : _.bind( this.clearHdaSearch, this ) + }); + return $where; + }, + /** toggle showing/hiding the search controls (rendering first on the initial show) + * @param {Event or Number} eventOrSpeed variadic - if number the speed of the show/hide effect + * @param {boolean} show force show/hide with T/F + */ + toggleSearchControls : function( eventOrSpeed, show ){ + var $searchControls = this.$el.find( '.history-search-controls' ), + speed = ( jQuery.type( eventOrSpeed ) === 'number' )?( eventOrSpeed ):( this.fxSpeed ); + show = ( show !== undefined )?( show ):( !$searchControls.is( ':visible' ) ); + if( show ){ + $searchControls.slideDown( speed, function(){ + $( this ).find( 'input' ).focus(); + }); } else { - this.hideSelectors(); + $searchControls.slideUp( speed ); + } + return show; + }, + + /** filter hda view list to those that contain the searchFor terms + * (see the search section in the HDA model for implementation of the actual searching) + */ + searchHdas : function( searchFor ){ + //note: assumes hda details are loaded + //this.log( 'onSearch', searchFor, this ); + var panel = this; + this.searchFor = searchFor; + this.filters = [ function( hda ){ return hda.matchesAll( panel.searchFor ); } ]; + this.trigger( 'search:searching', searchFor, this ); + this.renderHdas(); + return this; + }, + + /** clear the search filters and show all views that are normally shown */ + clearHdaSearch : function( searchFor ){ + //this.log( 'onSearchClear', this ); + this.searchFor = ''; + this.filters = []; + this.trigger( 'search:clear', this ); + this.renderHdas(); + return this; + }, + + // ........................................................................ loading indicator + /** hide the panel and display a loading indicator (in the panel's parent) when history model's are switched */ + _showLoadingIndicator : function( msg, speed, callback ){ + speed = ( speed !== undefined )?( speed ):( this.fxSpeed ); + if( !this.indicator ){ + this.indicator = new LoadingIndicator( this.$el, this.$el.parent() ); + } + if( !this.$el.is( ':visible' ) ){ + this.indicator.show( 0, callback ); + } else { + this.$el.fadeOut( speed ); + this.indicator.show( msg, speed, callback ); } }, - /** select all visible hdas */ - selectAllDatasets : function( event ){ - _.each( this.hdaViews, function( view ){ - view.select( event ); - }); + /** hide the loading indicator */ + _hideLoadingIndicator : function( speed, callback ){ + speed = ( speed !== undefined )?( speed ):( this.fxSpeed ); + if( this.indicator ){ + this.indicator.hide( speed, callback ); + } }, - /** deselect all visible hdas */ - deselectAllDatasets : function( event ){ - this.lastSelectedViewId = null; - _.each( this.hdaViews, function( view ){ - view.deselect( event ); - }); + // ........................................................................ (error) messages + /** Display a message in the top of the panel. + * @param {String} type type of message ('done', 'error', 'warning') + * @param {String} msg the message to display + * @param {Object or HTML} modal contents displayed when the user clicks 'details' in the message + */ + displayMessage : function( type, msg, details ){ + //precondition: msgContainer must have been rendered even if there's no model + var panel = this; + //this.log( 'displayMessage', type, msg, details ); + + this.scrollToTop(); + var $msgContainer = this.$messages(), + $msg = $( '
' ).addClass( type + 'message' ).html( msg ); + //this.log( ' ', $msgContainer ); + + if( !_.isEmpty( details ) ){ + var $detailsLink = $( 'Details' ) + .click( function(){ + Galaxy.modal.show( panel._messageToModalOptions( type, msg, details ) ); + return false; + }); + $msg.append( ' ', $detailsLink ); + } + return $msgContainer.html( $msg ); }, - /** select a range of datasets between A and B */ - selectDatasetRange : function( viewA, viewB ){ - var range = this.hdaViewRange( viewA, viewB ); - _.each( range, function( view ){ - view.select(); - }); - return range; + /** convert msg and details into modal options usable by Galaxy.modal */ + _messageToModalOptions : function( type, msg, details ){ + // only error is fleshed out here + var panel = this, + $modalBody = $( '
' ), + options = { title: 'Details' }; + + //TODO: to some util library + function objToTable( obj ){ + obj = _.omit( obj, _.functions( obj ) ); + return [ + '', + _.map( obj, function( val, key ){ + val = ( _.isObject( val ) )?( objToTable( val ) ):( val ); + return '' + + ''; + }).join( '' ), + '
' + key + '' + val + '
' + ].join( '' ); + } + + if( _.isObject( details ) ){ + options.body = $modalBody.append( objToTable( details ) ); + + } else { + options.body = $modalBody.html( details ); + } + options.buttons = { + 'Ok': function(){ + Galaxy.modal.hide(); + panel.clearMessages(); + } + //TODO: if( type === 'error' ){ options.buttons[ 'Report this error' ] = function(){} } + }; + return options; }, - /** return an array of all currently selected hdas */ - getSelectedHdaViews : function(){ - return _.filter( this.hdaViews, function( v ){ - return v.selected; - }); + /** Remove all messages from the panel. + */ + clearMessages : function(){ + this.$messages().empty(); + return this; }, - /** return an HdaCollection of the models of all currenly selected hdas */ - getSelectedHdaCollection : function(){ - return new HISTORY_CONTENTS.HistoryContents( _.map( this.getSelectedHdaViews(), function( hdaView ){ - return hdaView.model; - }), { historyId: this.model.id }); + // ........................................................................ scrolling + /** get the current scroll position of the panel in its parent */ + scrollPosition : function(){ + return this.$container().scrollTop(); + }, + + /** set the current scroll position of the panel in its parent */ + scrollTo : function( pos ){ + this.$container().scrollTop( pos ); + return this; + }, + + /** Scrolls the panel to the top. */ + scrollToTop : function(){ + this.$container().scrollTop( 0 ); + return this; + }, + + /** Scrolls the panel to show the HDA with the given id. + * @param {String} id the id of HDA to scroll into view + * @returns {HistoryPanel} the panel + */ + scrollToId : function( id ){ + // do nothing if id not found + if( ( !id ) || ( !this.hdaViews[ id ] ) ){ + return this; + } + var view = this.hdaViews[ id ]; + //this.scrollIntoView( $viewEl.offset().top ); + this.scrollTo( view.el.offsetTop ); + return this; + }, + + /** Scrolls the panel to show the HDA with the given hid. + * @param {Integer} hid the hid of HDA to scroll into view + * @returns {HistoryPanel} the panel + */ + scrollToHid : function( hid ){ + var hda = this.model.contents.getByHid( hid ); + // do nothing if hid not found + if( !hda ){ return this; } + return this.scrollToId( hda.id ); }, // ........................................................................ misc + print : function(){ + var panel = this; + panel.debug( this ); + _.each( this.hdaViews, function( view, id ){ + panel.debug( '\t ' + id, view ); + }); + }, + /** Return a string rep of the history */ - toString : function(){ - return 'HistoryPanel(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')'; + toString : function(){ + return 'ReadOnlyHistoryPanel(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')'; } }); +//------------------------------------------------------------------------------ TEMPLATES +var _panelTemplate = [ + '
', + '
', + '
', + '
', + + '
', + '<% if( history.name ){ %>', + '
<%= history.name %>
', + '<% } %>', + '
', + + '
', + '<% if( history.nice_size ){ %>', + '
<%= history.nice_size %>
', + '<% } %>', + '
', + '
', + + '<% if( history.deleted ){ %>', + '
', + _l( 'You are currently viewing a deleted history!' ), + '
', + '<% } %>', + + '
', + '<% if( history.message ){ %>', + // should already be localized + '
<%= history.message %>
', + '<% } %>', + '
', + + '
', + _l( 'You are over your disk quota' ), '. ', + _l( 'Tool execution is on hold until your disk usage drops below your allocated quota' ), '.', + '
', + + '
', + '
', + '
', + '
', + '', + '', + '
', + '', + '
', + '
', + // end history controls + + // where the datasets/hdas are added + '
', + '
', + _l( 'This history is empty' ), + '
' +].join( '' ); + +ReadOnlyHistoryPanel.templates = { + historyPanel : function( historyJSON ){ + return _.template( _panelTemplate, historyJSON, { variable: 'history' }); + } +}; + //============================================================================== return { - HistoryPanel : HistoryPanel + ReadOnlyHistoryPanel: ReadOnlyHistoryPanel }; }); diff --git a/static/scripts/mvc/history/readonly-history-panel.js b/static/scripts/mvc/history/readonly-history-panel.js deleted file mode 100644 index e2feb93851b..00000000000 --- a/static/scripts/mvc/history/readonly-history-panel.js +++ /dev/null @@ -1,1122 +0,0 @@ -define([ - "mvc/history/history-model", - "mvc/collection/hdca-base", - "mvc/dataset/dataset-list-element", - "mvc/dataset/hda-base", - "mvc/user/user-model", - "mvc/base-mvc", - "utils/localization" -], function( HISTORY_MODEL, HDCA_BASE, DATASET_LI, HDA_BASE, USER, BASE_MVC, _l ){ -// ============================================================================ -/** session storage for individual history preferences */ -var HistoryPrefs = BASE_MVC.SessionStorageModel.extend({ - defaults : { -//TODO:?? expandedHdas to array? - expandedHdas : {}, - //TODO:?? move to user? - show_deleted : false, - show_hidden : false - //TODO: add scroll position? - }, - /** add an hda id to the hash of expanded hdas */ - addExpandedHda : function( model ){ - var key = 'expandedHdas'; - this.save( key, _.extend( this.get( key ), _.object([ model.id ], [ model.get( 'id' ) ]) ) ); - }, - /** remove an hda id from the hash of expanded hdas */ - removeExpandedHda : function( model ){ - var key = 'expandedHdas'; - this.save( key, _.omit( this.get( key ), model.id ) ); - }, - toString : function(){ - return 'HistoryPrefs(' + this.id + ')'; - } -}); -// class lvl for access w/o instantiation -HistoryPrefs.storageKeyPrefix = 'history:'; - -/** key string to store each histories settings under */ -HistoryPrefs.historyStorageKey = function historyStorageKey( historyId ){ - if( !historyId ){ - throw new Error( 'HistoryPrefs.historyStorageKey needs valid id: ' + historyId ); - } - // single point of change - return ( HistoryPrefs.storageKeyPrefix + historyId ); -}; -/** return the existing storage for the history with the given id (or create one if it doesn't exist) */ -HistoryPrefs.get = function get( historyId ){ - return new HistoryPrefs({ id: HistoryPrefs.historyStorageKey( historyId ) }); -}; -/** clear all history related items in sessionStorage */ -HistoryPrefs.clearAll = function clearAll( historyId ){ - for( var key in sessionStorage ){ - if( key.indexOf( HistoryPrefs.storageKeyPrefix ) === 0 ){ - sessionStorage.removeItem( key ); - } - } -}; - - -/* ============================================================================= -TODO: - -============================================================================= */ -// base model and used as-is in history/view.mako -/** @class non-editable, read-only View/Controller for a history model. - * @name HistoryPanel - * - * Allows: - * changing the loaded history - * searching hdas - * displaying data, info, and download - * Does not allow: - * changing the name - * - * @augments Backbone.View - * @borrows LoggableMixin#logger as #logger - * @borrows LoggableMixin#log as #log - * @constructs - */ -var ReadOnlyHistoryPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend( -/** @lends ReadOnlyHistoryPanel.prototype */{ - - /** logger used to record this.log messages, commonly set to console */ - // comment this out to suppress log output - //logger : console, - - /** class to use for constructing the HDA views */ - //HDAViewClass : HDA_BASE.HDABaseView, - HDAViewClass : DATASET_LI.DatasetListItemView, - HDCAViewClass : HDCA_BASE.HDCABaseView, - - tagName : 'div', - className : 'history-panel', - - /** (in ms) that jquery effects will use */ - fxSpeed : 'fast', - - /** string to display when the model has no hdas */ - emptyMsg : _l( 'This history is empty' ), - /** string to no hdas match the search terms */ - noneFoundMsg : _l( 'No matching datasets found' ), - - // ......................................................................... SET UP - /** Set up the view, set up storage, bind listeners to HistoryContents events - * @param {Object} attributes optional settings for the panel - */ - initialize : function( attributes ){ - attributes = attributes || {}; - // set the logger if requested - if( attributes.logger ){ - this.logger = attributes.logger; - } - this.log( this + '.initialize:', attributes ); - - // ---- instance vars - // control contents/behavior based on where (and in what context) the panel is being used - /** where should pages from links be displayed? (default to new tab/window) */ - this.linkTarget = attributes.linkTarget || '_blank'; - /** how quickly should jquery fx run? */ - this.fxSpeed = _.has( attributes, 'fxSpeed' )?( attributes.fxSpeed ):( this.fxSpeed ); - - /** filters for displaying hdas */ - this.filters = []; - this.searchFor = ''; - - /** a function to locate the container to scroll to effectively scroll the panel */ -//TODO: rename - this.findContainerFn = attributes.findContainerFn; - // generally this is $el.parent() - but may be $el or $el.parent().parent() depending on the context - - // ---- sub views and saved elements - /** map of hda model ids to hda views */ - this.hdaViews = {}; - /** loading indicator */ - this.indicator = new LoadingIndicator( this.$el ); - - // ----- set up panel listeners, handle models passed on init, and call any ready functions - this._setUpListeners(); - // don't render when setting the first time - var modelOptions = _.pick( attributes, 'initiallyExpanded', 'show_deleted', 'show_hidden' ); - this.setModel( this.model, modelOptions, false ); -//TODO: remove? - if( attributes.onready ){ - attributes.onready.call( this ); - } - }, - - /** create any event listeners for the panel - * @fires: rendered:initial on the first render - * @fires: empty-history when switching to a history with no HDAs or creating a new history - */ - _setUpListeners : function(){ - this.on( 'error', function( model, xhr, options, msg, details ){ - this.errorHandler( model, xhr, options, msg, details ); - }); - - this.on( 'loading-history', function(){ - // show the loading indicator when loading a new history starts... - this._showLoadingIndicator( 'loading history...', 40 ); - }); - this.on( 'loading-done', function(){ - // ...hiding it again when loading is done (or there's been an error) - this._hideLoadingIndicator( 40 ); - if( _.isEmpty( this.hdaViews ) ){ - this.trigger( 'empty-history', this ); - } - }); - - // throw the first render up as a diff namespace using once (for outside consumption) - this.once( 'rendered', function(){ - this.trigger( 'rendered:initial', this ); - return false; - }); - - // debugging - if( this.logger ){ - this.on( 'all', function( event ){ - this.log( this + '', arguments ); - }, this ); - } - return this; - }, - - //TODO: see base-mvc - //onFree : function(){ - // _.each( this.hdaViews, function( view, modelId ){ - // view.free(); - // }); - // this.hdaViews = null; - //}, - - // ........................................................................ error handling - /** Event handler for errors (from the panel, the history, or the history's HDAs) - * @param {Model or View} model the (Backbone) source of the error - * @param {XMLHTTPRequest} xhr any ajax obj. assoc. with the error - * @param {Object} options the options map commonly used with bbone ajax - * @param {String} msg optional message passed to ease error location - * @param {Object} msg optional object containing error details - */ - errorHandler : function( model, xhr, options, msg, details ){ - this.error( model, xhr, options, msg, details ); -//TODO: getting JSON parse errors from jq migrate - - // interrupted ajax - if( xhr && xhr.status === 0 && xhr.readyState === 0 ){ - - // bad gateway - } else if( xhr && xhr.status === 502 ){ -//TODO: gmail style 'reconnecting in Ns' - - // otherwise, show an error message inside the panel - } else { - var parsed = this._parseErrorMessage( model, xhr, options, msg, details ); - // it's possible to have a triggered error before the message container is rendered - wait for it to show - if( !this.$messages().is( ':visible' ) ){ - this.once( 'rendered', function(){ - this.displayMessage( 'error', parsed.message, parsed.details ); - }); - } else { - this.displayMessage( 'error', parsed.message, parsed.details ); - } - } - }, - - /** Parse an error event into an Object usable by displayMessage based on the parameters - * note: see errorHandler for more info on params - */ - _parseErrorMessage : function( model, xhr, options, msg, details ){ - var user = Galaxy.currUser, - // add the args (w/ some extra info) into an obj - parsed = { - message : this._bePolite( msg ), - details : { - user : ( user instanceof USER.User )?( user.toJSON() ):( user + '' ), - source : ( model instanceof Backbone.Model )?( model.toJSON() ):( model + '' ), - xhr : xhr, - options : ( xhr )?( _.omit( options, 'xhr' ) ):( options ) - } - }; - // add any extra details passed in - _.extend( parsed.details, details || {} ); - // fancy xhr.header parsing (--> obj) - if( xhr && _.isFunction( xhr.getAllResponseHeaders ) ){ - var responseHeaders = xhr.getAllResponseHeaders(); - responseHeaders = _.compact( responseHeaders.split( '\n' ) ); - responseHeaders = _.map( responseHeaders, function( header ){ - return header.split( ': ' ); - }); - parsed.details.xhr.responseHeaders = _.object( responseHeaders ); - } - return parsed; - }, - - /** Modify an error message to be fancy and wear a monocle. */ - _bePolite : function( msg ){ - msg = msg || _l( 'An error occurred while getting updates from the server' ); - return msg + '. ' + _l( 'Please contact a Galaxy administrator if the problem persists' ) + '.'; - }, - - // ------------------------------------------------------------------------ loading history/hda models - //NOTE: all the following fns replace the existing history model with a new model - // (in the following 'details' refers to the full set of hda api data (urls, display_apps, misc_info, etc.) - // - hdas w/o details will have summary data only (name, hid, deleted, visible, state, etc.)) - - /** loads a history & hdas w/ details (but does not make them the current history) */ - loadHistoryWithHDADetails : function( historyId, attributes, historyFn, hdaFn ){ - //this.info( 'loadHistoryWithHDADetails:', historyId, attributes, historyFn, hdaFn ); - var hdaDetailIds = function( historyData ){ - // will be called to get hda ids that need details from the api -//TODO: non-visible HDAs are getting details loaded... either stop loading them at all or filter ids thru isVisible - return _.values( HistoryPrefs.get( historyData.id ).get( 'expandedHdas' ) ); - }; - return this.loadHistory( historyId, attributes, historyFn, hdaFn, hdaDetailIds ); - }, - - /** loads a history & hdas w/ NO details (but does not make them the current history) */ - loadHistory : function( historyId, attributes, historyFn, hdaFn, hdaDetailIds ){ - var panel = this; - attributes = attributes || {}; - - panel.trigger( 'loading-history', panel ); - //this.info( 'loadHistory:', historyId, attributes, historyFn, hdaFn, hdaDetailIds ); - var xhr = HISTORY_MODEL.History.getHistoryData( historyId, { - historyFn : historyFn, - hdaFn : hdaFn, - hdaDetailIds : attributes.initiallyExpanded || hdaDetailIds - }); - - return panel._loadHistoryFromXHR( xhr, attributes ) - .fail( function( xhr, where, history ){ - // throw an error up for the error handler -//TODO: difficult to localize - use template - panel.trigger( 'error', panel, xhr, attributes, _l( 'An error was encountered while ' + where ), - { historyId: historyId, history: history || {} }); - }) - .always( function(){ - // bc _hideLoadingIndicator relies on this firing - panel.trigger( 'loading-done', panel ); - }); - }, - - /** given an xhr that will provide both history and hda data, pass data to set model or handle xhr errors */ - _loadHistoryFromXHR : function( xhr, attributes ){ - var panel = this; - xhr.then( function( historyJSON, hdaJSON ){ - panel.JSONToModel( historyJSON, hdaJSON, attributes ); - }); - xhr.fail( function( xhr, where ){ - // always render - whether we get a model or not - panel.render(); - }); - return xhr; - }, - - - /** create a new history model from JSON and call setModel on it */ - JSONToModel : function( newHistoryJSON, newHdaJSON, attributes ){ - this.log( 'JSONToModel:', newHistoryJSON, newHdaJSON, attributes ); -//TODO: Maybe better in History? - attributes = attributes || {}; - //this.log( 'JSONToModel:', newHistoryJSON, newHdaJSON.length, attributes ); - -// // set up the new model and render -// if( Galaxy && Galaxy.currUser ){ -////TODO: global -// newHistoryJSON.user = Galaxy.currUser.toJSON(); -// } - var model = new HISTORY_MODEL.History( newHistoryJSON, newHdaJSON, attributes ); - this.setModel( model ); - return this; - }, - - /** release/free/shutdown old models and set up panel for new models - * @fires new-model with the panel as parameter - */ - setModel : function( model, attributes, render ){ - attributes = attributes || {}; - render = ( render !== undefined )?( render ):( true ); - this.log( 'setModel:', model, attributes, render ); - - this.freeModel(); - this.selectedHdaIds = []; - - if( model ){ - // set up the new model with user, logger, storage, events -// if( Galaxy && Galaxy.currUser ){ -////TODO: global -// model.user = Galaxy.currUser.toJSON(); -// } - this.model = model; - if( this.logger ){ - this.model.logger = this.logger; - } - this._setUpWebStorage( attributes.initiallyExpanded, attributes.show_deleted, attributes.show_hidden ); - this._setUpModelEventHandlers(); - this.trigger( 'new-model', this ); - } - - if( render ){ -//TODO: remove? - this.render(); - } - return this; - }, - - /** free the current model and all listeners for it, free any hdaViews for the model */ - freeModel : function(){ - // stop/release the previous model, and clear cache to hda sub-views - if( this.model ){ - this.model.clearUpdateTimeout(); - this.stopListening( this.model ); - this.stopListening( this.model.contents ); - //TODO: see base-mvc - //this.model.free(); - } - this.freeHdaViews(); - return this; - }, - - /** free any hdaViews the panel has */ - freeHdaViews : function(){ - this.hdaViews = {}; - return this; - }, - - // ------------------------------------------------------------------------ browser stored prefs - /** Set up client side storage. Currently PersistanStorage keyed under 'HistoryPanel.' - * @param {Object} initiallyExpanded - * @param {Boolean} show_deleted whether to show deleted HDAs (overrides stored) - * @param {Boolean} show_hidden - * @see PersistentStorage - */ - _setUpWebStorage : function( initiallyExpanded, show_deleted, show_hidden ){ - //this.log( '_setUpWebStorage', initiallyExpanded, show_deleted, show_hidden ); - this.storage = new HistoryPrefs({ - id: HistoryPrefs.historyStorageKey( this.model.get( 'id' ) ) - }); - - // expanded Hdas is a map of hda.ids -> a boolean repr'ing whether this hda's body is already expanded - // store any pre-expanded ids passed in - if( _.isObject( initiallyExpanded ) ){ - this.storage.set( 'exandedHdas', initiallyExpanded ); - } - - // get the show_deleted/hidden settings giving priority to values passed in, using web storage otherwise - // if the page has specifically requested show_deleted/hidden, these will be either true or false - // (as opposed to undefined, null) - and we give priority to that setting - if( _.isBoolean( show_deleted ) ){ - this.storage.set( 'show_deleted', show_deleted ); - } - if( _.isBoolean( show_hidden ) ){ - this.storage.set( 'show_hidden', show_hidden ); - } - - this.trigger( 'new-storage', this.storage, this ); - this.log( this + ' (init\'d) storage:', this.storage.get() ); - return this; - }, - - // ------------------------------------------------------------------------ history/hda event listening - /** listening for history and HDA events */ - _setUpModelEventHandlers : function(){ - // ---- hdas - // bind events from the model's hda collection - // note: don't listen to the hdas for errors, history will pass that to us - //this.model.contents.on( 'reset', this.addAll, this ); - this.model.contents.on( 'add', this.addContentView, this ); - - // on a model error - bounce it up to the panel and remove it from the model - this.model.on( 'error error:contents', function( model, xhr, options, msg ){ - this.errorHandler( model, xhr, options, msg ); - }, this ); - return this; - }, - - // ------------------------------------------------------------------------ panel rendering - /** Render urls, historyPanel body, and hdas (if any are shown) - * @fires: rendered when the panel is attached and fully visible - * @see Backbone.View#render - */ - render : function( speed, callback ){ - this.log( 'render:', speed, callback ); - // send a speed of 0 to have no fade in/out performed - speed = ( speed === undefined )?( this.fxSpeed ):( speed ); - var panel = this, - $newRender; - - // handle the possibility of no model (can occur if fetching the model returns an error) - if( this.model ){ - $newRender = this.renderModel(); - } else { - $newRender = this.renderWithoutModel(); - } - - // fade out existing, swap with the new, fade in, set up behaviours - $( panel ).queue( 'fx', [ - function( next ){ - if( speed && panel.$el.is( ':visible' ) ){ - panel.$el.fadeOut( speed, next ); - } else { - next(); - } - }, - function( next ){ - // swap over from temp div newRender - panel.$el.empty(); - if( $newRender ){ - panel.$el.append( $newRender.children() ); - } - next(); - }, - function( next ){ - if( speed && !panel.$el.is( ':visible' ) ){ - panel.$el.fadeIn( speed, next ); - } else { - next(); - } - }, - function( next ){ - //TODO: ideally, these would be set up before the fade in (can't because of async save text) - if( callback ){ callback.call( this ); } - panel.trigger( 'rendered', this ); - next(); - } - ]); - return this; - }, - - /** render without history data - * @returns {jQuery} dom fragment with message container only - */ - renderWithoutModel : function( ){ - // we'll always need the message container - var $newRender = $( '
' ), - $msgContainer = $( '
' ).addClass( 'message-container' ) - .css({ 'margin': '4px' }); - return $newRender.append( $msgContainer ); - }, - - /** render with history data - * @returns {jQuery} dom fragment as temporary container to be swapped out later - */ - renderModel : function( ){ - // tmp div for final swap in render - var $newRender = $( '
' ); - - // render based on anonymity, set up behaviors - $newRender.append( ReadOnlyHistoryPanel.templates.historyPanel( this.model.toJSON() ) ); - this.$emptyMessage( $newRender ).text( this.emptyMsg ); - // search and select available to both anon/logged-in users - $newRender.find( '.history-secondary-actions' ).prepend( this._renderSearchButton() ); - - this._setUpBehaviours( $newRender ); - - // render hda views (if any and any shown (show_deleted/hidden) - this.renderHdas( $newRender ); - return $newRender; - }, - - /** render the empty/none-found message */ - _renderEmptyMsg : function( $whereTo ){ - var panel = this, - $emptyMsg = panel.$emptyMessage( $whereTo ); - - if( !_.isEmpty( panel.hdaViews ) ){ - $emptyMsg.hide(); - - } else if( panel.searchFor ){ - $emptyMsg.text( panel.noneFoundMsg ).show(); - - } else { - $emptyMsg.text( panel.emptyMsg ).show(); - } - return this; - }, - - /** button for opening search */ - _renderSearchButton : function( $where ){ - return faIconButton({ - title : _l( 'Search datasets' ), - classes : 'history-search-btn', - faIcon : 'fa-search' - }); - }, - - /** Set up HistoryPanel js/widget behaviours */ - _setUpBehaviours : function( $where ){ - //TODO: these should be either sub-MVs, or handled by events - $where = $where || this.$el; - $where.find( '[title]' ).tooltip({ placement: 'bottom' }); - this._setUpSearchInput( $where.find( '.history-search-controls .history-search-input' ) ); - return this; - }, - - // ------------------------------------------------------------------------ sub-$element shortcuts - /** the scroll container for this panel - can be $el, $el.parent(), or grandparent depending on context */ - $container : function(){ - return ( this.findContainerFn )?( this.findContainerFn.call( this ) ):( this.$el.parent() ); - }, - /** where hdaViews are attached */ - $datasetsList : function( $where ){ - return ( $where || this.$el ).find( '.datasets-list' ); - }, - /** container where panel messages are attached */ - $messages : function( $where ){ - return ( $where || this.$el ).find( '.message-container' ); - }, - /** the message displayed when no hdaViews can be shown (no hdas, none matching search) */ - $emptyMessage : function( $where ){ - return ( $where || this.$el ).find( '.empty-history-message' ); - }, - - // ------------------------------------------------------------------------ hda sub-views - /** Set up/render a view for each HDA to be shown, init with model and listeners. - * HDA views are cached to the map this.hdaViews (using the model.id as key). - * @param {jQuery} $whereTo what dom element to prepend the HDA views to - * @returns the number of visible hda views - */ - renderHdas : function( $whereTo ){ - $whereTo = $whereTo || this.$el; - var panel = this, - newHdaViews = {}, - // only render the shown hdas - //TODO: switch to more general filtered pattern - visibleHdas = this.model.contents.getVisible( - this.storage.get( 'show_deleted' ), - this.storage.get( 'show_hidden' ), - this.filters - ); - //this.log( 'renderHdas, visibleHdas:', visibleHdas, $whereTo ); -//TODO: prepend to sep div, add as one - - this.$datasetsList( $whereTo ).empty(); - - if( visibleHdas.length ){ - visibleHdas.each( function( hda ){ - // render it (NOTE: reverse order, newest on top (prepend)) - var hdaId = hda.id, - hdaView = panel._createContentView( hda ); - newHdaViews[ hdaId ] = hdaView; - // persist selection - if( _.contains( panel.selectedHdaIds, hdaId ) ){ - hdaView.selected = true; - } - panel.attachContentView( hdaView.render(), $whereTo ); - }); - } - this.hdaViews = newHdaViews; - this._renderEmptyMsg( $whereTo ); - return this.hdaViews; - }, - - /** Create an HDA view for the given HDA and set up listeners (but leave attachment for addHdaView) - * @param {HistoryDatasetAssociation} hda - */ - _createContentView : function( content ){ - var ContentClass = this._getContentClass( content ), - options = _.extend( this._getContentOptions( content ), { - model : content - }), - contentView = new ContentClass( options ); - this._setUpHdaListeners( contentView ); - return contentView; - }, - - _getContentClass : function( content ){ - var contentType = content.get( "history_content_type" ); - switch( contentType ){ - case 'dataset': - return this.HDAViewClass; - case 'dataset_collection': - return this.HDCAViewClass; - } - throw new TypeError( 'Unknown history_content_type: ' + contentType ); - }, - - _getContentOptions : function( content ){ - return { - linkTarget : this.linkTarget, - expanded : !!this.storage.get( 'expandedHdas' )[ content.id ], - //draggable : true, - hasUser : this.model.ownedByCurrUser(), - logger : this.logger - }; - }, - - /** Set up HistoryPanel listeners for HDAView events. Currently binds: - * HDAView#body-visible, HDAView#body-hidden to store expanded states - * @param {HDAView} hdaView HDAView (base or edit) to listen to - */ - _setUpHdaListeners : function( hdaView ){ - var panel = this; - hdaView.on( 'error', function( model, xhr, options, msg ){ - panel.errorHandler( model, xhr, options, msg ); - }); - // maintain a list of hdas whose bodies are expanded - hdaView.on( 'expanded', function( view ){ - panel.storage.addExpandedHda( view.model ); - }); - hdaView.on( 'collapsed', function( view ){ - panel.storage.removeExpandedHda( view.model ); - }); - return this; - }, - - /** attach an hdaView to the panel */ - attachContentView : function( hdaView, $whereTo ){ - $whereTo = $whereTo || this.$el; - var $datasetsList = this.$datasetsList( $whereTo ); - $datasetsList.prepend( hdaView.$el ); - return this; - }, - - /** Add an hda view to the panel for the given hda - * @param {HistoryDatasetAssociation} hda - */ - addContentView : function( hda ){ - this.log( 'add.' + this, hda ); - var panel = this; - - // don't add the view if it wouldn't be visible accrd. to current settings - if( !hda.isVisible( this.storage.get( 'show_deleted' ), this.storage.get( 'show_hidden' ) ) ){ - return panel; - } - - // create and prepend to current el, if it was empty fadeout the emptyMsg first - $({}).queue([ - function fadeOutEmptyMsg( next ){ - var $emptyMsg = panel.$emptyMessage(); - if( $emptyMsg.is( ':visible' ) ){ - $emptyMsg.fadeOut( panel.fxSpeed, next ); - } else { - next(); - } - }, - function createAndPrepend( next ){ - var hdaView = panel._createContentView( hda ); - panel.hdaViews[ hda.id ] = hdaView; - hdaView.render().$el.hide(); - panel.scrollToTop(); - panel.attachContentView( hdaView ); - hdaView.$el.slideDown( panel.fxSpeed ); - } - ]); - return panel; - }, - -//TODO: removeHdaView? - /** Set up/render a view for each HDA to be shown, init with model and listeners. - * HDA views are cached to the map this.hdaViews (using the model.id as key). - * @param {jQuery} $whereTo what dom element to prepend the HDA views to - * @returns the number of visible hda views - */ - views : function( at ){ - var panel = this, - visibleHdas = this.model.contents.getVisible( - this.storage.get( 'show_deleted' ), - this.storage.get( 'show_hidden' ), - this.filters - ); - if( at !== undefined ){ - return panel.hdaViews[ visibleHdas.at( at ).id ]; - } - return visibleHdas.map( function( hda ){ - return panel.hdaViews[ hda.id ]; - }); - }, - - /** convenience alias to the model. Updates the hda list only (not the history) */ - refreshContents : function( detailIds, options ){ - if( this.model ){ - return this.model.refresh( detailIds, options ); - } - // may have callbacks - so return an empty promise - return $.when(); - }, - - ///** use underscore's findWhere to find a view where the model matches the terms - // * note: finds and returns the _first_ matching - // */ - //findHdaView : function( terms ){ - // if( !this.model || !this.model.contents.length ){ return undefined; } - // var model = this.model.contents.findWhere( terms ); - // return ( model )?( this.hdaViews[ model.id ] ):( undefined ); - //}, - - hdaViewRange : function( viewA, viewB ){ - if( viewA === viewB ){ return [ viewA ]; } - //TODO: would probably be better if we cache'd the views as an ordered list (as well as a map) - var panel = this, - withinSet = false, - set = []; - this.model.contents.getVisible( - this.storage.get( 'show_deleted' ), - this.storage.get( 'show_hidden' ), - this.filters - ).each( function( hda ){ - //console.debug( 'checking: ', hda.get( 'name' ) ); - if( withinSet ){ - //console.debug( '\t\t adding: ', hda.get( 'name' ) ); - set.push( panel.hdaViews[ hda.id ] ); - if( hda === viewA.model || hda === viewB.model ){ - //console.debug( '\t found last: ', hda.get( 'name' ) ); - withinSet = false; - } - } else { - if( hda === viewA.model || hda === viewB.model ){ - //console.debug( 'found first: ', hda.get( 'name' ) ); - withinSet = true; - set.push( panel.hdaViews[ hda.id ] ); - } - } - }); - return set; - }, - - // ------------------------------------------------------------------------ panel events - /** event map */ - events : { - // allow (error) messages to be clicked away -//TODO: switch to common close (X) idiom - 'click .message-container' : 'clearMessages', - 'click .history-search-btn' : 'toggleSearchControls' - }, - - /** Collapse all hda bodies and clear expandedHdas in the storage */ - collapseAllHdaBodies : function(){ - _.each( this.hdaViews, function( item ){ - item.collapse(); - }); - this.storage.set( 'expandedHdas', {} ); - return this; - }, - - /** Handle the user toggling the deleted visibility by: - * (1) storing the new value in the persistent storage - * (2) re-rendering the history - * @returns {Boolean} new show_deleted setting - */ - toggleShowDeleted : function( show ){ - show = ( show !== undefined )?( show ):( !this.storage.get( 'show_deleted' ) ); - this.storage.set( 'show_deleted', show ); - this.renderHdas(); - return this.storage.get( 'show_deleted' ); - }, - - /** Handle the user toggling the deleted visibility by: - * (1) storing the new value in the persistent storage - * (2) re-rendering the history - * @returns {Boolean} new show_hidden setting - */ - toggleShowHidden : function( show ){ - show = ( show !== undefined )?( show ):( !this.storage.get( 'show_hidden' ) ); - this.storage.set( 'show_hidden', show ); - this.renderHdas(); - return this.storage.get( 'show_hidden' ); - }, - - // ........................................................................ hda search & filters - /** render a search input for filtering datasets shown - * (see the search section in the HDA model for implementation of the actual searching) - * return will start the search - * esc will clear the search - * clicking the clear button will clear the search - * uses searchInput in ui.js - */ - _setUpSearchInput : function( $where ){ - var panel = this, - inputSelector = '.history-search-input'; - - function onFirstSearch( searchFor ){ - //this.log( 'onFirstSearch', searchFor, panel ); - if( panel.model.contents.haveDetails() ){ - panel.searchHdas( searchFor ); - return; - } - panel.$el.find( inputSelector ).searchInput( 'toggle-loading' ); - panel.model.contents.fetchAllDetails({ silent: true }) - .always( function(){ - panel.$el.find( inputSelector ).searchInput( 'toggle-loading' ); - }) - .done( function(){ - panel.searchHdas( searchFor ); - }); - } - $where.searchInput({ - initialVal : panel.searchFor, - name : 'history-search', - placeholder : 'search datasets', - classes : 'history-search', - onfirstsearch : onFirstSearch, - onsearch : _.bind( this.searchHdas, this ), - onclear : _.bind( this.clearHdaSearch, this ) - }); - return $where; - }, - /** toggle showing/hiding the search controls (rendering first on the initial show) - * @param {Event or Number} eventOrSpeed variadic - if number the speed of the show/hide effect - * @param {boolean} show force show/hide with T/F - */ - toggleSearchControls : function( eventOrSpeed, show ){ - var $searchControls = this.$el.find( '.history-search-controls' ), - speed = ( jQuery.type( eventOrSpeed ) === 'number' )?( eventOrSpeed ):( this.fxSpeed ); - show = ( show !== undefined )?( show ):( !$searchControls.is( ':visible' ) ); - if( show ){ - $searchControls.slideDown( speed, function(){ - $( this ).find( 'input' ).focus(); - }); - } else { - $searchControls.slideUp( speed ); - } - return show; - }, - - /** filter hda view list to those that contain the searchFor terms - * (see the search section in the HDA model for implementation of the actual searching) - */ - searchHdas : function( searchFor ){ - //note: assumes hda details are loaded - //this.log( 'onSearch', searchFor, this ); - var panel = this; - this.searchFor = searchFor; - this.filters = [ function( hda ){ return hda.matchesAll( panel.searchFor ); } ]; - this.trigger( 'search:searching', searchFor, this ); - this.renderHdas(); - return this; - }, - - /** clear the search filters and show all views that are normally shown */ - clearHdaSearch : function( searchFor ){ - //this.log( 'onSearchClear', this ); - this.searchFor = ''; - this.filters = []; - this.trigger( 'search:clear', this ); - this.renderHdas(); - return this; - }, - - // ........................................................................ loading indicator - /** hide the panel and display a loading indicator (in the panel's parent) when history model's are switched */ - _showLoadingIndicator : function( msg, speed, callback ){ - speed = ( speed !== undefined )?( speed ):( this.fxSpeed ); - if( !this.indicator ){ - this.indicator = new LoadingIndicator( this.$el, this.$el.parent() ); - } - if( !this.$el.is( ':visible' ) ){ - this.indicator.show( 0, callback ); - } else { - this.$el.fadeOut( speed ); - this.indicator.show( msg, speed, callback ); - } - }, - - /** hide the loading indicator */ - _hideLoadingIndicator : function( speed, callback ){ - speed = ( speed !== undefined )?( speed ):( this.fxSpeed ); - if( this.indicator ){ - this.indicator.hide( speed, callback ); - } - }, - - // ........................................................................ (error) messages - /** Display a message in the top of the panel. - * @param {String} type type of message ('done', 'error', 'warning') - * @param {String} msg the message to display - * @param {Object or HTML} modal contents displayed when the user clicks 'details' in the message - */ - displayMessage : function( type, msg, details ){ - //precondition: msgContainer must have been rendered even if there's no model - var panel = this; - //this.log( 'displayMessage', type, msg, details ); - - this.scrollToTop(); - var $msgContainer = this.$messages(), - $msg = $( '
' ).addClass( type + 'message' ).html( msg ); - //this.log( ' ', $msgContainer ); - - if( !_.isEmpty( details ) ){ - var $detailsLink = $( 'Details' ) - .click( function(){ - Galaxy.modal.show( panel._messageToModalOptions( type, msg, details ) ); - return false; - }); - $msg.append( ' ', $detailsLink ); - } - return $msgContainer.html( $msg ); - }, - - /** convert msg and details into modal options usable by Galaxy.modal */ - _messageToModalOptions : function( type, msg, details ){ - // only error is fleshed out here - var panel = this, - $modalBody = $( '
' ), - options = { title: 'Details' }; - - //TODO: to some util library - function objToTable( obj ){ - obj = _.omit( obj, _.functions( obj ) ); - return [ - '', - _.map( obj, function( val, key ){ - val = ( _.isObject( val ) )?( objToTable( val ) ):( val ); - return '' - + ''; - }).join( '' ), - '
' + key + '' + val + '
' - ].join( '' ); - } - - if( _.isObject( details ) ){ - options.body = $modalBody.append( objToTable( details ) ); - - } else { - options.body = $modalBody.html( details ); - } - options.buttons = { - 'Ok': function(){ - Galaxy.modal.hide(); - panel.clearMessages(); - } - //TODO: if( type === 'error' ){ options.buttons[ 'Report this error' ] = function(){} } - }; - return options; - }, - - /** Remove all messages from the panel. - */ - clearMessages : function(){ - this.$messages().empty(); - return this; - }, - - // ........................................................................ scrolling - /** get the current scroll position of the panel in its parent */ - scrollPosition : function(){ - return this.$container().scrollTop(); - }, - - /** set the current scroll position of the panel in its parent */ - scrollTo : function( pos ){ - this.$container().scrollTop( pos ); - return this; - }, - - /** Scrolls the panel to the top. */ - scrollToTop : function(){ - this.$container().scrollTop( 0 ); - return this; - }, - - /** Scrolls the panel to show the HDA with the given id. - * @param {String} id the id of HDA to scroll into view - * @returns {HistoryPanel} the panel - */ - scrollToId : function( id ){ - // do nothing if id not found - if( ( !id ) || ( !this.hdaViews[ id ] ) ){ - return this; - } - var view = this.hdaViews[ id ]; - //this.scrollIntoView( $viewEl.offset().top ); - this.scrollTo( view.el.offsetTop ); - return this; - }, - - /** Scrolls the panel to show the HDA with the given hid. - * @param {Integer} hid the hid of HDA to scroll into view - * @returns {HistoryPanel} the panel - */ - scrollToHid : function( hid ){ - var hda = this.model.contents.getByHid( hid ); - // do nothing if hid not found - if( !hda ){ return this; } - return this.scrollToId( hda.id ); - }, - - // ........................................................................ misc - print : function(){ - var panel = this; - panel.debug( this ); - _.each( this.hdaViews, function( view, id ){ - panel.debug( '\t ' + id, view ); - }); - }, - - /** Return a string rep of the history */ - toString : function(){ - return 'ReadOnlyHistoryPanel(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')'; - } -}); -//------------------------------------------------------------------------------ TEMPLATES -var _panelTemplate = [ - '
', - '
', - '
', - '
', - - '
', - '<% if( history.name ){ %>', - '
<%= history.name %>
', - '<% } %>', - '
', - - '
', - '<% if( history.nice_size ){ %>', - '
<%= history.nice_size %>
', - '<% } %>', - '
', - '
', - - '<% if( history.deleted ){ %>', - '
', - _l( 'You are currently viewing a deleted history!' ), - '
', - '<% } %>', - - '
', - '<% if( history.message ){ %>', - // should already be localized - '
<%= history.message %>
', - '<% } %>', - '
', - - '
', - _l( 'You are over your disk quota' ), '. ', - _l( 'Tool execution is on hold until your disk usage drops below your allocated quota' ), '.', - '
', - - '
', - '
', - '
', - '
', - '', - '', - '
', - '', - '
', - '
', - // end history controls - - // where the datasets/hdas are added - '
', - '
', - _l( 'This history is empty' ), - '
' -].join( '' ); - -ReadOnlyHistoryPanel.templates = { - historyPanel : function( historyJSON ){ - return _.template( _panelTemplate, historyJSON, { variable: 'history' }); - } -}; - - -//============================================================================== - return { - ReadOnlyHistoryPanel: ReadOnlyHistoryPanel - }; -}); diff --git a/static/scripts/packed/mvc/collection/collection-li-edit.js b/static/scripts/packed/mvc/collection/collection-li-edit.js new file mode 100644 index 00000000000..5b0a5888a64 --- /dev/null +++ b/static/scripts/packed/mvc/collection/collection-li-edit.js @@ -0,0 +1 @@ +define(["mvc/collection/collection-li","utils/localization"],function(b,a){var c=b.DCListItemView;var d=c.extend({toString:function(){var e=(this.model)?(this.model+""):("(no model)");return"DCEListItemEdit("+e+")"}});return{DCEListItemEdit:d}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/collection/collection-li.js b/static/scripts/packed/mvc/collection/collection-li.js new file mode 100644 index 00000000000..9d566f2aac8 --- /dev/null +++ b/static/scripts/packed/mvc/collection/collection-li.js @@ -0,0 +1 @@ +define(["mvc/dataset/dataset-li","mvc/base-mvc","utils/localization"],function(h,d,f){var c=d.ListItemView;var a=c.extend({className:c.prototype.className+" dataset-collection",fxSpeed:"fast",initialize:function(i){if(i.logger){this.logger=this.model.logger=i.logger}this.log(this+"(DCListItemView).initialize:",i);c.prototype.initialize.call(this,i)},expand:function(){var i=this;return i._fetchModelDetails().always(function(){i.trigger("expanded",i)})},_renderSubtitle:function(){var i=$('
');switch(this.model.get("collection_type")){case"list":return i.text(f("a list of datasets"));case"paired":return i.text(f("a pair of datasets"));case"list:paired":return i.text(f("a list of paired datasets"))}return i},toString:function(){var i=(this.model)?(this.model+""):("(no model)");return"DCListItemView("+i+")"}});a.prototype.templates=(function(){var i=d.wrapTemplate(['
','
','<%- collection.element_identifier || collection.name %>',"
",'
',"
"],"collection");return _.extend({},c.prototype.templates,{titleBar:i})}());var b=c.extend({logger:console,className:c.prototype.className+" dataset-collection-element",fxSpeed:"fast",initialize:function(i){if(i.logger){this.logger=this.model.logger=i.logger}this.log("DCEListItemView.initialize:",i);c.prototype.initialize.call(this,i)},toString:function(){var i=(this.model)?(this.model+""):("(no model)");return"DCEListItemView("+i+")"}});b.prototype.templates=(function(){var i=d.wrapTemplate(['
','
','<%- element.element_identifier %>',"
",'
',"
"],"element");return _.extend({},c.prototype.templates,{titleBar:i})}());var e=h.DatasetListItemView.extend({className:h.DatasetListItemView.prototype.className+" dataset-collection-element",initialize:function(i){if(i.logger){this.logger=this.model.logger=i.logger}this.log("DatasetDCEListItemView.initialize:",i);h.DatasetListItemView.prototype.initialize.call(this,i)},toString:function(){var i=(this.model)?(this.model+""):("(no model)");return"DatasetDCEListItemView("+i+")"}});e.prototype.templates=(function(){var i=d.wrapTemplate(['
','','
','<%- element.element_identifier %>',"
","
"],"element");return _.extend({},h.DatasetListItemView.prototype.templates,{titleBar:i})}());var g=a.extend({className:a.prototype.className+" dataset-collection-element",_swapNewRender:function(i){a.prototype._swapNewRender.call(this,i);var j=this.model.get("state")||"ok";this.$el.addClass("state-"+j);return this.$el},toString:function(){var i=(this.model)?(this.model+""):("(no model)");return"NestedDCDCEListItemView("+i+")"}});return{DCListItemView:a,DCEListItemView:b,DatasetDCEListItemView:e,NestedDCDCEListItemView:g}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/collection/collection-model.js b/static/scripts/packed/mvc/collection/collection-model.js index febcaf365c3..8f875877880 100644 --- a/static/scripts/packed/mvc/collection/collection-model.js +++ b/static/scripts/packed/mvc/collection/collection-model.js @@ -1 +1 @@ -define(["mvc/dataset/dataset-model","mvc/base-mvc","utils/localization"],function(b,o,e){var f={defaults:{model_class:"DatasetCollectionElement",element_identifier:null,element_index:null,element_type:null},_mergeObject:function(q){_.extend(q,q.object);delete q.object;return q},constructor:function(q,r){this.debug("\t DatasetCollectionElement.constructor:",q,r);q=this._mergeObject(q);Backbone.Model.apply(this,arguments)},parse:function(r,s){var q=r;q=this._mergeObject(q);return q}};var p=Backbone.Model.extend(o.LoggableMixin).extend(f);var m=Backbone.Collection.extend(o.LoggableMixin).extend({model:p,initialize:function(q,r){this.debug(this+"(DCECollection).initialize:",q,r);r=r||{}},toString:function(){return(["DatasetCollectionElementCollection(",this.length,")"].join(""))}});var g=b.DatasetAssociation.extend(o.mixin(f,{defaults:_.extend({},b.DatasetAssociation.prototype.defaults,f.defaults),constructor:function(q,r){this.debug("\t DatasetDCE.constructor:",q,r);f.constructor.call(this,q,r)},initialize:function(q,r){this.debug(this+"(DatasetDCE).initialize:",q,r);b.DatasetAssociation.prototype.initialize.call(this,q,r)},toString:function(){var q=this.get("element_identifier");return(["DatasetDCE(",q,")"].join(""))}}));var l=m.extend({model:g,initialize:function(q,r){this.debug(this+"(DatasetDCECollection).initialize:",q,r);m.prototype.initialize.call(this,q,r)},toString:function(){return(["DatasetDCECollection(",this.length,")"].join(""))}});var i=Backbone.Model.extend(o.LoggableMixin).extend(o.SearchableModelMixin).extend({defaults:{collection_type:null,deleted:false},collectionClass:m,initialize:function(r,q){this.debug(this+"(DatasetCollection).initialize:",r,q,this);this.elements=this._createElementsModel();this.on("change:elements",function(){this.log("change:elements");this.elements=this._createElementsModel()})},_createElementsModel:function(){this.debug(this+"._createElementsModel",this.collectionClass,this.get("elements"),this.elements);var q=this.get("elements")||[];this.unset("elements",{silent:true});this.elements=new this.collectionClass(q);return this.elements},toJSON:function(){var q=Backbone.Model.prototype.toJSON.call(this);if(this.elements){q.elements=this.elements.toJSON()}return q},inReadyState:function(){return true},hasDetails:function(){this.debug("hasDetails:",this.elements.length);return this.elements.length!==0},getVisibleContents:function(q){return this.elements},"delete":function(q){if(this.get("deleted")){return jQuery.when()}return this.save({deleted:true},q)},undelete:function(q){if(!this.get("deleted")||this.get("purged")){return jQuery.when()}return this.save({deleted:false},q)},searchAttributes:["name"],toString:function(){var q=[this.get("id"),this.get("name")||this.get("element_identifier")];return"DatasetCollection("+(q.join(","))+")"}});var h=i.extend({collectionClass:l,initialize:function(r,q){this.debug(this+"(ListDatasetCollection).initialize:",r,q);i.prototype.initialize.call(this,r,q)},toString:function(){return(["ListDatasetCollection(",this.get("name"),")"].join(""))}});var d=h.extend({initialize:function(r,q){this.debug(this+"(PairDatasetCollection).initialize:",r,q);h.prototype.initialize.call(this,r,q)},toString:function(){return(["PairDatasetCollection(",this.get("name"),")"].join(""))}});var j=i.extend(o.mixin(f,{constructor:function(q,r){this.debug("\t NestedDCDCE.constructor:",q,r);f.constructor.call(this,q,r)},toString:function(){var q=(this.object)?(""+this.object):(this.get("element_identifier"));return(["NestedDCDCE(",q,")"].join(""))}}));var n=m.extend({model:j,initialize:function(r,q){this.debug(this+"(NestedDCDCECollection).initialize:",r,q);m.prototype.initialize.call(this,r,q)},toString:function(){return(["NestedDCDCECollection(",this.length,")"].join(""))}});var a=d.extend(o.mixin(f,{constructor:function(q,r){this.debug("\t NestedPairDCDCE.constructor:",q,r);f.constructor.call(this,q,r)},toString:function(){var q=(this.object)?(""+this.object):(this.get("element_identifier"));return(["NestedPairDCDCE(",q,")"].join(""))}}));var k=n.extend({model:a,initialize:function(r,q){this.debug(this+"(NestedPairDCDCECollection).initialize:",r,q);n.prototype.initialize.call(this,r,q)},toString:function(){return(["NestedPairDCDCECollection(",this.length,")"].join(""))}});var c=i.extend({collectionClass:k,initialize:function(q,r){this.debug(this+"(ListPairedDatasetCollection).initialize:",q,r);i.prototype.initialize.call(this,q,r)},toString:function(){return(["ListPairedDatasetCollection(",this.get("name"),")"].join(""))}});return{ListDatasetCollection:h,PairDatasetCollection:d,ListPairedDatasetCollection:c}}); \ No newline at end of file +define(["mvc/dataset/dataset-model","mvc/base-mvc","utils/localization"],function(l,o,d){var e={defaults:{model_class:"DatasetCollectionElement",element_identifier:null,element_index:null,element_type:null},_mergeObject:function(q){_.extend(q,q.object);delete q.object;return q},constructor:function(q,r){this.debug("\t DatasetCollectionElement.constructor:",q,r);q=this._mergeObject(q);Backbone.Model.apply(this,arguments)},parse:function(r,s){var q=r;q=this._mergeObject(q);return q}};var p=Backbone.Model.extend(o.LoggableMixin).extend(e);var m=Backbone.Collection.extend(o.LoggableMixin).extend({model:p,initialize:function(q,r){this.debug(this+"(DCECollection).initialize:",q,r);r=r||{}},toString:function(){return(["DatasetCollectionElementCollection(",this.length,")"].join(""))}});var f=l.DatasetAssociation.extend(o.mixin(e,{defaults:_.extend({},l.DatasetAssociation.prototype.defaults,e.defaults),constructor:function(q,r){this.debug("\t DatasetDCE.constructor:",q,r);e.constructor.call(this,q,r)},initialize:function(q,r){this.debug(this+"(DatasetDCE).initialize:",q,r);l.DatasetAssociation.prototype.initialize.call(this,q,r)},toString:function(){var q=this.get("element_identifier");return(["DatasetDCE(",q,")"].join(""))}}));var k=m.extend({model:f,initialize:function(q,r){this.debug(this+"(DatasetDCECollection).initialize:",q,r);m.prototype.initialize.call(this,q,r)},toString:function(){return(["DatasetDCECollection(",this.length,")"].join(""))}});var h=Backbone.Model.extend(o.LoggableMixin).extend(o.SearchableModelMixin).extend({defaults:{collection_type:null,deleted:false},collectionClass:m,initialize:function(r,q){this.debug(this+"(DatasetCollection).initialize:",r,q,this);this.elements=this._createElementsModel();this.on("change:elements",function(){this.log("change:elements");this.elements=this._createElementsModel()})},_createElementsModel:function(){this.debug(this+"._createElementsModel",this.collectionClass,this.get("elements"),this.elements);var q=this.get("elements")||[];this.unset("elements",{silent:true});this.elements=new this.collectionClass(q);return this.elements},toJSON:function(){var q=Backbone.Model.prototype.toJSON.call(this);if(this.elements){q.elements=this.elements.toJSON()}return q},inReadyState:function(){return true},hasDetails:function(){this.debug("hasDetails:",this.elements.length);return this.elements.length!==0},getVisibleContents:function(q){return this.elements},"delete":function(q){if(this.get("deleted")){return jQuery.when()}return this.save({deleted:true},q)},undelete:function(q){if(!this.get("deleted")||this.get("purged")){return jQuery.when()}return this.save({deleted:false},q)},searchAttributes:["name"],toString:function(){var q=[this.get("id"),this.get("name")||this.get("element_identifier")];return"DatasetCollection("+(q.join(","))+")"}});var g=h.extend({collectionClass:k,initialize:function(r,q){this.debug(this+"(ListDatasetCollection).initialize:",r,q);h.prototype.initialize.call(this,r,q)},toString:function(){return(["ListDatasetCollection(",this.get("name"),")"].join(""))}});var c=g.extend({initialize:function(r,q){this.debug(this+"(PairDatasetCollection).initialize:",r,q);g.prototype.initialize.call(this,r,q)},toString:function(){return(["PairDatasetCollection(",this.get("name"),")"].join(""))}});var i=h.extend(o.mixin(e,{constructor:function(q,r){this.debug("\t NestedDCDCE.constructor:",q,r);e.constructor.call(this,q,r)},toString:function(){var q=(this.object)?(""+this.object):(this.get("element_identifier"));return(["NestedDCDCE(",q,")"].join(""))}}));var n=m.extend({model:i,initialize:function(r,q){this.debug(this+"(NestedDCDCECollection).initialize:",r,q);m.prototype.initialize.call(this,r,q)},toString:function(){return(["NestedDCDCECollection(",this.length,")"].join(""))}});var a=c.extend(o.mixin(e,{constructor:function(q,r){this.debug("\t NestedPairDCDCE.constructor:",q,r);e.constructor.call(this,q,r)},toString:function(){var q=(this.object)?(""+this.object):(this.get("element_identifier"));return(["NestedPairDCDCE(",q,")"].join(""))}}));var j=n.extend({model:a,initialize:function(r,q){this.debug(this+"(NestedPairDCDCECollection).initialize:",r,q);n.prototype.initialize.call(this,r,q)},toString:function(){return(["NestedPairDCDCECollection(",this.length,")"].join(""))}});var b=h.extend({collectionClass:j,initialize:function(q,r){this.debug(this+"(ListPairedDatasetCollection).initialize:",q,r);h.prototype.initialize.call(this,q,r)},toString:function(){return(["ListPairedDatasetCollection(",this.get("name"),")"].join(""))}});return{ListDatasetCollection:g,PairDatasetCollection:c,ListPairedDatasetCollection:b}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/collection/collection-panel.js b/static/scripts/packed/mvc/collection/collection-panel.js index ad79285de3e..f5d0d6ba4ae 100644 --- a/static/scripts/packed/mvc/collection/collection-panel.js +++ b/static/scripts/packed/mvc/collection/collection-panel.js @@ -1 +1 @@ -define(["mvc/collection/dataset-collection-base","mvc/base-mvc","utils/localization"],function(f,a,e){var d=Backbone.View.extend(a.LoggableMixin).extend({tagName:"div",className:"dataset-collection-panel",fxSpeed:"fast",DatasetDCEViewClass:f.DatasetDCEBaseView,NestedDCEViewClass:f.NestedDCEBaseView,initialize:function(h){h=h||{};if(h.logger){this.logger=h.logger}this.log(this+".initialize:",h);this.hasUser=h.hasUser;this.panelStack=[];this.parentName=h.parentName},_setUpListeners:function(){this.on("all",function(h){this.log(this+"",arguments)},this);return this},_setUpModelEventHandlers:function(){return this},render:function(j,k){this.log("render:",j,k);j=(j===undefined)?(this.fxSpeed):(j);var h=this,i;if(!this.model){return this}i=this.renderModel();$(h).queue("fx",[function(l){if(j&&h.$el.is(":visible")){h.$el.fadeOut(j,l)}else{l()}},function(l){h.$el.empty();if(i){h.$el.append(i.children())}l()},function(l){if(j&&!h.$el.is(":visible")){h.$el.fadeIn(j,l)}else{l()}},function(l){if(k){k.call(this)}h.trigger("rendered",this);l()}]);return this},renderModel:function(){var j=this.model.get("collection_type")||this.model.object.get("collection_type"),i=_.extend(this.model.toJSON(),{parentName:this.parentName,type:j}),h=$("
").append(this.templates.panel(i));this._setUpBehaviours(h);this.renderContents(h);return h},_setUpBehaviours:function(h){h=h||this.$el;h.find("[title]").tooltip({placement:"bottom"});return this},$container:function(){return(this.findContainerFn)?(this.findContainerFn.call(this)):(this.$el.parent())},$datasetsList:function(h){return(h||this.$el).find(".datasets-list")},renderContents:function(i){i=i||this.$el;this.warn(this+".renderContents:, model:",this.model);var h=this,k={},j=this.model.getVisibleContents();this.log("renderContents, visibleContents:",j,i);this.$datasetsList(i).empty();if(j&&j.length){j.each(function(m){var n=m.id,l=h._createContentView(m);k[n]=l;h._attachContentView(l.render(),i)})}this.contentViews=k;return this.contentViews},_createContentView:function(j){var i=null,h=this._getContentClass(j);this.debug("ContentClass:",h);this.debug("content:",j);i=new h({model:j,linkTarget:this.linkTarget,hasUser:this.hasUser,logger:this.logger});this.debug("contentView:",i);this._setUpContentListeners(i);return i},_getContentClass:function(h){this.debug(this+"._getContentClass:",h);this.debug("DCEViewClass:",this.DCEViewClass);switch(h.get("element_type")){case"hda":return this.DCEViewClass;case"dataset_collection":return this.DCEViewClass}throw new TypeError("Unknown element type:",h.get("element_type"))},_setUpContentListeners:function(i){var h=this;if(i.model.get("element_type")==="dataset_collection"){i.on("expanded",function(j){h.info("expanded",j);h._addCollectionPanel(j)})}},_addCollectionPanel:function(j){var k=this,h=j.model;this.debug("collection panel (stack), collectionView:",j);this.debug("collection panel (stack), collectionModel:",h);var i=new c({model:h,parentName:this.model.get("name")});k.panelStack.push(i);k.$(".controls").add(".datasets-list").hide();k.$el.append(i.$el);i.on("close",function(){k.render();j.collapse();k.panelStack.pop()});if(!i.model.hasDetails()){var l=i.model.fetch();l.done(function(){i.render()})}else{i.render()}},_attachContentView:function(j,i){i=i||this.$el;var h=this.$datasetsList(i);h.append(j.$el);return this},events:{"click .navigation .back":"close"},close:function(h){this.$el.remove();this.trigger("close")},toString:function(){return"CollectionPanel("+((this.model)?(this.model.get("name")):(""))+")"}});d.templates=d.prototype.templates=(function(){var h=_.template(['
','",'
','
<%- collection.name || collection.element_identifier %>
','
','<% if( collection.type === "list" ){ %>',e("a list of datasets"),'<% } else if( collection.type === "paired" ){ %>',e("a pair of datasets"),'<% } else if( collection.type === "list:paired" ){ %>',e("a list of paired datasets"),"<% } %>","
","
","
",'
'].join(""));return{panel:function(i){return h({_l:e,collection:i})}}}());var b=d.extend({DCEViewClass:f.DatasetDCEBaseView,toString:function(){return"ListCollectionPanel("+((this.model)?(this.model.get("name")):(""))+")"}});var c=b.extend({toString:function(){return"PairCollectionPanel("+((this.model)?(this.model.get("name")):(""))+")"}});var g=d.extend({DCEViewClass:f.NestedDCDCEBaseView,toString:function(){return"ListOfPairsCollectionPanel("+((this.model)?(this.model.get("name")):(""))+")"}});return{CollectionPanel:d,ListCollectionPanel:b,PairCollectionPanel:c,ListOfPairsCollectionPanel:g}}); \ No newline at end of file +define(["mvc/collection/collection-model","mvc/collection/collection-li","mvc/base-mvc","utils/localization"],function(h,f,a,e){var d=Backbone.View.extend(a.LoggableMixin).extend({tagName:"div",className:"dataset-collection-panel",fxSpeed:"fast",DatasetDCEViewClass:f.DatasetDCEListItemView,NestedDCDCEViewClass:f.NestedDCDCEListItemView,initialize:function(i){i=i||{};if(i.logger){this.logger=i.logger}this.log(this+".initialize:",i);this.linkTarget=i.linkTarget||"_blank";this.hasUser=i.hasUser;this.panelStack=[];this.parentName=i.parentName;window.collectionPanel=this},_setUpListeners:function(){this.on("all",function(i){this.log(this+"",arguments)},this);return this},_setUpModelEventHandlers:function(){return this},render:function(k,l){this.log("render:",k,l);k=(k===undefined)?(this.fxSpeed):(k);var i=this,j;if(!this.model){return this}j=this.renderModel();$(i).queue("fx",[function(m){if(k&&i.$el.is(":visible")){i.$el.fadeOut(k,m)}else{m()}},function(m){i.$el.empty();if(j){i.$el.append(j.children())}m()},function(m){if(k&&!i.$el.is(":visible")){i.$el.fadeIn(k,m)}else{m()}},function(m){if(l){l.call(this)}i.trigger("rendered",this);m()}]);return this},renderModel:function(){var k=this.model.get("collection_type")||this.model.object.get("collection_type"),j=_.extend(this.model.toJSON(),{parentName:this.parentName,type:k}),i=$("
").append(this.templates.panel(j));this._setUpBehaviours(i);this.renderContents(i);return i},_setUpBehaviours:function(i){i=i||this.$el;i.find("[title]").tooltip({placement:"bottom"});return this},$container:function(){return(this.findContainerFn)?(this.findContainerFn.call(this)):(this.$el.parent())},$datasetsList:function(i){return(i||this.$el).find(".datasets-list")},renderContents:function(j){j=j||this.$el;this.warn(this+".renderContents:, model:",this.model);var i=this,l={},k=this.model.getVisibleContents();this.$datasetsList(j).empty();if(k&&k.length){k.each(function(n){var o=n.id,m=i._createContentView(n);l[o]=m;i._attachContentView(m.render(),j)})}this.contentViews=l;return this.contentViews},_createContentView:function(k){var j=null,i=this._getContentClass(k);j=new i({model:k,linkTarget:this.linkTarget,hasUser:this.hasUser,logger:this.logger});this._setUpContentListeners(j);return j},_getContentClass:function(i){switch(i.get("element_type")){case"hda":return this.DatasetDCEViewClass;case"dataset_collection":return this.NestedDCDCEViewClass}throw new TypeError("Unknown element type:",i.get("element_type"))},_setUpContentListeners:function(j){var i=this;if(j.model.get("element_type")==="dataset_collection"){j.on("expanded",function(k){i.info("expanded",k);i._addCollectionPanel(k)})}},_addCollectionPanel:function(k){var l=this,i=k.model;var j=new c({model:i,parentName:this.model.get("name"),linkTarget:this.linkTarget});l.panelStack.push(j);l.$(".controls").add(".datasets-list").hide();l.$el.append(j.$el);j.on("close",function(){l.render();k.collapse();l.panelStack.pop()});if(!j.model.hasDetails()){var m=j.model.fetch();m.done(function(){j.render()})}else{j.render()}},_attachContentView:function(k,j){j=j||this.$el;var i=this.$datasetsList(j);i.append(k.$el);return this},events:{"click .navigation .back":"close"},close:function(i){this.$el.remove();this.trigger("close")},toString:function(){return"CollectionPanel("+((this.model)?(this.model.get("name")):(""))+")"}});d.templates=d.prototype.templates=(function(){var i=_.template(['
','",'
','
<%- collection.name || collection.element_identifier %>
','
','<% if( collection.type === "list" ){ %>',e("a list of datasets"),'<% } else if( collection.type === "paired" ){ %>',e("a pair of datasets"),'<% } else if( collection.type === "list:paired" ){ %>',e("a list of paired datasets"),"<% } %>","
","
","
",'
'].join(""));return{panel:function(j){return i({_l:e,collection:j})}}}());var b=d.extend({DatasetDCEViewClass:f.DatasetDCEListItemView,toString:function(){return"ListCollectionPanel("+((this.model)?(this.model.get("name")):(""))+")"}});var c=b.extend({toString:function(){return"PairCollectionPanel("+((this.model)?(this.model.get("name")):(""))+")"}});var g=d.extend({NestedDCDCEViewClass:f.NestedDCDCEListItemView,toString:function(){return"ListOfPairsCollectionPanel("+((this.model)?(this.model.get("name")):(""))+")"}});return{CollectionPanel:d,ListCollectionPanel:b,PairCollectionPanel:c,ListOfPairsCollectionPanel:g}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/collection/dataset-collection-base.js b/static/scripts/packed/mvc/collection/dataset-collection-base.js deleted file mode 100644 index 5e44e0f2fe4..00000000000 --- a/static/scripts/packed/mvc/collection/dataset-collection-base.js +++ /dev/null @@ -1 +0,0 @@ -define(["mvc/dataset/dataset-list-element","mvc/base-mvc","utils/localization"],function(g,c,d){var b=c.ListItemView;var a=b.extend({className:b.prototype.className+" dataset-collection",fxSpeed:"fast",initialize:function(i){if(i.logger){this.logger=this.model.logger=i.logger}this.log("DCBaseView.initialize:",i);b.prototype.initialize.call(this,i)},expand:function(){var i=this;return i._fetchModelDetails().always(function(){i.trigger("expanded",i)})},_renderSubtitle:function(){var i=$('
');switch(this.model.get("collection_type")){case"list":return i.text(d("a list of datasets"));case"paired":return i.text(d("a pair of datasets"));case"list:paired":return i.text(d("a list of paired datasets"))}return i},toString:function(){var i=(this.model)?(this.model+""):("(no model)");return"DCBaseView("+i+")"}});a.prototype.templates=(function(){var i=c.wrapTemplate(['
','
','<%- collection.element_identifier || collection.name %>',"
",'
',"
"],"collection");return _.extend({},b.prototype.templates,{titleBar:i})}());var f=b.extend({logger:console,className:b.prototype.className+" dataset-collection-element",fxSpeed:"fast",initialize:function(i){if(i.logger){this.logger=this.model.logger=i.logger}this.log("DCEBaseView.initialize:",i);b.prototype.initialize.call(this,i)},toString:function(){var i=(this.model)?(this.model+""):("(no model)");return"DCEBaseView("+i+")"}});f.prototype.templates=(function(){var i=c.wrapTemplate(['
','
','<%- element.element_identifier %>',"
",'
',"
"],"element");return _.extend({},b.prototype.templates,{titleBar:i})}());var h=g.DatasetListItemView.extend({className:g.DatasetListItemView.prototype.className+" dataset-collection-element",initialize:function(i){if(i.logger){this.logger=this.model.logger=i.logger}this.log("DatasetDCEBaseView.initialize:",i);g.DatasetListItemView.prototype.initialize.call(this,i)},toString:function(){var i=(this.model)?(this.model+""):("(no model)");return"DatasetDCEBaseView("+i+")"}});h.prototype.templates=(function(){var i=c.wrapTemplate(['
','','
','<%- element.element_identifier %>',"
","
"],"element");return _.extend({},g.DatasetListItemView.prototype.templates,{titleBar:i})}());var e=a.extend({className:a.prototype.className+" dataset-collection-element",_swapNewRender:function(i){g.DatasetListItemView.prototype._swapNewRender.call(this,i);var j=this.model.get("state")||"ok";this.$el.addClass("state-"+j);return this.$el},toString:function(){var i=(this.model)?(this.model+""):("(no model)");return"NestedDCDCEBaseView("+i+")"}});return{DCBaseView:a,DCEBaseView:f,DatasetDCEBaseView:h,NestedDCDCEBaseView:e}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/collection/dataset-collection-edit.js b/static/scripts/packed/mvc/collection/dataset-collection-edit.js deleted file mode 100644 index 2c79fa66cee..00000000000 --- a/static/scripts/packed/mvc/collection/dataset-collection-edit.js +++ /dev/null @@ -1 +0,0 @@ -define(["mvc/dataset/states","mvc/collection/dataset-collection-base","utils/localization"],function(b,e,c){var d=e.DCBaseView;var a=d.extend({toString:function(){var f=(this.model)?(this.model+""):("(no model)");return"DCEditView("+f+")"}});return{DCEditView:a}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/collection/hdca-base.js b/static/scripts/packed/mvc/collection/hdca-base.js deleted file mode 100644 index aa2fcf81003..00000000000 --- a/static/scripts/packed/mvc/collection/hdca-base.js +++ /dev/null @@ -1 +0,0 @@ -define(["mvc/dataset/states","mvc/collection/dataset-collection-base","mvc/base-mvc","utils/localization"],function(a,d,b,c){var e=d.DCBaseView;var f=e.extend({className:e.prototype.className+" history-content",_swapNewRender:function(g){e.prototype._swapNewRender.call(this,g);var h=this.model.get("state")||a.OK;this.$el.addClass("state-"+h);return this.$el},toString:function(){var g=(this.model)?(this.model+""):("(no model)");return"HDCABaseView("+g+")"}});f.prototype.templates=(function(){var g=b.wrapTemplate(['
','','
','<%- collection.hid %> ','<%- collection.name %>',"
",'
',"
"],"collection");return _.extend({},e.prototype.templates,{titleBar:g})}());return{HDCABaseView:f}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/collection/hdca-edit.js b/static/scripts/packed/mvc/collection/hdca-edit.js deleted file mode 100644 index 69c2247338c..00000000000 --- a/static/scripts/packed/mvc/collection/hdca-edit.js +++ /dev/null @@ -1 +0,0 @@ -define(["mvc/dataset/states","mvc/collection/hdca-base","utils/localization"],function(a,e,b){var d=e.HDCABaseView;var c=d.extend({_renderPrimaryActions:function(){this.log(this+"._renderPrimaryActions");return d.prototype._renderPrimaryActions.call(this).concat([this._renderDeleteButton()])},_renderDeleteButton:function(){var g=this,f=this.model.get("deleted");return faIconButton({title:f?b("Dataset collection is already deleted"):b("Delete"),classes:"delete-btn",faIcon:"fa-times",disabled:f,onclick:function(){g.$el.find(".icon-btn.delete-btn").trigger("mouseout");g.model["delete"]()}})},toString:function(){var f=(this.model)?(this.model+""):("(no model)");return"HDCAEditView("+f+")"}});return{HDCAEditView:c}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/collection/hdca-model.js b/static/scripts/packed/mvc/collection/hdca-model.js deleted file mode 100644 index 58199bec778..00000000000 --- a/static/scripts/packed/mvc/collection/hdca-model.js +++ /dev/null @@ -1 +0,0 @@ -define(["mvc/history/history-content-base","mvc/collection/collection-model","utils/localization"],function(i,c,a){var g=i.HistoryContentMixin,h=c.ListDatasetCollection,j=c.PairDatasetCollection,f=c.ListPairedDatasetCollection;var d=h.extend(g).extend({initialize:function(l,k){h.prototype.initialize.call(this,l,k);g.initialize.call(this,l,k)},toString:function(){return(["HistoryListDatasetCollection(",this.get("name"),")"].join(""))}});var e=j.extend(g).extend({initialize:function(l,k){j.prototype.initialize.call(this,l,k);g.initialize.call(this,l,k)},toString:function(){return(["HistoryPairDatasetCollection(",this.get("name"),")"].join(""))}});var b=f.extend(g).extend({initialize:function(l,k){f.prototype.initialize.call(this,l,k);g.initialize.call(this,l,k)},toString:function(){return(["HistoryListPairedDatasetCollection(",this.get("name"),")"].join(""))}});return{HistoryListDatasetCollection:d,HistoryPairDatasetCollection:e,HistoryListPairedDatasetCollection:b}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/dataset/dataset-li-edit.js b/static/scripts/packed/mvc/dataset/dataset-li-edit.js new file mode 100644 index 00000000000..8b4563710e0 --- /dev/null +++ b/static/scripts/packed/mvc/dataset/dataset-li-edit.js @@ -0,0 +1 @@ +define(["mvc/dataset/states","mvc/dataset/dataset-li","mvc/tags","mvc/annotations","mvc/base-mvc","utils/localization"],function(g,d,e,a,h,b){var f=d.DatasetListItemView;var i=f.extend({initialize:function(j){f.prototype.initialize.call(this,j);this.hasUser=j.hasUser;this.purgeAllowed=j.purgeAllowed||false;this.tagsEditorShown=j.tagsEditorShown||false;this.annotationEditorShown=j.annotationEditorShown||false},_renderPrimaryActions:function(){var j=f.prototype._renderPrimaryActions.call(this);if(this.model.get("state")===g.NOT_VIEWABLE){return j}return f.prototype._renderPrimaryActions.call(this).concat([this._renderEditButton(),this._renderDeleteButton()])},_renderEditButton:function(){if((this.model.get("state")===g.DISCARDED)||(!this.model.get("accessible"))){return null}var l=this.model.get("purged"),j=this.model.get("deleted"),k={title:b("Edit attributes"),href:this.model.urls.edit,target:this.linkTarget,faIcon:"fa-pencil",classes:"edit-btn"};if(j||l){k.disabled=true;if(l){k.title=b("Cannot edit attributes of datasets removed from disk")}else{if(j){k.title=b("Undelete dataset to edit attributes")}}}else{if(_.contains([g.UPLOAD,g.NEW],this.model.get("state"))){k.disabled=true;k.title=b("This dataset is not yet editable")}}return faIconButton(k)},_renderDeleteButton:function(){if((!this.model.get("accessible"))){return null}var j=this,k=this.model.isDeletedOrPurged();return faIconButton({title:!k?b("Delete"):b("Dataset is already deleted"),disabled:k,faIcon:"fa-times",classes:"delete-btn",onclick:function(){j.$el.find(".icon-btn.delete-btn").trigger("mouseout");j.model["delete"]()}})},_renderDetails:function(){var j=f.prototype._renderDetails.call(this),k=this.model.get("state");if(!this.model.isDeletedOrPurged()&&_.contains([g.OK,g.FAILED_METADATA],k)){this._renderTags(j);this._renderAnnotation(j);this._makeDbkeyEditLink(j)}this._setUpBehaviors(j);return j},_renderSecondaryActions:function(){var j=f.prototype._renderSecondaryActions.call(this);switch(this.model.get("state")){case g.UPLOAD:case g.NEW:case g.NOT_VIEWABLE:return j;case g.ERROR:j.unshift(this._renderErrButton());return j.concat([this._renderRerunButton()]);case g.OK:case g.FAILED_METADATA:return j.concat([this._renderRerunButton(),this._renderVisualizationsButton()])}return j.concat([this._renderRerunButton()])},_renderErrButton:function(){return faIconButton({title:b("View or report this error"),href:this.model.urls.report_error,classes:"report-error-btn",target:this.linkTarget,faIcon:"fa-bug"})},_renderRerunButton:function(){return faIconButton({title:b("Run this job again"),href:this.model.urls.rerun,classes:"rerun-btn",target:this.linkTarget,faIcon:"fa-refresh"})},_renderVisualizationsButton:function(){var j=this.model.get("visualizations");if((this.model.isDeletedOrPurged())||(!this.hasUser)||(!this.model.hasData())||(_.isEmpty(j))){return null}if(!_.isObject(j[0])){this.warn("Visualizations have been switched off");return null}var k=$(this.templates.visualizations(j,this));this._addScratchBookFn(k.find(".visualization-link").addBack(".visualization-link"));return k},_addScratchBookFn:function(j){j.click(function(k){if(Galaxy.frame&&Galaxy.frame.active){Galaxy.frame.add({title:"Visualization",type:"url",content:$(this).attr("href")});k.preventDefault();k.stopPropagation()}})},_renderTags:function(j){if(!this.hasUser){return}var k=this;this.tagsEditor=new e.TagsEditor({model:this.model,el:j.find(".tags-display"),onshowFirstTime:function(){this.render()},onshow:function(){k.tagsEditorShown=true},onhide:function(){k.tagsEditorShown=false},$activator:faIconButton({title:b("Edit dataset tags"),classes:"tag-btn",faIcon:"fa-tags"}).appendTo(j.find(".actions .right"))});if(this.tagsEditorShown){this.tagsEditor.toggle(true)}},_renderAnnotation:function(j){if(!this.hasUser){return}var k=this;this.annotationEditor=new a.AnnotationEditor({model:this.model,el:j.find(".annotation-display"),onshowFirstTime:function(){this.render()},onshow:function(){k.annotationEditorShown=true},onhide:function(){k.annotationEditorShown=false},$activator:faIconButton({title:b("Edit dataset annotation"),classes:"annotate-btn",faIcon:"fa-comment"}).appendTo(j.find(".actions .right"))});if(this.annotationEditorShown){this.annotationEditor.toggle(true)}},_makeDbkeyEditLink:function(j){if(this.model.get("metadata_dbkey")==="?"&&!this.model.isDeletedOrPurged()){var k=$('?').attr("href",this.model.urls.edit).attr("target",this.linkTarget);j.find(".dbkey .value").replaceWith(k)}},events:_.extend(_.clone(f.prototype.events),{"click .undelete-link":function(j){this.model.undelete();return false},"click .purge-link":"_confirmPurge"}),_confirmPurge:function c(j){this.model.purge();return false},toString:function(){var j=(this.model)?(this.model+""):("(no model)");return"HDAEditView("+j+")"}});i.prototype.templates=(function(){var k=_.extend({},f.prototype.templates.warnings,{failed_metadata:h.wrapTemplate(['<% if( dataset.state === "failed_metadata" ){ %>','","<% } %>"],"dataset"),deleted:h.wrapTemplate(["<% if( dataset.deleted && !dataset.purged ){ %>",'
',b("This dataset has been deleted"),'
',b("Undelete it"),"","<% if( view.purgeAllowed ){ %>",'
',b("Permanently remove it from disk"),"","<% } %>","
","<% } %>"],"dataset")});var j=h.wrapTemplate(["<% if( visualizations.length === 1 ){ %>",'">','',"","<% } else { %>",'","<% } %>"],"visualizations");return _.extend({},f.prototype.templates,{warnings:k,visualizations:j})}());return{DatasetListItemEdit:i}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/dataset/dataset-list-element.js b/static/scripts/packed/mvc/dataset/dataset-li.js similarity index 100% rename from static/scripts/packed/mvc/dataset/dataset-list-element.js rename to static/scripts/packed/mvc/dataset/dataset-li.js diff --git a/static/scripts/packed/mvc/dataset/dataset-model.js b/static/scripts/packed/mvc/dataset/dataset-model.js index 0d15452e1b7..121a1e1de44 100644 --- a/static/scripts/packed/mvc/dataset/dataset-model.js +++ b/static/scripts/packed/mvc/dataset/dataset-model.js @@ -1 +1 @@ -define(["mvc/dataset/states","mvc/base-mvc","utils/localization"],function(a,b,c){var f=b.SearchableModelMixin;var e=Backbone.Model.extend(b.LoggableMixin).extend(b.mixin(f,{defaults:{state:a.NEW,deleted:false,purged:false,name:"(unnamed dataset)",accessible:true,data_type:"",file_ext:"",file_size:0,meta_files:[],misc_blurb:"",misc_info:"",tags:[]},initialize:function(h,g){this.debug("Dataset.initialize",h,g);if(!this.get("accessible")){this.set("state",a.NOT_VIEWABLE)}this.urls=this._generateUrls();this._setUpListeners()},_generateUrls:function(){var h=this.get("id");if(!h){return{}}var g={purge:"datasets/"+h+"/purge_async",display:"datasets/"+h+"/display/?preview=True",edit:"datasets/"+h+"/edit",download:"datasets/"+h+"/display?to_ext="+this.get("file_ext"),report_error:"dataset/errors?id="+h,rerun:"tool_runner/rerun?id="+h,show_params:"datasets/"+h+"/show_params",visualization:"visualization",meta_download:"dataset/get_metadata_file?hda_id="+h+"&metadata_name="};if(galaxy_config&&galaxy_config.root){_.each(g,function(i,j){g[i]=galaxy_config.root+j})}this.urls=g;return g},_setUpListeners:function(){this.on("change:state",function(h,g){this.log(this+" has changed state:",h,g);if(this.inReadyState()){this.trigger("state:ready",h,g,this.previous("state"))}});this.on("change:id change:file_ext",function(g){this._generateUrls()})},toJSON:function(){var g=Backbone.Model.prototype.toJSON.call(this);return _.extend(g,{urls:this.urls})},isDeletedOrPurged:function(){return(this.get("deleted")||this.get("purged"))},inReadyState:function(){var g=_.contains(a.READY_STATES,this.get("state"));return(this.isDeletedOrPurged()||g)},hasDetails:function(){return _.has(this.attributes,"genome_build")},hasData:function(){return(this.get("file_size")>0)},"delete":function(g){if(this.get("deleted")){return jQuery.when()}return this.save({deleted:true},g)},undelete:function(g){if(!this.get("deleted")||this.get("purged")){return jQuery.when()}return this.save({deleted:false},g)},purge:function d(g){if(this.get("purged")){return jQuery.when()}g=g||{};g.url=this.urls.purge;var h=this,i=jQuery.ajax(g);i.done(function(l,j,k){h.set({deleted:true,purged:true})});i.fail(function(n,j,m){var k=c("Unable to purge dataset");var l=("Removal of datasets by users is not allowed in this Galaxy instance");if(n.responseJSON&&n.responseJSON.error){k=n.responseJSON.error}else{if(n.responseText.indexOf(l)!==-1){k=l}}n.responseText=k;h.trigger("error",h,n,g,c(k),{error:k})});return i},searchAttributes:["name","file_ext","genome_build","misc_blurb","misc_info","annotation","tags"],searchAliases:{title:"name",format:"file_ext",database:"genome_build",blurb:"misc_blurb",description:"misc_blurb",info:"misc_info",tag:"tags"},toString:function(){var g=this.get("id")||"";if(this.get("name")){g='"'+this.get("name")+'",'+g}return"Dataset("+g+")"}}));return{DatasetAssociation:e}}); \ No newline at end of file +define(["mvc/dataset/states","mvc/base-mvc","utils/localization"],function(a,b,c){var f=b.SearchableModelMixin;var e=Backbone.Model.extend(b.LoggableMixin).extend(b.mixin(f,{defaults:{state:a.NEW,deleted:false,purged:false,name:"(unnamed dataset)",accessible:true,data_type:"",file_ext:"",file_size:0,meta_files:[],misc_blurb:"",misc_info:"",tags:[]},initialize:function(h,g){this.debug("Dataset.initialize",h,g);if(!this.get("accessible")){this.set("state",a.NOT_VIEWABLE)}this.urls=this._generateUrls();this._setUpListeners()},_generateUrls:function(){var i=this.get("id");if(!i){return{}}var h={purge:"datasets/"+i+"/purge_async",display:"datasets/"+i+"/display/?preview=True",edit:"datasets/"+i+"/edit",download:"datasets/"+i+"/display?to_ext="+this.get("file_ext"),report_error:"dataset/errors?id="+i,rerun:"tool_runner/rerun?id="+i,show_params:"datasets/"+i+"/show_params",visualization:"visualization",meta_download:"dataset/get_metadata_file?hda_id="+i+"&metadata_name="};var g=(galaxy_config&&galaxy_config.root)?(galaxy_config.root):("/");_.each(h,function(k,j){h[j]=g+k});this.urls=h;return h},_setUpListeners:function(){this.on("change:state",function(h,g){this.log(this+" has changed state:",h,g);if(this.inReadyState()){this.trigger("state:ready",h,g,this.previous("state"))}});this.on("change:id change:file_ext",function(g){this._generateUrls()})},toJSON:function(){var g=Backbone.Model.prototype.toJSON.call(this);return _.extend(g,{urls:this.urls})},isDeletedOrPurged:function(){return(this.get("deleted")||this.get("purged"))},inReadyState:function(){var g=_.contains(a.READY_STATES,this.get("state"));return(this.isDeletedOrPurged()||g)},hasDetails:function(){return _.has(this.attributes,"genome_build")},hasData:function(){return(this.get("file_size")>0)},"delete":function(g){if(this.get("deleted")){return jQuery.when()}return this.save({deleted:true},g)},undelete:function(g){if(!this.get("deleted")||this.get("purged")){return jQuery.when()}return this.save({deleted:false},g)},purge:function d(g){if(this.get("purged")){return jQuery.when()}g=g||{};g.url=this.urls.purge;var h=this,i=jQuery.ajax(g);i.done(function(l,j,k){h.set({deleted:true,purged:true})});i.fail(function(n,j,m){var k=c("Unable to purge dataset");var l=("Removal of datasets by users is not allowed in this Galaxy instance");if(n.responseJSON&&n.responseJSON.error){k=n.responseJSON.error}else{if(n.responseText.indexOf(l)!==-1){k=l}}n.responseText=k;h.trigger("error",h,n,g,c(k),{error:k})});return i},searchAttributes:["name","file_ext","genome_build","misc_blurb","misc_info","annotation","tags"],searchAliases:{title:"name",format:"file_ext",database:"genome_build",blurb:"misc_blurb",description:"misc_blurb",info:"misc_info",tag:"tags"},toString:function(){var g=this.get("id")||"";if(this.get("name")){g='"'+this.get("name")+'",'+g}return"Dataset("+g+")"}}));return{DatasetAssociation:e}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/dataset/editable-dataset-list-element.js b/static/scripts/packed/mvc/dataset/editable-dataset-list-element.js deleted file mode 100644 index 0166fe501c5..00000000000 --- a/static/scripts/packed/mvc/dataset/editable-dataset-list-element.js +++ /dev/null @@ -1 +0,0 @@ -define(["mvc/dataset/states","mvc/dataset/dataset-list-element","mvc/tags","mvc/annotations","mvc/base-mvc","utils/localization"],function(h,e,f,a,i,b){var g=e.DatasetListItemView;var d=g.extend({initialize:function(j){g.prototype.initialize.call(this,j);this.hasUser=j.hasUser;this.purgeAllowed=j.purgeAllowed||false;this.tagsEditorShown=j.tagsEditorShown||false;this.annotationEditorShown=j.annotationEditorShown||false},_renderPrimaryActions:function(){var j=g.prototype._renderPrimaryActions.call(this);if(this.model.get("state")===h.NOT_VIEWABLE){return j}return g.prototype._renderPrimaryActions.call(this).concat([this._renderEditButton(),this._renderDeleteButton()])},_renderEditButton:function(){if((this.model.get("state")===h.DISCARDED)||(!this.model.get("accessible"))){return null}var l=this.model.get("purged"),j=this.model.get("deleted"),k={title:b("Edit attributes"),href:this.model.urls.edit,target:this.linkTarget,faIcon:"fa-pencil",classes:"edit-btn"};if(j||l){k.disabled=true;if(l){k.title=b("Cannot edit attributes of datasets removed from disk")}else{if(j){k.title=b("Undelete dataset to edit attributes")}}}else{if(_.contains([h.UPLOAD,h.NEW],this.model.get("state"))){k.disabled=true;k.title=b("This dataset is not yet editable")}}return faIconButton(k)},_renderDeleteButton:function(){if((!this.model.get("accessible"))){return null}var j=this,k=this.model.isDeletedOrPurged();return faIconButton({title:!k?b("Delete"):b("Dataset is already deleted"),disabled:k,faIcon:"fa-times",classes:"delete-btn",onclick:function(){j.$el.find(".icon-btn.delete-btn").trigger("mouseout");j.model["delete"]()}})},_renderDetails:function(){var j=g.prototype._renderDetails.call(this),k=this.model.get("state");if(!this.model.isDeletedOrPurged()&&_.contains([h.OK,h.FAILED_METADATA],k)){this._renderTags(j);this._renderAnnotation(j);this._makeDbkeyEditLink(j)}this._setUpBehaviors(j);return j},_renderSecondaryActions:function(){var j=g.prototype._renderSecondaryActions.call(this);switch(this.model.get("state")){case h.UPLOAD:case h.NEW:case h.NOT_VIEWABLE:return j;case h.ERROR:j.unshift(this._renderErrButton());return j.concat([this._renderRerunButton()]);case h.OK:case h.FAILED_METADATA:return j.concat([this._renderRerunButton(),this._renderVisualizationsButton()])}return j.concat([this._renderRerunButton()])},_renderErrButton:function(){return faIconButton({title:b("View or report this error"),href:this.model.urls.report_error,classes:"report-error-btn",target:this.linkTarget,faIcon:"fa-bug"})},_renderRerunButton:function(){return faIconButton({title:b("Run this job again"),href:this.model.urls.rerun,classes:"rerun-btn",target:this.linkTarget,faIcon:"fa-refresh"})},_renderVisualizationsButton:function(){var j=this.model.get("visualizations");if((this.model.isDeletedOrPurged())||(!this.hasUser)||(!this.model.hasData())||(_.isEmpty(j))){return null}if(!_.isObject(j[0])){this.warn("Visualizations have been switched off");return null}var k=$(this.templates.visualizations(j,this));this._addScratchBookFn(k.find(".visualization-link").addBack(".visualization-link"));return k},_addScratchBookFn:function(j){j.click(function(k){if(Galaxy.frame&&Galaxy.frame.active){Galaxy.frame.add({title:"Visualization",type:"url",content:$(this).attr("href")});k.preventDefault();k.stopPropagation()}})},_renderTags:function(j){if(!this.hasUser){return}var k=this;this.tagsEditor=new f.TagsEditor({model:this.model,el:j.find(".tags-display"),onshowFirstTime:function(){this.render()},onshow:function(){k.tagsEditorShown=true},onhide:function(){k.tagsEditorShown=false},$activator:faIconButton({title:b("Edit dataset tags"),classes:"tag-btn",faIcon:"fa-tags"}).appendTo(j.find(".actions .right"))});if(this.tagsEditorShown){this.tagsEditor.toggle(true)}},_renderAnnotation:function(j){if(!this.hasUser){return}var k=this;this.annotationEditor=new a.AnnotationEditor({model:this.model,el:j.find(".annotation-display"),onshowFirstTime:function(){this.render()},onshow:function(){k.annotationEditorShown=true},onhide:function(){k.annotationEditorShown=false},$activator:faIconButton({title:b("Edit dataset annotation"),classes:"annotate-btn",faIcon:"fa-comment"}).appendTo(j.find(".actions .right"))});if(this.annotationEditorShown){this.annotationEditor.toggle(true)}},_makeDbkeyEditLink:function(j){if(this.model.get("metadata_dbkey")==="?"&&!this.model.isDeletedOrPurged()){var k=$('?').attr("href",this.model.urls.edit).attr("target",this.linkTarget);j.find(".dbkey .value").replaceWith(k)}},events:_.extend(_.clone(g.prototype.events),{"click .undelete-link":function(j){this.model.undelete();return false},"click .purge-link":"_confirmPurge"}),_confirmPurge:function c(j){this.model.purge();return false},toString:function(){var j=(this.model)?(this.model+""):("(no model)");return"HDAEditView("+j+")"}});d.prototype.templates=(function(){var k=_.extend({},g.prototype.templates.warnings,{failed_metadata:i.wrapTemplate(['<% if( dataset.state === "failed_metadata" ){ %>','","<% } %>"],"dataset"),deleted:i.wrapTemplate(["<% if( dataset.deleted && !dataset.purged ){ %>",'
',b("This dataset has been deleted"),'
',b("Undelete it"),"","<% if( view.purgeAllowed ){ %>",'
',b("Permanently remove it from disk"),"","<% } %>","
","<% } %>"],"dataset")});var j=i.wrapTemplate(["<% if( visualizations.length === 1 ){ %>",'">','',"","<% } else { %>",'","<% } %>"],"visualizations");return _.extend({},g.prototype.templates,{warnings:k,visualizations:j})}());return{EditableDatasetListItemView:d}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/dataset/hda-base.js b/static/scripts/packed/mvc/dataset/hda-base.js deleted file mode 100644 index c80fab31c1e..00000000000 --- a/static/scripts/packed/mvc/dataset/hda-base.js +++ /dev/null @@ -1 +0,0 @@ -define(["mvc/dataset/dataset-list-element","mvc/base-mvc","utils/localization"],function(e,b,c){var d=e.DatasetListItemView;var a=d.extend({initialize:function(f,g){d.prototype.initialize.call(this,f,g)},className:d.prototype.className+" history-content",toString:function(){var f=(this.model)?(this.model+""):("(no model)");return"HDABaseView("+f+")"}});a.prototype.templates=(function(){var g=b.wrapTemplate(['
','','
','<%- dataset.hid %> ','<%- dataset.name %>',"
","
"],"dataset");var f=_.extend({},d.prototype.templates.warnings,{hidden:b.wrapTemplate(["<% if( !dataset.visible ){ %>",'
',c("This dataset has been hidden"),"
","<% } %>"],"dataset")});return _.extend({},d.prototype.templates,{titleBar:g,warnings:f})}());return{HDABaseView:a}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/dataset/hda-edit.js b/static/scripts/packed/mvc/dataset/hda-edit.js deleted file mode 100644 index 230955a9fa5..00000000000 --- a/static/scripts/packed/mvc/dataset/hda-edit.js +++ /dev/null @@ -1 +0,0 @@ -define(["mvc/dataset/editable-dataset-list-element","mvc/dataset/hda-base","mvc/base-mvc","utils/localization"],function(e,a,b,c){var d=e.EditableDatasetListItemView;var f=d.extend({className:d.prototype.className+" history-content",events:_.extend(_.clone(d.prototype.events),{"click .unhide-link":function(g){this.model.unhide();return false}}),toString:function(){var g=(this.model)?(this.model+""):("(no model)");return"HDAEditView("+g+")"}});f.prototype.templates=(function(){var g=_.extend({},d.prototype.templates.warnings,{hidden:b.wrapTemplate(["<% if( !dataset.visible ){ %>",'
',c("This dataset has been hidden"),'
',c("Unhide it"),"","
","<% } %>"],"dataset")});return _.extend({},d.prototype.templates,{titleBar:a.HDABaseView.prototype.templates.titleBar,warnings:g})}());return{HDAEditView:f}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/dataset/hda-model.js b/static/scripts/packed/mvc/dataset/hda-model.js deleted file mode 100644 index dd3139bcb60..00000000000 --- a/static/scripts/packed/mvc/dataset/hda-model.js +++ /dev/null @@ -1 +0,0 @@ -define(["mvc/dataset/dataset-model","mvc/history/history-content-base","mvc/base-mvc","utils/localization"],function(e,g,b,c){var f=e.DatasetAssociation,d=g.HistoryContentMixin;var a=f.extend(b.mixin(d,{constructor:function(i,h){d.constructor.call(this,i,h)},defaults:_.extend({},f.prototype.defaults,d.defaults,{model_class:"HistoryDatasetAssociation"}),initialize:function(h,i){f.prototype.initialize.call(this,h,i);d.initialize.call(this,h,i)},toString:function(){var h=this.get("id")||"";if(this.get("name")){h=this.get("hid")+' :"'+this.get("name")+'",'+h}return"HDA("+h+")"}}));return{HistoryDatasetAssociation:a}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/history/annotated-history-panel.js b/static/scripts/packed/mvc/history/annotated-history-panel.js deleted file mode 100644 index 7e851c16f58..00000000000 --- a/static/scripts/packed/mvc/history/annotated-history-panel.js +++ /dev/null @@ -1 +0,0 @@ -define(["mvc/dataset/hda-base","mvc/history/readonly-history-panel","utils/localization"],function(a,c,b){var e=c.ReadOnlyHistoryPanel;var d=e.extend({className:"annotated-history-panel",HDAViewClass:a.HDABaseView,renderModel:function(){this.$el.addClass(this.className);var h=e.prototype.renderModel.call(this),f=this.$datasetsList(h),g=$("").addClass("datasets-list datasets-table");g.append(f.children());f.replaceWith(g);h.find(".history-subtitle").after(this.renderHistoryAnnotation());h.find(".history-search-btn").hide();h.find(".history-controls").after(h.find(".history-search-controls").show());return h},renderHistoryAnnotation:function(){var f=this.model.get("annotation");if(!f){return null}return $(['
',f,"
"].join(""))},renderHdas:function(g){g=g||this.$el;var f=e.prototype.renderHdas.call(this,g);this.$datasetsList(g).prepend($("").addClass("headers").append([$("").addClass("dataset-row").append([$("
").text(b("Dataset")),$("").text(b("Annotation"))]));return f},attachContentView:function(i,g){g=g||this.$el;var j=_.find(i.el.classList,function(k){return(/^state\-/).test(k)}),f=i.model.get("annotation")||"",h=$("
").addClass("dataset-container").append(i.$el).addClass(j?j.replace("-","-color-"):""),$("").addClass("additional-info").text(f)]);this.$datasetsList(g).append(h)},events:_.extend(_.clone(e.prototype.events),{"click tr":function(f){$(f.currentTarget).find(".dataset-title-bar").click()},"click .icon-btn":function(f){f.stopPropagation()}}),toString:function(){return"AnnotatedHistoryPanel("+((this.model)?(this.model.get("name")):(""))+")"}});return{AnnotatedHistoryPanel:d}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/history/current-history-panel.js b/static/scripts/packed/mvc/history/current-history-panel.js deleted file mode 100644 index 0c50fa55f67..00000000000 --- a/static/scripts/packed/mvc/history/current-history-panel.js +++ /dev/null @@ -1 +0,0 @@ -define(["mvc/dataset/hda-edit","mvc/history/history-panel","mvc/collection/collection-panel","mvc/base-mvc","utils/localization"],function(c,f,a,h,b){var d=h.SessionStorageModel.extend({defaults:{searching:false,tagsEditorShown:false,annotationEditorShown:false},toString:function(){return"HistoryPanelPrefs("+JSON.stringify(this.toJSON())+")"}});d.storageKey=function e(){return("history-panel")};var g=f.HistoryPanel;var i=g.extend({emptyMsg:b("This history is empty. Click 'Get Data' on the left tool menu to start"),noneFoundMsg:b("No matching datasets found"),initialize:function(j){j=j||{};this.preferences=new d(_.extend({id:d.storageKey()},_.pick(j,_.keys(d.prototype.defaults))));g.prototype.initialize.call(this,j);this.panelStack=[]},loadCurrentHistory:function(k){var j=this;return this.loadHistoryWithHDADetails("current",k).then(function(m,l){j.trigger("current-history",j)})},switchToHistory:function(m,l){var j=this,k=function(){return jQuery.ajax({url:galaxy_config.root+"api/histories/"+m+"/set_as_current",method:"PUT"})};return this.loadHistoryWithHDADetails(m,l,k).then(function(o,n){j.trigger("switched-history",j)})},createNewHistory:function(l){if(!Galaxy||!Galaxy.currUser||Galaxy.currUser.isAnonymous()){this.displayMessage("error",b("You must be logged in to create histories"));return $.when()}var j=this,k=function(){return jQuery.post(galaxy_config.root+"api/histories",{current:true})};return this.loadHistory(undefined,l,k).then(function(n,m){j.trigger("new-history",j)})},setModel:function(k,j,l){g.prototype.setModel.call(this,k,j,l);if(this.model){this.log("checking for updates");this.model.checkForUpdates()}return this},_setUpModelEventHandlers:function(){g.prototype._setUpModelEventHandlers.call(this);if(Galaxy&&Galaxy.quotaMeter){this.listenTo(this.model,"change:nice_size",function(){Galaxy.quotaMeter.update()})}this.model.contents.on("state:ready",function(k,l,j){if((!k.get("visible"))&&(!this.storage.get("show_hidden"))){this.removeHdaView(this.hdaViews[k.id])}},this)},render:function(l,m){this.log("render:",l,m);l=(l===undefined)?(this.fxSpeed):(l);var j=this,k;if(this.model){k=this.renderModel()}else{k=this.renderWithoutModel()}$(j).queue("fx",[function(n){if(l&&j.$el.is(":visible")){j.$el.fadeOut(l,n)}else{n()}},function(n){j.$el.empty();if(k){j.$el.append(k.children());j.renderBasedOnPrefs()}n()},function(n){if(l&&!j.$el.is(":visible")){j.$el.fadeIn(l,n)}else{n()}},function(n){if(m){m.call(this)}j.trigger("rendered",this);n()}]);return this},renderBasedOnPrefs:function(){if(this.preferences.get("searching")){this.toggleSearchControls(0,true)}},_renderEmptyMsg:function(l){var k=this,j=k.$emptyMessage(l),m=$(".toolMenuContainer");if((_.isEmpty(k.hdaViews)&&!k.searchFor)&&(Galaxy&&Galaxy.upload&&m.size())){j.empty();j.html([b("This history is empty"),". ",b("You can "),'',b("load your own data"),"",b(" or "),'',b("get data from an external source"),""].join(""));j.find(".uploader-link").click(function(n){Galaxy.upload._eventShow(n)});j.find(".get-data-link").click(function(n){m.parent().scrollTop(0);m.find('span:contains("Get Data")').click()});j.show()}else{g.prototype._renderEmptyMsg.call(this,l)}return this},toggleSearchControls:function(k,j){var l=g.prototype.toggleSearchControls.call(this,k,j);this.preferences.set("searching",l)},_renderTags:function(j){var k=this;g.prototype._renderTags.call(this,j);if(this.preferences.get("tagsEditorShown")){this.tagsEditor.toggle(true)}this.tagsEditor.on("hiddenUntilActivated:shown hiddenUntilActivated:hidden",function(l){k.preferences.set("tagsEditorShown",l.hidden)})},_renderAnnotation:function(j){var k=this;g.prototype._renderAnnotation.call(this,j);if(this.preferences.get("annotationEditorShown")){this.annotationEditor.toggle(true)}this.annotationEditor.on("hiddenUntilActivated:shown hiddenUntilActivated:hidden",function(l){k.preferences.set("annotationEditorShown",l.hidden)})},_setUpHdaListeners:function(k){g.prototype._setUpHdaListeners.call(this,k);var j=this;if(k instanceof j.HDCAViewClass){k.off("expanded");k.on("expanded",function(l){this.info("expanded",l);j._addCollectionPanel(l)});k.off("collapsed")}},_addCollectionPanel:function(l){var m=this,j=l.model;this.debug("history panel (stack), collectionModel:",j);var k=new (this._getCollectionPanelClass(j))({model:j,HDAViewClass:this.HDAViewClass,parentName:this.model.get("name")});m.panelStack.push(k);m.$(".history-controls").add(".datasets-list").hide();m.$el.append(k.$el);k.on("close",function(){m.render();l.collapse();m.panelStack.pop()});if(!k.model.hasDetails()){var n=k.model.fetch();n.done(function(){k.render()})}else{k.render()}},_getCollectionPanelClass:function(j){switch(j.get("collection_type")){case"list":return a.ListCollectionPanel;case"paired":return a.PairCollectionPanel;case"list:paired":return a.ListOfPairsCollectionPanel}throw new TypeError("Uknown collection_type: "+j.get("collection_type"))},addContentView:function(j){if(this.panelStack.length){return this}return g.prototype.addContentView.call(this,j)},connectToQuotaMeter:function(j){if(!j){return this}this.listenTo(j,"quota:over",this.showQuotaMessage);this.listenTo(j,"quota:under",this.hideQuotaMessage);this.on("rendered rendered:initial",function(){if(j&&j.isOverQuota()){this.showQuotaMessage()}});return this},showQuotaMessage:function(){var j=this.$el.find(".quota-message");if(j.is(":hidden")){j.slideDown(this.fxSpeed)}},hideQuotaMessage:function(){var j=this.$el.find(".quota-message");if(!j.is(":hidden")){j.slideUp(this.fxSpeed)}},connectToOptionsMenu:function(j){if(!j){return this}this.on("new-storage",function(l,k){if(j&&l){j.findItemByHtml(b("Include Deleted Datasets")).checked=l.get("show_deleted");j.findItemByHtml(b("Include Hidden Datasets")).checked=l.get("show_hidden")}});return this},toString:function(){return"CurrentHistoryPanel("+((this.model)?(this.model.get("name")):(""))+")"}});return{CurrentHistoryPanel:i}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/history/hda-li-edit.js b/static/scripts/packed/mvc/history/hda-li-edit.js new file mode 100644 index 00000000000..85b44bf7ae5 --- /dev/null +++ b/static/scripts/packed/mvc/history/hda-li-edit.js @@ -0,0 +1 @@ +define(["mvc/dataset/dataset-li-edit","mvc/history/hda-li","mvc/base-mvc","utils/localization"],function(b,d,a,c){var e=b.DatasetListItemEdit;var f=e.extend({className:e.prototype.className+" history-content",events:_.extend(_.clone(e.prototype.events),{"click .unhide-link":function(g){this.model.unhide();return false}}),toString:function(){var g=(this.model)?(this.model+""):("(no model)");return"HDAListItemEdit("+g+")"}});f.prototype.templates=(function(){var g=_.extend({},e.prototype.templates.warnings,{hidden:a.wrapTemplate(["<% if( !dataset.visible ){ %>",'
',c("This dataset has been hidden"),'
',c("Unhide it"),"","
","<% } %>"],"dataset")});return _.extend({},e.prototype.templates,{titleBar:d.HDAListItemView.prototype.templates.titleBar,warnings:g})}());return{HDAListItemEdit:f}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/history/hda-li.js b/static/scripts/packed/mvc/history/hda-li.js new file mode 100644 index 00000000000..319f90d6e14 --- /dev/null +++ b/static/scripts/packed/mvc/history/hda-li.js @@ -0,0 +1 @@ +define(["mvc/dataset/dataset-li","mvc/base-mvc","utils/localization"],function(e,a,c){var d=e.DatasetListItemView;var b=d.extend({initialize:function(f,g){d.prototype.initialize.call(this,f,g)},className:d.prototype.className+" history-content",toString:function(){var f=(this.model)?(this.model+""):("(no model)");return"HDAListItemView("+f+")"}});b.prototype.templates=(function(){var g=a.wrapTemplate(['
','','
','<%- dataset.hid %> ','<%- dataset.name %>',"
","
"],"dataset");var f=_.extend({},d.prototype.templates.warnings,{hidden:a.wrapTemplate(["<% if( !dataset.visible ){ %>",'
',c("This dataset has been hidden"),"
","<% } %>"],"dataset")});return _.extend({},d.prototype.templates,{titleBar:g,warnings:f})}());return{HDAListItemView:b}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/history/hda-model.js b/static/scripts/packed/mvc/history/hda-model.js new file mode 100644 index 00000000000..c7849b6877f --- /dev/null +++ b/static/scripts/packed/mvc/history/hda-model.js @@ -0,0 +1 @@ +define(["mvc/dataset/dataset-model","mvc/history/history-content-model","mvc/base-mvc","utils/localization"],function(e,g,b,c){var f=e.DatasetAssociation,d=g.HistoryContentMixin;var a=f.extend(b.mixin(d,{constructor:function(i,h){d.constructor.call(this,i,h)},defaults:_.extend({},f.prototype.defaults,d.defaults,{model_class:"HistoryDatasetAssociation"}),initialize:function(h,i){f.prototype.initialize.call(this,h,i);d.initialize.call(this,h,i)},toString:function(){var h=this.get("id")||"";if(this.get("name")){h=this.get("hid")+' :"'+this.get("name")+'",'+h}return"HDA("+h+")"}}));return{HistoryDatasetAssociation:a}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/history/hdca-li-edit.js b/static/scripts/packed/mvc/history/hdca-li-edit.js new file mode 100644 index 00000000000..85453474dad --- /dev/null +++ b/static/scripts/packed/mvc/history/hdca-li-edit.js @@ -0,0 +1 @@ +define(["mvc/dataset/states","mvc/history/hdca-li","utils/localization"],function(a,e,b){var c=e.HDCAListItemView;var d=c.extend({_renderPrimaryActions:function(){this.log(this+"._renderPrimaryActions");return c.prototype._renderPrimaryActions.call(this).concat([this._renderDeleteButton()])},_renderDeleteButton:function(){var g=this,f=this.model.get("deleted");return faIconButton({title:f?b("Dataset collection is already deleted"):b("Delete"),classes:"delete-btn",faIcon:"fa-times",disabled:f,onclick:function(){g.$el.find(".icon-btn.delete-btn").trigger("mouseout");g.model["delete"]()}})},toString:function(){var f=(this.model)?(this.model+""):("(no model)");return"HDCAListItemEdit("+f+")"}});return{HDCAListItemEdit:d}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/history/hdca-li.js b/static/scripts/packed/mvc/history/hdca-li.js new file mode 100644 index 00000000000..7a0bf881a33 --- /dev/null +++ b/static/scripts/packed/mvc/history/hdca-li.js @@ -0,0 +1 @@ +define(["mvc/dataset/states","mvc/collection/collection-li","mvc/base-mvc","utils/localization"],function(a,e,c,d){var f=e.DCListItemView;var b=f.extend({className:f.prototype.className+" history-content",_swapNewRender:function(g){f.prototype._swapNewRender.call(this,g);var h=this.model.get("state")||a.OK;this.$el.addClass("state-"+h);return this.$el},toString:function(){var g=(this.model)?(this.model+""):("(no model)");return"HDCAListItemView("+g+")"}});b.prototype.templates=(function(){var g=c.wrapTemplate(['
','','
','<%- collection.hid %> ','<%- collection.name %>',"
",'
',"
"],"collection");return _.extend({},f.prototype.templates,{titleBar:g})}());return{HDCAListItemView:b}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/history/hdca-model.js b/static/scripts/packed/mvc/history/hdca-model.js new file mode 100644 index 00000000000..1100acb50d0 --- /dev/null +++ b/static/scripts/packed/mvc/history/hdca-model.js @@ -0,0 +1 @@ +define(["mvc/collection/collection-model","mvc/history/history-content-model","utils/localization"],function(c,i,a){var g=i.HistoryContentMixin,h=c.ListDatasetCollection,j=c.PairDatasetCollection,f=c.ListPairedDatasetCollection;var d=h.extend(g).extend({initialize:function(l,k){h.prototype.initialize.call(this,l,k);g.initialize.call(this,l,k)},toString:function(){return(["HistoryListDatasetCollection(",this.get("name"),")"].join(""))}});var e=j.extend(g).extend({initialize:function(l,k){j.prototype.initialize.call(this,l,k);g.initialize.call(this,l,k)},toString:function(){return(["HistoryPairDatasetCollection(",this.get("name"),")"].join(""))}});var b=f.extend(g).extend({initialize:function(l,k){f.prototype.initialize.call(this,l,k);g.initialize.call(this,l,k)},toString:function(){return(["HistoryListPairedDatasetCollection(",this.get("name"),")"].join(""))}});return{HistoryListDatasetCollection:d,HistoryPairDatasetCollection:e,HistoryListPairedDatasetCollection:b}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/history/history-content-base-view.js b/static/scripts/packed/mvc/history/history-content-base-view.js deleted file mode 100644 index 8f76ea0e8fb..00000000000 --- a/static/scripts/packed/mvc/history/history-content-base-view.js +++ /dev/null @@ -1 +0,0 @@ -define(["mvc/base-mvc","utils/localization"],function(a,b){var d={initialize:function(e){}};var c=a.ExpandableView.extend(d);return{HistoryContentViewMixin:d,HistoryContentBaseView:c}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/history/history-content-base.js b/static/scripts/packed/mvc/history/history-content-model.js similarity index 100% rename from static/scripts/packed/mvc/history/history-content-base.js rename to static/scripts/packed/mvc/history/history-content-model.js diff --git a/static/scripts/packed/mvc/history/history-contents.js b/static/scripts/packed/mvc/history/history-contents.js index eb4876e9fcb..0b3b440f2f7 100644 --- a/static/scripts/packed/mvc/history/history-contents.js +++ b/static/scripts/packed/mvc/history/history-contents.js @@ -1 +1 @@ -define(["mvc/history/history-content-base","mvc/dataset/hda-model","mvc/collection/hdca-model","mvc/base-mvc","utils/localization"],function(g,e,b,a,c){var f=Backbone.Collection.extend(a.LoggableMixin).extend({model:function(i,h){if(i.history_content_type==="dataset"){return new e.HistoryDatasetAssociation(i,h)}else{if(i.history_content_type==="dataset_collection"){switch(i.collection_type){case"list":return new b.HistoryListDatasetCollection(i,h);case"paired":return new b.HistoryPairDatasetCollection(i,h);case"list:paired":return new b.HistoryListPairedDatasetCollection(i,h)}throw new TypeError("Unknown collection_type: "+i.collection_type)}}throw new TypeError("Unknown history_content_type: "+i.history_content_type)},initialize:function(i,h){h=h||{};this.historyId=h.historyId;this.on("all",function(){this.debug(this+".event:",arguments)})},urlRoot:galaxy_config.root+"api/histories",url:function(){return this.urlRoot+"/"+this.historyId+"/contents"},ids:function(){return this.map(function(h){return h.get("id")})},notReady:function(){return this.filter(function(h){return !h.inReadyState()})},running:function(){var h=[];this.each(function(j){var i=!j.inReadyState();if(i){h.push(j.get("id"))}});return h},getByHid:function(h){return _.first(this.filter(function(i){return i.get("hid")===h}))},getVisible:function(h,k,j){j=j||[];this.debug("checking isVisible");var i=new f(this.filter(function(l){return l.isVisible(h,k)}));_.each(j,function(l){if(!_.isFunction(l)){return}i=new f(i.filter(l))});return i},haveDetails:function(){return this.all(function(h){return h.hasDetails()})},fetchAllDetails:function(i){i=i||{};var h={details:"all"};i.data=(i.data)?(_.extend(i.data,h)):(h);return this.fetch(i)},ajaxQueue:function(k,j){var i=jQuery.Deferred(),h=this.length,m=[];if(!h){i.resolve([]);return i}var l=this.chain().reverse().map(function(o,n){return function(){var p=k.call(o,j);p.done(function(q){i.notify({curr:n,total:h,response:q,model:o})});p.always(function(q){m.push(q);if(l.length){l.shift()()}else{i.resolve(m)}})}}).value();l.shift()();return i},matches:function(h){return this.filter(function(i){return i.matches(h)})},set:function(j,h){var i=this;j=_.map(j,function(m){var l=m.attributes||m,n=g.typeIdStr(l.history_content_type,l.id),o=i.get(n);if(!o){return m}var k=o.toJSON();_.extend(k,m);return k});Backbone.Collection.prototype.set.call(this,j,h)},promoteToHistoryDatasetCollection:function d(m,k,i){i=i||{};i.url=this.url();i.type="POST";var o=k;var l=[],h=null;if(k==="list"){this.chain().each(function(r){var p=r.attributes.name;var s=r.get("id");var q=r.attributes.history_content_type;if(q==="dataset"){if(o!=="list"){this.log("Invalid collection type")}l.push({name:p,src:"hda",id:s})}else{if(o==="list"){o="list:"+r.attributes.collection_type}else{if(o!=="list:"+r.attributes.collection_type){this.log("Invalid collection type")}}l.push({name:p,src:"hdca",id:s})}});h="New Dataset List"}else{if(k==="paired"){var j=this.ids();if(j.length!==2){}l.push({name:"forward",src:"hda",id:j[0]});l.push({name:"reverse",src:"hda",id:j[1]});h="New Dataset Pair"}}i.data={type:"dataset_collection",name:h,collection_type:o,element_identifiers:JSON.stringify(l)};var n=jQuery.ajax(i);n.done(function(r,p,q){m.refresh()});n.fail(function(r,p,q){if(r.responseJSON&&r.responseJSON.error){error=r.responseJSON.error}else{error=r.responseJSON}r.responseText=error});return n},print:function(){var h=this;h.each(function(i){h.debug(i);if(i.elements){h.debug("\t elements:",i.elements)}})},toString:function(){return(["HistoryContents(",[this.historyId,this.length].join(),")"].join(""))}});return{HistoryContents:f}}); \ No newline at end of file +define(["mvc/history/history-content-model","mvc/history/hda-model","mvc/history/hdca-model","mvc/base-mvc","utils/localization"],function(g,e,b,a,c){var f=Backbone.Collection.extend(a.LoggableMixin).extend({model:function(i,h){if(i.history_content_type==="dataset"){return new e.HistoryDatasetAssociation(i,h)}else{if(i.history_content_type==="dataset_collection"){switch(i.collection_type){case"list":return new b.HistoryListDatasetCollection(i,h);case"paired":return new b.HistoryPairDatasetCollection(i,h);case"list:paired":return new b.HistoryListPairedDatasetCollection(i,h)}throw new TypeError("Unknown collection_type: "+i.collection_type)}}throw new TypeError("Unknown history_content_type: "+i.history_content_type)},initialize:function(i,h){h=h||{};this.historyId=h.historyId;this.on("all",function(){this.debug(this+".event:",arguments)})},urlRoot:galaxy_config.root+"api/histories",url:function(){return this.urlRoot+"/"+this.historyId+"/contents"},ids:function(){return this.map(function(h){return h.get("id")})},notReady:function(){return this.filter(function(h){return !h.inReadyState()})},running:function(){var h=[];this.each(function(j){var i=!j.inReadyState();if(i){h.push(j.get("id"))}});return h},getByHid:function(h){return _.first(this.filter(function(i){return i.get("hid")===h}))},getVisible:function(h,k,j){j=j||[];this.debug("checking isVisible");var i=new f(this.filter(function(l){return l.isVisible(h,k)}));_.each(j,function(l){if(!_.isFunction(l)){return}i=new f(i.filter(l))});return i},haveDetails:function(){return this.all(function(h){return h.hasDetails()})},fetchAllDetails:function(i){i=i||{};var h={details:"all"};i.data=(i.data)?(_.extend(i.data,h)):(h);return this.fetch(i)},ajaxQueue:function(k,j){var i=jQuery.Deferred(),h=this.length,m=[];if(!h){i.resolve([]);return i}var l=this.chain().reverse().map(function(o,n){return function(){var p=k.call(o,j);p.done(function(q){i.notify({curr:n,total:h,response:q,model:o})});p.always(function(q){m.push(q);if(l.length){l.shift()()}else{i.resolve(m)}})}}).value();l.shift()();return i},matches:function(h){return this.filter(function(i){return i.matches(h)})},set:function(j,h){var i=this;j=_.map(j,function(m){var l=m.attributes||m,n=g.typeIdStr(l.history_content_type,l.id),o=i.get(n);if(!o){return m}var k=o.toJSON();_.extend(k,m);return k});Backbone.Collection.prototype.set.call(this,j,h)},promoteToHistoryDatasetCollection:function d(m,k,i){i=i||{};i.url=this.url();i.type="POST";var o=k;var l=[],h=null;if(k==="list"){this.chain().each(function(r){var p=r.attributes.name;var s=r.get("id");var q=r.attributes.history_content_type;if(q==="dataset"){if(o!=="list"){this.log("Invalid collection type")}l.push({name:p,src:"hda",id:s})}else{if(o==="list"){o="list:"+r.attributes.collection_type}else{if(o!=="list:"+r.attributes.collection_type){this.log("Invalid collection type")}}l.push({name:p,src:"hdca",id:s})}});h="New Dataset List"}else{if(k==="paired"){var j=this.ids();if(j.length!==2){}l.push({name:"forward",src:"hda",id:j[0]});l.push({name:"reverse",src:"hda",id:j[1]});h="New Dataset Pair"}}i.data={type:"dataset_collection",name:h,collection_type:o,element_identifiers:JSON.stringify(l)};var n=jQuery.ajax(i);n.done(function(r,p,q){m.refresh()});n.fail(function(r,p,q){if(r.responseJSON&&r.responseJSON.error){error=r.responseJSON.error}else{error=r.responseJSON}r.responseText=error});return n},print:function(){var h=this;h.each(function(i){h.debug(i);if(i.elements){h.debug("\t elements:",i.elements)}})},toString:function(){return(["HistoryContents(",[this.historyId,this.length].join(),")"].join(""))}});return{HistoryContents:f}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/history/history-panel-annotated.js b/static/scripts/packed/mvc/history/history-panel-annotated.js new file mode 100644 index 00000000000..32646843c6b --- /dev/null +++ b/static/scripts/packed/mvc/history/history-panel-annotated.js @@ -0,0 +1 @@ +define(["mvc/history/history-panel","mvc/history/hda-li","utils/localization"],function(e,b,a){var d=e.ReadOnlyHistoryPanel;var c=d.extend({className:"annotated-history-panel",HDAViewClass:b.HDAReadonlyListItemView,renderModel:function(){this.$el.addClass(this.className);var h=d.prototype.renderModel.call(this),f=this.$datasetsList(h),g=$("").addClass("datasets-list datasets-table");g.append(f.children());f.replaceWith(g);h.find(".history-subtitle").after(this.renderHistoryAnnotation());h.find(".history-search-btn").hide();h.find(".history-controls").after(h.find(".history-search-controls").show());return h},renderHistoryAnnotation:function(){var f=this.model.get("annotation");if(!f){return null}return $(['
',f,"
"].join(""))},renderHdas:function(g){g=g||this.$el;var f=d.prototype.renderHdas.call(this,g);this.$datasetsList(g).prepend($("").addClass("headers").append([$("").addClass("dataset-row").append([$("
").text(a("Dataset")),$("").text(a("Annotation"))]));return f},attachContentView:function(i,g){g=g||this.$el;var j=_.find(i.el.classList,function(k){return(/^state\-/).test(k)}),f=i.model.get("annotation")||"",h=$("
").addClass("dataset-container").append(i.$el).addClass(j?j.replace("-","-color-"):""),$("").addClass("additional-info").text(f)]);this.$datasetsList(g).append(h)},events:_.extend(_.clone(d.prototype.events),{"click tr":function(f){$(f.currentTarget).find(".dataset-title-bar").click()},"click .icon-btn":function(f){f.stopPropagation()}}),toString:function(){return"AnnotatedHistoryPanel("+((this.model)?(this.model.get("name")):(""))+")"}});return{AnnotatedHistoryPanel:c}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/history/history-panel-edit-current.js b/static/scripts/packed/mvc/history/history-panel-edit-current.js new file mode 100644 index 00000000000..c557339bfff --- /dev/null +++ b/static/scripts/packed/mvc/history/history-panel-edit-current.js @@ -0,0 +1 @@ +define(["mvc/history/history-panel-edit","mvc/collection/collection-panel","mvc/base-mvc","utils/localization"],function(g,f,b,d){var c=b.SessionStorageModel.extend({defaults:{searching:false,tagsEditorShown:false,annotationEditorShown:false},toString:function(){return"HistoryPanelPrefs("+JSON.stringify(this.toJSON())+")"}});c.storageKey=function h(){return("history-panel")};var e=g.HistoryPanel;var a=e.extend({emptyMsg:d("This history is empty. Click 'Get Data' on the left tool menu to start"),noneFoundMsg:d("No matching datasets found"),initialize:function(i){i=i||{};this.preferences=new c(_.extend({id:c.storageKey()},_.pick(i,_.keys(c.prototype.defaults))));e.prototype.initialize.call(this,i);this.panelStack=[]},loadCurrentHistory:function(j){var i=this;return this.loadHistoryWithHDADetails("current",j).then(function(l,k){i.trigger("current-history",i)})},switchToHistory:function(l,k){var i=this,j=function(){return jQuery.ajax({url:galaxy_config.root+"api/histories/"+l+"/set_as_current",method:"PUT"})};return this.loadHistoryWithHDADetails(l,k,j).then(function(n,m){i.trigger("switched-history",i)})},createNewHistory:function(k){if(!Galaxy||!Galaxy.currUser||Galaxy.currUser.isAnonymous()){this.displayMessage("error",d("You must be logged in to create histories"));return $.when()}var i=this,j=function(){return jQuery.post(galaxy_config.root+"api/histories",{current:true})};return this.loadHistory(undefined,k,j).then(function(m,l){i.trigger("new-history",i)})},setModel:function(j,i,k){e.prototype.setModel.call(this,j,i,k);if(this.model){this.log("checking for updates");this.model.checkForUpdates()}return this},_setUpModelEventHandlers:function(){e.prototype._setUpModelEventHandlers.call(this);if(Galaxy&&Galaxy.quotaMeter){this.listenTo(this.model,"change:nice_size",function(){Galaxy.quotaMeter.update()})}this.model.contents.on("state:ready",function(j,k,i){if((!j.get("visible"))&&(!this.storage.get("show_hidden"))){this.removeHdaView(this.hdaViews[j.id])}},this)},render:function(k,l){this.log("render:",k,l);k=(k===undefined)?(this.fxSpeed):(k);var i=this,j;if(this.model){j=this.renderModel()}else{j=this.renderWithoutModel()}$(i).queue("fx",[function(m){if(k&&i.$el.is(":visible")){i.$el.fadeOut(k,m)}else{m()}},function(m){i.$el.empty();if(j){i.$el.append(j.children());i.renderBasedOnPrefs()}m()},function(m){if(k&&!i.$el.is(":visible")){i.$el.fadeIn(k,m)}else{m()}},function(m){if(l){l.call(this)}i.trigger("rendered",this);m()}]);return this},renderBasedOnPrefs:function(){if(this.preferences.get("searching")){this.toggleSearchControls(0,true)}},_renderEmptyMsg:function(k){var j=this,i=j.$emptyMessage(k),l=$(".toolMenuContainer");if((_.isEmpty(j.hdaViews)&&!j.searchFor)&&(Galaxy&&Galaxy.upload&&l.size())){i.empty();i.html([d("This history is empty"),". ",d("You can "),'',d("load your own data"),"",d(" or "),'',d("get data from an external source"),""].join(""));i.find(".uploader-link").click(function(m){Galaxy.upload._eventShow(m)});i.find(".get-data-link").click(function(m){l.parent().scrollTop(0);l.find('span:contains("Get Data")').click()});i.show()}else{e.prototype._renderEmptyMsg.call(this,k)}return this},toggleSearchControls:function(j,i){var k=e.prototype.toggleSearchControls.call(this,j,i);this.preferences.set("searching",k)},_renderTags:function(i){var j=this;e.prototype._renderTags.call(this,i);if(this.preferences.get("tagsEditorShown")){this.tagsEditor.toggle(true)}this.tagsEditor.on("hiddenUntilActivated:shown hiddenUntilActivated:hidden",function(k){j.preferences.set("tagsEditorShown",k.hidden)})},_renderAnnotation:function(i){var j=this;e.prototype._renderAnnotation.call(this,i);if(this.preferences.get("annotationEditorShown")){this.annotationEditor.toggle(true)}this.annotationEditor.on("hiddenUntilActivated:shown hiddenUntilActivated:hidden",function(k){j.preferences.set("annotationEditorShown",k.hidden)})},_setUpHdaListeners:function(j){e.prototype._setUpHdaListeners.call(this,j);var i=this;if(j instanceof i.HDCAViewClass){j.off("expanded");j.on("expanded",function(k){this.info("expanded",k);i._addCollectionPanel(k)});j.off("collapsed")}},_addCollectionPanel:function(k){var l=this,i=k.model;this.debug("history panel (stack), collectionModel:",i);var j=new (this._getCollectionPanelClass(i))({model:i,HDAViewClass:this.HDAViewClass,parentName:this.model.get("name"),linkTarget:this.linkTarget});l.panelStack.push(j);l.$(".history-controls").add(".datasets-list").hide();l.$el.append(j.$el);j.on("close",function(){l.render();k.collapse();l.panelStack.pop()});if(!j.model.hasDetails()){var m=j.model.fetch();m.done(function(){j.render()})}else{j.render()}},_getCollectionPanelClass:function(i){switch(i.get("collection_type")){case"list":return f.ListCollectionPanel;case"paired":return f.PairCollectionPanel;case"list:paired":return f.ListOfPairsCollectionPanel}throw new TypeError("Uknown collection_type: "+i.get("collection_type"))},addContentView:function(i){if(this.panelStack.length){return this}return e.prototype.addContentView.call(this,i)},connectToQuotaMeter:function(i){if(!i){return this}this.listenTo(i,"quota:over",this.showQuotaMessage);this.listenTo(i,"quota:under",this.hideQuotaMessage);this.on("rendered rendered:initial",function(){if(i&&i.isOverQuota()){this.showQuotaMessage()}});return this},showQuotaMessage:function(){var i=this.$el.find(".quota-message");if(i.is(":hidden")){i.slideDown(this.fxSpeed)}},hideQuotaMessage:function(){var i=this.$el.find(".quota-message");if(!i.is(":hidden")){i.slideUp(this.fxSpeed)}},connectToOptionsMenu:function(i){if(!i){return this}this.on("new-storage",function(k,j){if(i&&k){i.findItemByHtml(d("Include Deleted Datasets")).checked=k.get("show_deleted");i.findItemByHtml(d("Include Hidden Datasets")).checked=k.get("show_hidden")}});return this},toString:function(){return"CurrentHistoryPanel("+((this.model)?(this.model.get("name")):(""))+")"}});return{CurrentHistoryPanel:a}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/history/history-panel-edit.js b/static/scripts/packed/mvc/history/history-panel-edit.js new file mode 100644 index 00000000000..1f6f41374fe --- /dev/null +++ b/static/scripts/packed/mvc/history/history-panel-edit.js @@ -0,0 +1 @@ +define(["mvc/history/history-panel","mvc/history/history-contents","mvc/dataset/states","mvc/history/hda-model","mvc/history/hda-li-edit","mvc/history/hdca-li-edit","mvc/tags","mvc/annotations","utils/localization"],function(f,h,k,d,c,g,j,a,b){var i=f.ReadOnlyHistoryPanel;var e=i.extend({HDAViewClass:c.HDAListItemEdit,HDCAViewClass:g.HDCAListItemEdit,initialize:function(l){l=l||{};this.selectedHdaIds=[];this.lastSelectedViewId=null;this.tagsEditor=null;this.annotationEditor=null;this.purgeAllowed=l.purgeAllowed||false;this.selecting=l.selecting||false;this.annotationEditorShown=l.annotationEditorShown||false;this.tagsEditorShown=l.tagsEditorShown||false;i.prototype.initialize.call(this,l)},_setUpModelEventHandlers:function(){i.prototype._setUpModelEventHandlers.call(this);this.model.on("change:nice_size",this.updateHistoryDiskSize,this);this.model.contents.on("change:deleted",this._handleHdaDeletionChange,this);this.model.contents.on("change:visible",this._handleHdaVisibleChange,this);this.model.contents.on("change:purged",function(l){this.model.fetch()},this)},renderModel:function(){var l=$("
");l.append(e.templates.historyPanel(this.model.toJSON()));this.$emptyMessage(l).text(this.emptyMsg);if(Galaxy&&Galaxy.currUser&&Galaxy.currUser.id&&Galaxy.currUser.id===this.model.get("user_id")){this._renderTags(l);this._renderAnnotation(l)}l.find(".history-secondary-actions").prepend(this._renderSelectButton());l.find(".history-dataset-actions").toggle(this.selecting);l.find(".history-secondary-actions").prepend(this._renderSearchButton());this._setUpBehaviours(l);this.renderHdas(l);return l},_renderTags:function(l){var m=this;this.tagsEditor=new j.TagsEditor({model:this.model,el:l.find(".history-controls .tags-display"),onshowFirstTime:function(){this.render()},onshow:function(){m.toggleHDATagEditors(true,m.fxSpeed)},onhide:function(){m.toggleHDATagEditors(false,m.fxSpeed)},$activator:faIconButton({title:b("Edit history tags"),classes:"history-tag-btn",faIcon:"fa-tags"}).appendTo(l.find(".history-secondary-actions"))})},_renderAnnotation:function(l){var m=this;this.annotationEditor=new a.AnnotationEditor({model:this.model,el:l.find(".history-controls .annotation-display"),onshowFirstTime:function(){this.render()},onshow:function(){m.toggleHDAAnnotationEditors(true,m.fxSpeed)},onhide:function(){m.toggleHDAAnnotationEditors(false,m.fxSpeed)},$activator:faIconButton({title:b("Edit history annotation"),classes:"history-annotate-btn",faIcon:"fa-comment"}).appendTo(l.find(".history-secondary-actions"))})},_renderSelectButton:function(l){return faIconButton({title:b("Operations on multiple datasets"),classes:"history-select-btn",faIcon:"fa-check-square-o"})},_setUpBehaviours:function(l){l=l||this.$el;i.prototype._setUpBehaviours.call(this,l);if(!this.model){return}this._setUpDatasetActionsPopup(l);if((!Galaxy.currUser||Galaxy.currUser.isAnonymous())||(Galaxy.currUser.id!==this.model.get("user_id"))){return}var m=this;l.find(".history-name").attr("title",b("Click to rename history")).tooltip({placement:"bottom"}).make_text_editable({on_finish:function(n){var o=m.model.get("name");if(n&&n!==o){m.$el.find(".history-name").text(n);m.model.save({name:n}).fail(function(){m.$el.find(".history-name").text(m.model.previous("name"))})}else{m.$el.find(".history-name").text(o)}}})},_setUpDatasetActionsPopup:function(l){var m=this,n=[{html:b("Hide datasets"),func:function(){var o=d.HistoryDatasetAssociation.prototype.hide;m.getSelectedHdaCollection().ajaxQueue(o)}},{html:b("Unhide datasets"),func:function(){var o=d.HistoryDatasetAssociation.prototype.unhide;m.getSelectedHdaCollection().ajaxQueue(o)}},{html:b("Delete datasets"),func:function(){var o=d.HistoryDatasetAssociation.prototype["delete"];m.getSelectedHdaCollection().ajaxQueue(o)}},{html:b("Undelete datasets"),func:function(){var o=d.HistoryDatasetAssociation.prototype.undelete;m.getSelectedHdaCollection().ajaxQueue(o)}}];if(m.purgeAllowed){n.push({html:b("Permanently delete datasets"),func:function(){if(confirm(b("This will permanently remove the data in your datasets. Are you sure?"))){var o=d.HistoryDatasetAssociation.prototype.purge;m.getSelectedHdaCollection().ajaxQueue(o)}}})}n.push({html:b("Build Dataset List (Experimental)"),func:function(){m.getSelectedHdaCollection().promoteToHistoryDatasetCollection(m.model,"list")}});n.push({html:b("Build Dataset Pair (Experimental)"),func:function(){m.getSelectedHdaCollection().promoteToHistoryDatasetCollection(m.model,"paired")}});n.push({html:b("Build List of Dataset Pairs (Experimental)"),func:_.bind(m._showPairedCollectionModal,m)});return new PopupMenu(l.find(".history-dataset-action-popup-btn"),n)},_showPairedCollectionModal:function(){var l=this,m=l.getSelectedHdaCollection().toJSON().filter(function(n){return n.history_content_type==="dataset"&&n.state===k.OK});if(m.length){require(["mvc/collection/paired-collection-creator"],function(n){window.creator=n.pairedCollectionCreatorModal(m,{historyId:l.model.id})})}else{}},_handleHdaDeletionChange:function(l){if(l.get("deleted")&&!this.storage.get("show_deleted")){this.removeHdaView(this.hdaViews[l.id])}},_handleHdaVisibleChange:function(l){if(l.hidden()&&!this.storage.get("show_hidden")){this.removeHdaView(this.hdaViews[l.id])}},_getContentOptions:function(m){var l=i.prototype._getContentOptions.call(this,m);_.extend(l,{selectable:this.selecting,purgeAllowed:this.purgeAllowed,tagsEditorShown:(this.tagsEditor&&!this.tagsEditor.hidden),annotationEditorShown:(this.annotationEditor&&!this.annotationEditor.hidden)});return l},_setUpHdaListeners:function(m){var l=this;i.prototype._setUpHdaListeners.call(this,m);m.on("selected",function(p,o){if(!o){return}var n=[];if((o.shiftKey)&&(l.lastSelectedViewId&&_.has(l.hdaViews,l.lastSelectedViewId))){var r=l.hdaViews[l.lastSelectedViewId];n=l.selectDatasetRange(p,r).map(function(s){return s.model.id})}else{var q=p.model.id;l.lastSelectedViewId=q;n=[q]}l.selectedHdaIds=_.union(l.selectedHdaIds,n)});m.on("de-selected",function(o,n){var p=o.model.id;l.selectedHdaIds=_.without(l.selectedHdaIds,p)})},toggleHDATagEditors:function(l){var m=arguments;_.each(this.hdaViews,function(n){if(n.tagsEditor){n.tagsEditor.toggle.apply(n.tagsEditor,m)}})},toggleHDAAnnotationEditors:function(l){var m=arguments;_.each(this.hdaViews,function(n){if(n.annotationEditor){n.annotationEditor.toggle.apply(n.annotationEditor,m)}})},removeHdaView:function(m){if(!m){return}var l=this;m.$el.fadeOut(l.fxSpeed,function(){m.off();m.remove();delete l.hdaViews[m.model.id];if(_.isEmpty(l.hdaViews)){l.trigger("empty-history",l);l._renderEmptyMsg()}})},events:_.extend(_.clone(i.prototype.events),{"click .history-select-btn":"toggleSelectors","click .history-select-all-datasets-btn":"selectAllDatasets","click .history-deselect-all-datasets-btn":"deselectAllDatasets"}),updateHistoryDiskSize:function(){this.$el.find(".history-size").text(this.model.get("nice_size"))},showSelectors:function(l){l=(l!==undefined)?(l):(this.fxSpeed);this.selecting=true;this.$(".history-dataset-actions").slideDown(l);_.each(this.hdaViews,function(m){m.showSelector()});this.selectedHdaIds=[];this.lastSelectedViewId=null},hideSelectors:function(l){l=(l!==undefined)?(l):(this.fxSpeed);this.selecting=false;this.$(".history-dataset-actions").slideUp(l);_.each(this.hdaViews,function(m){m.hideSelector()});this.selectedHdaIds=[];this.lastSelectedViewId=null},toggleSelectors:function(){if(!this.selecting){this.showSelectors()}else{this.hideSelectors()}},selectAllDatasets:function(l){_.each(this.hdaViews,function(m){m.select(l)})},deselectAllDatasets:function(l){this.lastSelectedViewId=null;_.each(this.hdaViews,function(m){m.deselect(l)})},selectDatasetRange:function(n,m){var l=this.hdaViewRange(n,m);_.each(l,function(o){o.select()});return l},getSelectedHdaViews:function(){return _.filter(this.hdaViews,function(l){return l.selected})},getSelectedHdaCollection:function(){return new h.HistoryContents(_.map(this.getSelectedHdaViews(),function(l){return l.model}),{historyId:this.model.id})},toString:function(){return"HistoryPanel("+((this.model)?(this.model.get("name")):(""))+")"}});return{HistoryPanel:e}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/history/history-panel.js b/static/scripts/packed/mvc/history/history-panel.js index 0ef2095ef63..a8911dc2f70 100644 --- a/static/scripts/packed/mvc/history/history-panel.js +++ b/static/scripts/packed/mvc/history/history-panel.js @@ -1 +1 @@ -define(["mvc/dataset/states","mvc/dataset/hda-model","mvc/dataset/hda-base","mvc/dataset/hda-edit","mvc/dataset/dataset-list-element","mvc/dataset/editable-dataset-list-element","mvc/collection/dataset-collection-base","mvc/collection/dataset-collection-edit","mvc/collection/hdca-base","mvc/collection/hdca-edit","mvc/history/history-contents","mvc/history/readonly-history-panel","mvc/tags","mvc/annotations","utils/localization"],function(p,h,j,g,m,f,e,q,a,k,l,c,o,b,d){var n=c.ReadOnlyHistoryPanel;var i=n.extend({HDAViewClass:g.HDAEditView,HDCAViewClass:k.HDCAEditView,initialize:function(r){r=r||{};this.selectedHdaIds=[];this.lastSelectedViewId=null;this.tagsEditor=null;this.annotationEditor=null;this.purgeAllowed=r.purgeAllowed||false;this.selecting=r.selecting||false;this.annotationEditorShown=r.annotationEditorShown||false;this.tagsEditorShown=r.tagsEditorShown||false;n.prototype.initialize.call(this,r)},_setUpModelEventHandlers:function(){n.prototype._setUpModelEventHandlers.call(this);this.model.on("change:nice_size",this.updateHistoryDiskSize,this);this.model.contents.on("change:deleted",this._handleHdaDeletionChange,this);this.model.contents.on("change:visible",this._handleHdaVisibleChange,this);this.model.contents.on("change:purged",function(r){this.model.fetch()},this)},renderModel:function(){var r=$("
");r.append(i.templates.historyPanel(this.model.toJSON()));this.$emptyMessage(r).text(this.emptyMsg);if(Galaxy&&Galaxy.currUser&&Galaxy.currUser.id&&Galaxy.currUser.id===this.model.get("user_id")){this._renderTags(r);this._renderAnnotation(r)}r.find(".history-secondary-actions").prepend(this._renderSelectButton());r.find(".history-dataset-actions").toggle(this.selecting);r.find(".history-secondary-actions").prepend(this._renderSearchButton());this._setUpBehaviours(r);this.renderHdas(r);return r},_renderTags:function(r){var s=this;this.tagsEditor=new o.TagsEditor({model:this.model,el:r.find(".history-controls .tags-display"),onshowFirstTime:function(){this.render()},onshow:function(){s.toggleHDATagEditors(true,s.fxSpeed)},onhide:function(){s.toggleHDATagEditors(false,s.fxSpeed)},$activator:faIconButton({title:d("Edit history tags"),classes:"history-tag-btn",faIcon:"fa-tags"}).appendTo(r.find(".history-secondary-actions"))})},_renderAnnotation:function(r){var s=this;this.annotationEditor=new b.AnnotationEditor({model:this.model,el:r.find(".history-controls .annotation-display"),onshowFirstTime:function(){this.render()},onshow:function(){s.toggleHDAAnnotationEditors(true,s.fxSpeed)},onhide:function(){s.toggleHDAAnnotationEditors(false,s.fxSpeed)},$activator:faIconButton({title:d("Edit history annotation"),classes:"history-annotate-btn",faIcon:"fa-comment"}).appendTo(r.find(".history-secondary-actions"))})},_renderSelectButton:function(r){return faIconButton({title:d("Operations on multiple datasets"),classes:"history-select-btn",faIcon:"fa-check-square-o"})},_setUpBehaviours:function(r){r=r||this.$el;n.prototype._setUpBehaviours.call(this,r);if(!this.model){return}this._setUpDatasetActionsPopup(r);if((!Galaxy.currUser||Galaxy.currUser.isAnonymous())||(Galaxy.currUser.id!==this.model.get("user_id"))){return}var s=this;r.find(".history-name").attr("title",d("Click to rename history")).tooltip({placement:"bottom"}).make_text_editable({on_finish:function(t){var u=s.model.get("name");if(t&&t!==u){s.$el.find(".history-name").text(t);s.model.save({name:t}).fail(function(){s.$el.find(".history-name").text(s.model.previous("name"))})}else{s.$el.find(".history-name").text(u)}}})},_setUpDatasetActionsPopup:function(r){var s=this,t=[{html:d("Hide datasets"),func:function(){var u=h.HistoryDatasetAssociation.prototype.hide;s.getSelectedHdaCollection().ajaxQueue(u)}},{html:d("Unhide datasets"),func:function(){var u=h.HistoryDatasetAssociation.prototype.unhide;s.getSelectedHdaCollection().ajaxQueue(u)}},{html:d("Delete datasets"),func:function(){var u=h.HistoryDatasetAssociation.prototype["delete"];s.getSelectedHdaCollection().ajaxQueue(u)}},{html:d("Undelete datasets"),func:function(){var u=h.HistoryDatasetAssociation.prototype.undelete;s.getSelectedHdaCollection().ajaxQueue(u)}}];if(s.purgeAllowed){t.push({html:d("Permanently delete datasets"),func:function(){if(confirm(d("This will permanently remove the data in your datasets. Are you sure?"))){var u=h.HistoryDatasetAssociation.prototype.purge;s.getSelectedHdaCollection().ajaxQueue(u)}}})}t.push({html:d("Build Dataset List (Experimental)"),func:function(){s.getSelectedHdaCollection().promoteToHistoryDatasetCollection(s.model,"list")}});t.push({html:d("Build Dataset Pair (Experimental)"),func:function(){s.getSelectedHdaCollection().promoteToHistoryDatasetCollection(s.model,"paired")}});t.push({html:d("Build List of Dataset Pairs (Experimental)"),func:_.bind(s._showPairedCollectionModal,s)});return new PopupMenu(r.find(".history-dataset-action-popup-btn"),t)},_showPairedCollectionModal:function(){var r=this,s=r.getSelectedHdaCollection().toJSON().filter(function(t){return t.history_content_type==="dataset"&&t.state===p.OK});if(s.length){require(["mvc/collection/paired-collection-creator"],function(t){window.creator=t.pairedCollectionCreatorModal(s,{historyId:r.model.id})})}else{}},_handleHdaDeletionChange:function(r){if(r.get("deleted")&&!this.storage.get("show_deleted")){this.removeHdaView(this.hdaViews[r.id])}},_handleHdaVisibleChange:function(r){if(r.hidden()&&!this.storage.get("show_hidden")){this.removeHdaView(this.hdaViews[r.id])}},_getContentOptions:function(s){var r=n.prototype._getContentOptions.call(this,s);_.extend(r,{selectable:this.selecting,purgeAllowed:this.purgeAllowed,tagsEditorShown:(this.tagsEditor&&!this.tagsEditor.hidden),annotationEditorShown:(this.annotationEditor&&!this.annotationEditor.hidden)});return r},_setUpHdaListeners:function(s){var r=this;n.prototype._setUpHdaListeners.call(this,s);s.on("selected",function(v,u){if(!u){return}var t=[];if((u.shiftKey)&&(r.lastSelectedViewId&&_.has(r.hdaViews,r.lastSelectedViewId))){var x=r.hdaViews[r.lastSelectedViewId];t=r.selectDatasetRange(v,x).map(function(y){return y.model.id})}else{var w=v.model.id;r.lastSelectedViewId=w;t=[w]}r.selectedHdaIds=_.union(r.selectedHdaIds,t)});s.on("de-selected",function(u,t){var v=u.model.id;r.selectedHdaIds=_.without(r.selectedHdaIds,v)})},toggleHDATagEditors:function(r){var s=arguments;_.each(this.hdaViews,function(t){if(t.tagsEditor){t.tagsEditor.toggle.apply(t.tagsEditor,s)}})},toggleHDAAnnotationEditors:function(r){var s=arguments;_.each(this.hdaViews,function(t){if(t.annotationEditor){t.annotationEditor.toggle.apply(t.annotationEditor,s)}})},removeHdaView:function(s){if(!s){return}var r=this;s.$el.fadeOut(r.fxSpeed,function(){s.off();s.remove();delete r.hdaViews[s.model.id];if(_.isEmpty(r.hdaViews)){r.trigger("empty-history",r);r._renderEmptyMsg()}})},events:_.extend(_.clone(n.prototype.events),{"click .history-select-btn":"toggleSelectors","click .history-select-all-datasets-btn":"selectAllDatasets","click .history-deselect-all-datasets-btn":"deselectAllDatasets"}),updateHistoryDiskSize:function(){this.$el.find(".history-size").text(this.model.get("nice_size"))},showSelectors:function(r){r=(r!==undefined)?(r):(this.fxSpeed);this.selecting=true;this.$(".history-dataset-actions").slideDown(r);_.each(this.hdaViews,function(s){s.showSelector()});this.selectedHdaIds=[];this.lastSelectedViewId=null},hideSelectors:function(r){r=(r!==undefined)?(r):(this.fxSpeed);this.selecting=false;this.$(".history-dataset-actions").slideUp(r);_.each(this.hdaViews,function(s){s.hideSelector()});this.selectedHdaIds=[];this.lastSelectedViewId=null},toggleSelectors:function(){if(!this.selecting){this.showSelectors()}else{this.hideSelectors()}},selectAllDatasets:function(r){_.each(this.hdaViews,function(s){s.select(r)})},deselectAllDatasets:function(r){this.lastSelectedViewId=null;_.each(this.hdaViews,function(s){s.deselect(r)})},selectDatasetRange:function(t,s){var r=this.hdaViewRange(t,s);_.each(r,function(u){u.select()});return r},getSelectedHdaViews:function(){return _.filter(this.hdaViews,function(r){return r.selected})},getSelectedHdaCollection:function(){return new l.HistoryContents(_.map(this.getSelectedHdaViews(),function(r){return r.model}),{historyId:this.model.id})},toString:function(){return"HistoryPanel("+((this.model)?(this.model.get("name")):(""))+")"}});return{HistoryPanel:i}}); \ No newline at end of file +define(["mvc/history/history-model","mvc/history/hda-li","mvc/history/hdca-li","mvc/user/user-model","mvc/base-mvc","utils/localization"],function(e,b,a,f,k,d){var i=k.SessionStorageModel.extend({defaults:{expandedHdas:{},show_deleted:false,show_hidden:false},addExpandedHda:function(m){var n="expandedHdas";this.save(n,_.extend(this.get(n),_.object([m.id],[m.get("id")])))},removeExpandedHda:function(m){var n="expandedHdas";this.save(n,_.omit(this.get(n),m.id))},toString:function(){return"HistoryPrefs("+this.id+")"}});i.storageKeyPrefix="history:";i.historyStorageKey=function g(m){if(!m){throw new Error("HistoryPrefs.historyStorageKey needs valid id: "+m)}return(i.storageKeyPrefix+m)};i.get=function c(m){return new i({id:i.historyStorageKey(m)})};i.clearAll=function h(n){for(var m in sessionStorage){if(m.indexOf(i.storageKeyPrefix)===0){sessionStorage.removeItem(m)}}};var j=Backbone.View.extend(k.LoggableMixin).extend({HDAViewClass:b.HDAListItemView,HDCAViewClass:a.HDCAListItemView,tagName:"div",className:"history-panel",fxSpeed:"fast",emptyMsg:d("This history is empty"),noneFoundMsg:d("No matching datasets found"),initialize:function(m){m=m||{};if(m.logger){this.logger=m.logger}this.log(this+".initialize:",m);this.linkTarget=m.linkTarget||"_blank";this.fxSpeed=_.has(m,"fxSpeed")?(m.fxSpeed):(this.fxSpeed);this.filters=[];this.searchFor="";this.findContainerFn=m.findContainerFn;this.hdaViews={};this.indicator=new LoadingIndicator(this.$el);this._setUpListeners();var n=_.pick(m,"initiallyExpanded","show_deleted","show_hidden");this.setModel(this.model,n,false);if(m.onready){m.onready.call(this)}},_setUpListeners:function(){this.on("error",function(n,q,m,p,o){this.errorHandler(n,q,m,p,o)});this.on("loading-history",function(){this._showLoadingIndicator("loading history...",40)});this.on("loading-done",function(){this._hideLoadingIndicator(40);if(_.isEmpty(this.hdaViews)){this.trigger("empty-history",this)}});this.once("rendered",function(){this.trigger("rendered:initial",this);return false});if(this.logger){this.on("all",function(m){this.log(this+"",arguments)},this)}return this},errorHandler:function(o,r,n,q,p){this.error(o,r,n,q,p);if(r&&r.status===0&&r.readyState===0){}else{if(r&&r.status===502){}else{var m=this._parseErrorMessage(o,r,n,q,p);if(!this.$messages().is(":visible")){this.once("rendered",function(){this.displayMessage("error",m.message,m.details)})}else{this.displayMessage("error",m.message,m.details)}}}},_parseErrorMessage:function(p,t,o,s,r){var n=Galaxy.currUser,m={message:this._bePolite(s),details:{user:(n instanceof f.User)?(n.toJSON()):(n+""),source:(p instanceof Backbone.Model)?(p.toJSON()):(p+""),xhr:t,options:(t)?(_.omit(o,"xhr")):(o)}};_.extend(m.details,r||{});if(t&&_.isFunction(t.getAllResponseHeaders)){var q=t.getAllResponseHeaders();q=_.compact(q.split("\n"));q=_.map(q,function(u){return u.split(": ")});m.details.xhr.responseHeaders=_.object(q)}return m},_bePolite:function(m){m=m||d("An error occurred while getting updates from the server");return m+". "+d("Please contact a Galaxy administrator if the problem persists")+"."},loadHistoryWithHDADetails:function(o,n,m,q){var p=function(r){return _.values(i.get(r.id).get("expandedHdas"))};return this.loadHistory(o,n,m,q,p)},loadHistory:function(p,o,n,s,q){var m=this;o=o||{};m.trigger("loading-history",m);var r=e.History.getHistoryData(p,{historyFn:n,hdaFn:s,hdaDetailIds:o.initiallyExpanded||q});return m._loadHistoryFromXHR(r,o).fail(function(v,t,u){m.trigger("error",m,v,o,d("An error was encountered while "+t),{historyId:p,history:u||{}})}).always(function(){m.trigger("loading-done",m)})},_loadHistoryFromXHR:function(o,n){var m=this;o.then(function(p,q){m.JSONToModel(p,q,n)});o.fail(function(q,p){m.render()});return o},JSONToModel:function(p,m,n){this.log("JSONToModel:",p,m,n);n=n||{};var o=new e.History(p,m,n);this.setModel(o);return this},setModel:function(n,m,o){m=m||{};o=(o!==undefined)?(o):(true);this.log("setModel:",n,m,o);this.freeModel();this.selectedHdaIds=[];if(n){this.model=n;if(this.logger){this.model.logger=this.logger}this._setUpWebStorage(m.initiallyExpanded,m.show_deleted,m.show_hidden);this._setUpModelEventHandlers();this.trigger("new-model",this)}if(o){this.render()}return this},freeModel:function(){if(this.model){this.model.clearUpdateTimeout();this.stopListening(this.model);this.stopListening(this.model.contents)}this.freeHdaViews();return this},freeHdaViews:function(){this.hdaViews={};return this},_setUpWebStorage:function(n,m,o){this.storage=new i({id:i.historyStorageKey(this.model.get("id"))});if(_.isObject(n)){this.storage.set("exandedHdas",n)}if(_.isBoolean(m)){this.storage.set("show_deleted",m)}if(_.isBoolean(o)){this.storage.set("show_hidden",o)}this.trigger("new-storage",this.storage,this);this.log(this+" (init'd) storage:",this.storage.get());return this},_setUpModelEventHandlers:function(){this.model.contents.on("add",this.addContentView,this);this.model.on("error error:contents",function(n,p,m,o){this.errorHandler(n,p,m,o)},this);return this},render:function(o,p){this.log("render:",o,p);o=(o===undefined)?(this.fxSpeed):(o);var m=this,n;if(this.model){n=this.renderModel()}else{n=this.renderWithoutModel()}$(m).queue("fx",[function(q){if(o&&m.$el.is(":visible")){m.$el.fadeOut(o,q)}else{q()}},function(q){m.$el.empty();if(n){m.$el.append(n.children())}q()},function(q){if(o&&!m.$el.is(":visible")){m.$el.fadeIn(o,q)}else{q()}},function(q){if(p){p.call(this)}m.trigger("rendered",this);q()}]);return this},renderWithoutModel:function(){var m=$("
"),n=$("
").addClass("message-container").css({margin:"4px"});return m.append(n)},renderModel:function(){var m=$("
");m.append(j.templates.historyPanel(this.model.toJSON()));this.$emptyMessage(m).text(this.emptyMsg);m.find(".history-secondary-actions").prepend(this._renderSearchButton());this._setUpBehaviours(m);this.renderHdas(m);return m},_renderEmptyMsg:function(o){var n=this,m=n.$emptyMessage(o);if(!_.isEmpty(n.hdaViews)){m.hide()}else{if(n.searchFor){m.text(n.noneFoundMsg).show()}else{m.text(n.emptyMsg).show()}}return this},_renderSearchButton:function(m){return faIconButton({title:d("Search datasets"),classes:"history-search-btn",faIcon:"fa-search"})},_setUpBehaviours:function(m){m=m||this.$el;m.find("[title]").tooltip({placement:"bottom"});this._setUpSearchInput(m.find(".history-search-controls .history-search-input"));return this},$container:function(){return(this.findContainerFn)?(this.findContainerFn.call(this)):(this.$el.parent())},$datasetsList:function(m){return(m||this.$el).find(".datasets-list")},$messages:function(m){return(m||this.$el).find(".message-container")},$emptyMessage:function(m){return(m||this.$el).find(".empty-history-message")},renderHdas:function(n){n=n||this.$el;var m=this,p={},o=this.model.contents.getVisible(this.storage.get("show_deleted"),this.storage.get("show_hidden"),this.filters);this.$datasetsList(n).empty();if(o.length){o.each(function(r){var q=r.id,s=m._createContentView(r);p[q]=s;if(_.contains(m.selectedHdaIds,q)){s.selected=true}m.attachContentView(s.render(),n)})}this.hdaViews=p;this._renderEmptyMsg(n);return this.hdaViews},_createContentView:function(p){var n=this._getContentClass(p),m=_.extend(this._getContentOptions(p),{model:p}),o=new n(m);this._setUpHdaListeners(o);return o},_getContentClass:function(m){var n=m.get("history_content_type");switch(n){case"dataset":return this.HDAViewClass;case"dataset_collection":return this.HDCAViewClass}throw new TypeError("Unknown history_content_type: "+n)},_getContentOptions:function(m){return{linkTarget:this.linkTarget,expanded:!!this.storage.get("expandedHdas")[m.id],hasUser:this.model.ownedByCurrUser(),logger:this.logger}},_setUpHdaListeners:function(n){var m=this;n.on("error",function(p,r,o,q){m.errorHandler(p,r,o,q)});n.on("expanded",function(o){m.storage.addExpandedHda(o.model)});n.on("collapsed",function(o){m.storage.removeExpandedHda(o.model)});return this},attachContentView:function(o,n){n=n||this.$el;var m=this.$datasetsList(n);m.prepend(o.$el);return this},addContentView:function(p){this.log("add."+this,p);var n=this;if(!p.isVisible(this.storage.get("show_deleted"),this.storage.get("show_hidden"))){return n}$({}).queue([function o(r){var q=n.$emptyMessage();if(q.is(":visible")){q.fadeOut(n.fxSpeed,r)}else{r()}},function m(q){var r=n._createContentView(p);n.hdaViews[p.id]=r;r.render().$el.hide();n.scrollToTop();n.attachContentView(r);r.$el.slideDown(n.fxSpeed)}]);return n},views:function(m){var n=this,o=this.model.contents.getVisible(this.storage.get("show_deleted"),this.storage.get("show_hidden"),this.filters);if(m!==undefined){return n.hdaViews[o.at(m).id]}return o.map(function(p){return n.hdaViews[p.id]})},refreshContents:function(n,m){if(this.model){return this.model.refresh(n,m)}return $.when()},hdaViewRange:function(p,o){if(p===o){return[p]}var m=this,n=false,q=[];this.model.contents.getVisible(this.storage.get("show_deleted"),this.storage.get("show_hidden"),this.filters).each(function(r){if(n){q.push(m.hdaViews[r.id]);if(r===p.model||r===o.model){n=false}}else{if(r===p.model||r===o.model){n=true;q.push(m.hdaViews[r.id])}}});return q},events:{"click .message-container":"clearMessages","click .history-search-btn":"toggleSearchControls"},collapseAllHdaBodies:function(){_.each(this.hdaViews,function(m){m.collapse()});this.storage.set("expandedHdas",{});return this},toggleShowDeleted:function(m){m=(m!==undefined)?(m):(!this.storage.get("show_deleted"));this.storage.set("show_deleted",m);this.renderHdas();return this.storage.get("show_deleted")},toggleShowHidden:function(m){m=(m!==undefined)?(m):(!this.storage.get("show_hidden"));this.storage.set("show_hidden",m);this.renderHdas();return this.storage.get("show_hidden")},_setUpSearchInput:function(n){var o=this,p=".history-search-input";function m(q){if(o.model.contents.haveDetails()){o.searchHdas(q);return}o.$el.find(p).searchInput("toggle-loading");o.model.contents.fetchAllDetails({silent:true}).always(function(){o.$el.find(p).searchInput("toggle-loading")}).done(function(){o.searchHdas(q)})}n.searchInput({initialVal:o.searchFor,name:"history-search",placeholder:"search datasets",classes:"history-search",onfirstsearch:m,onsearch:_.bind(this.searchHdas,this),onclear:_.bind(this.clearHdaSearch,this)});return n},toggleSearchControls:function(o,m){var n=this.$el.find(".history-search-controls"),p=(jQuery.type(o)==="number")?(o):(this.fxSpeed);m=(m!==undefined)?(m):(!n.is(":visible"));if(m){n.slideDown(p,function(){$(this).find("input").focus()})}else{n.slideUp(p)}return m},searchHdas:function(m){var n=this;this.searchFor=m;this.filters=[function(o){return o.matchesAll(n.searchFor)}];this.trigger("search:searching",m,this);this.renderHdas();return this},clearHdaSearch:function(m){this.searchFor="";this.filters=[];this.trigger("search:clear",this);this.renderHdas();return this},_showLoadingIndicator:function(n,m,o){m=(m!==undefined)?(m):(this.fxSpeed);if(!this.indicator){this.indicator=new LoadingIndicator(this.$el,this.$el.parent())}if(!this.$el.is(":visible")){this.indicator.show(0,o)}else{this.$el.fadeOut(m);this.indicator.show(n,m,o)}},_hideLoadingIndicator:function(m,n){m=(m!==undefined)?(m):(this.fxSpeed);if(this.indicator){this.indicator.hide(m,n)}},displayMessage:function(r,s,q){var o=this;this.scrollToTop();var p=this.$messages(),m=$("
").addClass(r+"message").html(s);if(!_.isEmpty(q)){var n=$('Details').click(function(){Galaxy.modal.show(o._messageToModalOptions(r,s,q));return false});m.append(" ",n)}return p.html(m)},_messageToModalOptions:function(q,s,p){var m=this,r=$("
"),o={title:"Details"};function n(t){t=_.omit(t,_.functions(t));return["",_.map(t,function(v,u){v=(_.isObject(v))?(n(v)):(v);return'"}).join(""),"
'+u+''+v+"
"].join("")}if(_.isObject(p)){o.body=r.append(n(p))}else{o.body=r.html(p)}o.buttons={Ok:function(){Galaxy.modal.hide();m.clearMessages()}};return o},clearMessages:function(){this.$messages().empty();return this},scrollPosition:function(){return this.$container().scrollTop()},scrollTo:function(m){this.$container().scrollTop(m);return this},scrollToTop:function(){this.$container().scrollTop(0);return this},scrollToId:function(n){if((!n)||(!this.hdaViews[n])){return this}var m=this.hdaViews[n];this.scrollTo(m.el.offsetTop);return this},scrollToHid:function(m){var n=this.model.contents.getByHid(m);if(!n){return this}return this.scrollToId(n.id)},print:function(){var m=this;m.debug(this);_.each(this.hdaViews,function(n,o){m.debug("\t "+o,n)})},toString:function(){return"ReadOnlyHistoryPanel("+((this.model)?(this.model.get("name")):(""))+")"}});var l=['
','
','
',"
",'
',"<% if( history.name ){ %>",'
<%= history.name %>
',"<% } %>","
",'
',"<% if( history.nice_size ){ %>",'
<%= history.nice_size %>
',"<% } %>",'
',"
","<% if( history.deleted ){ %>",'
',d("You are currently viewing a deleted history!"),"
","<% } %>",'
',"<% if( history.message ){ %>",'
<%= history.message %>
',"<% } %>","
",'
',d("You are over your disk quota"),". ",d("Tool execution is on hold until your disk usage drops below your allocated quota"),".","
",'
','
','
','
','",'","
",'","
","
",'
','
',d("This history is empty"),"
"].join("");j.templates={historyPanel:function(m){return _.template(l,m,{variable:"history"})}};return{ReadOnlyHistoryPanel:j}}); \ No newline at end of file diff --git a/static/scripts/packed/mvc/history/readonly-history-panel.js b/static/scripts/packed/mvc/history/readonly-history-panel.js deleted file mode 100644 index 7bc6cb9954c..00000000000 --- a/static/scripts/packed/mvc/history/readonly-history-panel.js +++ /dev/null @@ -1 +0,0 @@ -define(["mvc/history/history-model","mvc/collection/hdca-base","mvc/dataset/dataset-list-element","mvc/dataset/hda-base","mvc/user/user-model","mvc/base-mvc","utils/localization"],function(d,a,k,i,e,l,c){var h=l.SessionStorageModel.extend({defaults:{expandedHdas:{},show_deleted:false,show_hidden:false},addExpandedHda:function(n){var o="expandedHdas";this.save(o,_.extend(this.get(o),_.object([n.id],[n.get("id")])))},removeExpandedHda:function(n){var o="expandedHdas";this.save(o,_.omit(this.get(o),n.id))},toString:function(){return"HistoryPrefs("+this.id+")"}});h.storageKeyPrefix="history:";h.historyStorageKey=function f(n){if(!n){throw new Error("HistoryPrefs.historyStorageKey needs valid id: "+n)}return(h.storageKeyPrefix+n)};h.get=function b(n){return new h({id:h.historyStorageKey(n)})};h.clearAll=function g(o){for(var n in sessionStorage){if(n.indexOf(h.storageKeyPrefix)===0){sessionStorage.removeItem(n)}}};var j=Backbone.View.extend(l.LoggableMixin).extend({HDAViewClass:k.DatasetListItemView,HDCAViewClass:a.HDCABaseView,tagName:"div",className:"history-panel",fxSpeed:"fast",emptyMsg:c("This history is empty"),noneFoundMsg:c("No matching datasets found"),initialize:function(n){n=n||{};if(n.logger){this.logger=n.logger}this.log(this+".initialize:",n);this.linkTarget=n.linkTarget||"_blank";this.fxSpeed=_.has(n,"fxSpeed")?(n.fxSpeed):(this.fxSpeed);this.filters=[];this.searchFor="";this.findContainerFn=n.findContainerFn;this.hdaViews={};this.indicator=new LoadingIndicator(this.$el);this._setUpListeners();var o=_.pick(n,"initiallyExpanded","show_deleted","show_hidden");this.setModel(this.model,o,false);if(n.onready){n.onready.call(this)}},_setUpListeners:function(){this.on("error",function(o,r,n,q,p){this.errorHandler(o,r,n,q,p)});this.on("loading-history",function(){this._showLoadingIndicator("loading history...",40)});this.on("loading-done",function(){this._hideLoadingIndicator(40);if(_.isEmpty(this.hdaViews)){this.trigger("empty-history",this)}});this.once("rendered",function(){this.trigger("rendered:initial",this);return false});if(this.logger){this.on("all",function(n){this.log(this+"",arguments)},this)}return this},errorHandler:function(p,s,o,r,q){this.error(p,s,o,r,q);if(s&&s.status===0&&s.readyState===0){}else{if(s&&s.status===502){}else{var n=this._parseErrorMessage(p,s,o,r,q);if(!this.$messages().is(":visible")){this.once("rendered",function(){this.displayMessage("error",n.message,n.details)})}else{this.displayMessage("error",n.message,n.details)}}}},_parseErrorMessage:function(q,u,p,t,s){var o=Galaxy.currUser,n={message:this._bePolite(t),details:{user:(o instanceof e.User)?(o.toJSON()):(o+""),source:(q instanceof Backbone.Model)?(q.toJSON()):(q+""),xhr:u,options:(u)?(_.omit(p,"xhr")):(p)}};_.extend(n.details,s||{});if(u&&_.isFunction(u.getAllResponseHeaders)){var r=u.getAllResponseHeaders();r=_.compact(r.split("\n"));r=_.map(r,function(v){return v.split(": ")});n.details.xhr.responseHeaders=_.object(r)}return n},_bePolite:function(n){n=n||c("An error occurred while getting updates from the server");return n+". "+c("Please contact a Galaxy administrator if the problem persists")+"."},loadHistoryWithHDADetails:function(p,o,n,r){var q=function(s){return _.values(h.get(s.id).get("expandedHdas"))};return this.loadHistory(p,o,n,r,q)},loadHistory:function(q,p,o,t,r){var n=this;p=p||{};n.trigger("loading-history",n);var s=d.History.getHistoryData(q,{historyFn:o,hdaFn:t,hdaDetailIds:p.initiallyExpanded||r});return n._loadHistoryFromXHR(s,p).fail(function(w,u,v){n.trigger("error",n,w,p,c("An error was encountered while "+u),{historyId:q,history:v||{}})}).always(function(){n.trigger("loading-done",n)})},_loadHistoryFromXHR:function(p,o){var n=this;p.then(function(q,r){n.JSONToModel(q,r,o)});p.fail(function(r,q){n.render()});return p},JSONToModel:function(q,n,o){this.log("JSONToModel:",q,n,o);o=o||{};var p=new d.History(q,n,o);this.setModel(p);return this},setModel:function(o,n,p){n=n||{};p=(p!==undefined)?(p):(true);this.log("setModel:",o,n,p);this.freeModel();this.selectedHdaIds=[];if(o){this.model=o;if(this.logger){this.model.logger=this.logger}this._setUpWebStorage(n.initiallyExpanded,n.show_deleted,n.show_hidden);this._setUpModelEventHandlers();this.trigger("new-model",this)}if(p){this.render()}return this},freeModel:function(){if(this.model){this.model.clearUpdateTimeout();this.stopListening(this.model);this.stopListening(this.model.contents)}this.freeHdaViews();return this},freeHdaViews:function(){this.hdaViews={};return this},_setUpWebStorage:function(o,n,p){this.storage=new h({id:h.historyStorageKey(this.model.get("id"))});if(_.isObject(o)){this.storage.set("exandedHdas",o)}if(_.isBoolean(n)){this.storage.set("show_deleted",n)}if(_.isBoolean(p)){this.storage.set("show_hidden",p)}this.trigger("new-storage",this.storage,this);this.log(this+" (init'd) storage:",this.storage.get());return this},_setUpModelEventHandlers:function(){this.model.contents.on("add",this.addContentView,this);this.model.on("error error:contents",function(o,q,n,p){this.errorHandler(o,q,n,p)},this);return this},render:function(p,q){this.log("render:",p,q);p=(p===undefined)?(this.fxSpeed):(p);var n=this,o;if(this.model){o=this.renderModel()}else{o=this.renderWithoutModel()}$(n).queue("fx",[function(r){if(p&&n.$el.is(":visible")){n.$el.fadeOut(p,r)}else{r()}},function(r){n.$el.empty();if(o){n.$el.append(o.children())}r()},function(r){if(p&&!n.$el.is(":visible")){n.$el.fadeIn(p,r)}else{r()}},function(r){if(q){q.call(this)}n.trigger("rendered",this);r()}]);return this},renderWithoutModel:function(){var n=$("
"),o=$("
").addClass("message-container").css({margin:"4px"});return n.append(o)},renderModel:function(){var n=$("
");n.append(j.templates.historyPanel(this.model.toJSON()));this.$emptyMessage(n).text(this.emptyMsg);n.find(".history-secondary-actions").prepend(this._renderSearchButton());this._setUpBehaviours(n);this.renderHdas(n);return n},_renderEmptyMsg:function(p){var o=this,n=o.$emptyMessage(p);if(!_.isEmpty(o.hdaViews)){n.hide()}else{if(o.searchFor){n.text(o.noneFoundMsg).show()}else{n.text(o.emptyMsg).show()}}return this},_renderSearchButton:function(n){return faIconButton({title:c("Search datasets"),classes:"history-search-btn",faIcon:"fa-search"})},_setUpBehaviours:function(n){n=n||this.$el;n.find("[title]").tooltip({placement:"bottom"});this._setUpSearchInput(n.find(".history-search-controls .history-search-input"));return this},$container:function(){return(this.findContainerFn)?(this.findContainerFn.call(this)):(this.$el.parent())},$datasetsList:function(n){return(n||this.$el).find(".datasets-list")},$messages:function(n){return(n||this.$el).find(".message-container")},$emptyMessage:function(n){return(n||this.$el).find(".empty-history-message")},renderHdas:function(o){o=o||this.$el;var n=this,q={},p=this.model.contents.getVisible(this.storage.get("show_deleted"),this.storage.get("show_hidden"),this.filters);this.$datasetsList(o).empty();if(p.length){p.each(function(s){var r=s.id,t=n._createContentView(s);q[r]=t;if(_.contains(n.selectedHdaIds,r)){t.selected=true}n.attachContentView(t.render(),o)})}this.hdaViews=q;this._renderEmptyMsg(o);return this.hdaViews},_createContentView:function(q){var o=this._getContentClass(q),n=_.extend(this._getContentOptions(q),{model:q}),p=new o(n);this._setUpHdaListeners(p);return p},_getContentClass:function(n){var o=n.get("history_content_type");switch(o){case"dataset":return this.HDAViewClass;case"dataset_collection":return this.HDCAViewClass}throw new TypeError("Unknown history_content_type: "+o)},_getContentOptions:function(n){return{linkTarget:this.linkTarget,expanded:!!this.storage.get("expandedHdas")[n.id],hasUser:this.model.ownedByCurrUser(),logger:this.logger}},_setUpHdaListeners:function(o){var n=this;o.on("error",function(q,s,p,r){n.errorHandler(q,s,p,r)});o.on("expanded",function(p){n.storage.addExpandedHda(p.model)});o.on("collapsed",function(p){n.storage.removeExpandedHda(p.model)});return this},attachContentView:function(p,o){o=o||this.$el;var n=this.$datasetsList(o);n.prepend(p.$el);return this},addContentView:function(q){this.log("add."+this,q);var o=this;if(!q.isVisible(this.storage.get("show_deleted"),this.storage.get("show_hidden"))){return o}$({}).queue([function p(s){var r=o.$emptyMessage();if(r.is(":visible")){r.fadeOut(o.fxSpeed,s)}else{s()}},function n(r){var s=o._createContentView(q);o.hdaViews[q.id]=s;s.render().$el.hide();o.scrollToTop();o.attachContentView(s);s.$el.slideDown(o.fxSpeed)}]);return o},views:function(n){var o=this,p=this.model.contents.getVisible(this.storage.get("show_deleted"),this.storage.get("show_hidden"),this.filters);if(n!==undefined){return o.hdaViews[p.at(n).id]}return p.map(function(q){return o.hdaViews[q.id]})},refreshContents:function(o,n){if(this.model){return this.model.refresh(o,n)}return $.when()},hdaViewRange:function(q,p){if(q===p){return[q]}var n=this,o=false,r=[];this.model.contents.getVisible(this.storage.get("show_deleted"),this.storage.get("show_hidden"),this.filters).each(function(s){if(o){r.push(n.hdaViews[s.id]);if(s===q.model||s===p.model){o=false}}else{if(s===q.model||s===p.model){o=true;r.push(n.hdaViews[s.id])}}});return r},events:{"click .message-container":"clearMessages","click .history-search-btn":"toggleSearchControls"},collapseAllHdaBodies:function(){_.each(this.hdaViews,function(n){n.collapse()});this.storage.set("expandedHdas",{});return this},toggleShowDeleted:function(n){n=(n!==undefined)?(n):(!this.storage.get("show_deleted"));this.storage.set("show_deleted",n);this.renderHdas();return this.storage.get("show_deleted")},toggleShowHidden:function(n){n=(n!==undefined)?(n):(!this.storage.get("show_hidden"));this.storage.set("show_hidden",n);this.renderHdas();return this.storage.get("show_hidden")},_setUpSearchInput:function(o){var p=this,q=".history-search-input";function n(r){if(p.model.contents.haveDetails()){p.searchHdas(r);return}p.$el.find(q).searchInput("toggle-loading");p.model.contents.fetchAllDetails({silent:true}).always(function(){p.$el.find(q).searchInput("toggle-loading")}).done(function(){p.searchHdas(r)})}o.searchInput({initialVal:p.searchFor,name:"history-search",placeholder:"search datasets",classes:"history-search",onfirstsearch:n,onsearch:_.bind(this.searchHdas,this),onclear:_.bind(this.clearHdaSearch,this)});return o},toggleSearchControls:function(p,n){var o=this.$el.find(".history-search-controls"),q=(jQuery.type(p)==="number")?(p):(this.fxSpeed);n=(n!==undefined)?(n):(!o.is(":visible"));if(n){o.slideDown(q,function(){$(this).find("input").focus()})}else{o.slideUp(q)}return n},searchHdas:function(n){var o=this;this.searchFor=n;this.filters=[function(p){return p.matchesAll(o.searchFor)}];this.trigger("search:searching",n,this);this.renderHdas();return this},clearHdaSearch:function(n){this.searchFor="";this.filters=[];this.trigger("search:clear",this);this.renderHdas();return this},_showLoadingIndicator:function(o,n,p){n=(n!==undefined)?(n):(this.fxSpeed);if(!this.indicator){this.indicator=new LoadingIndicator(this.$el,this.$el.parent())}if(!this.$el.is(":visible")){this.indicator.show(0,p)}else{this.$el.fadeOut(n);this.indicator.show(o,n,p)}},_hideLoadingIndicator:function(n,o){n=(n!==undefined)?(n):(this.fxSpeed);if(this.indicator){this.indicator.hide(n,o)}},displayMessage:function(s,t,r){var p=this;this.scrollToTop();var q=this.$messages(),n=$("
").addClass(s+"message").html(t);if(!_.isEmpty(r)){var o=$('Details').click(function(){Galaxy.modal.show(p._messageToModalOptions(s,t,r));return false});n.append(" ",o)}return q.html(n)},_messageToModalOptions:function(r,t,q){var n=this,s=$("
"),p={title:"Details"};function o(u){u=_.omit(u,_.functions(u));return["",_.map(u,function(w,v){w=(_.isObject(w))?(o(w)):(w);return'"}).join(""),"
'+v+''+w+"
"].join("")}if(_.isObject(q)){p.body=s.append(o(q))}else{p.body=s.html(q)}p.buttons={Ok:function(){Galaxy.modal.hide();n.clearMessages()}};return p},clearMessages:function(){this.$messages().empty();return this},scrollPosition:function(){return this.$container().scrollTop()},scrollTo:function(n){this.$container().scrollTop(n);return this},scrollToTop:function(){this.$container().scrollTop(0);return this},scrollToId:function(o){if((!o)||(!this.hdaViews[o])){return this}var n=this.hdaViews[o];this.scrollTo(n.el.offsetTop);return this},scrollToHid:function(n){var o=this.model.contents.getByHid(n);if(!o){return this}return this.scrollToId(o.id)},print:function(){var n=this;n.debug(this);_.each(this.hdaViews,function(o,p){n.debug("\t "+p,o)})},toString:function(){return"ReadOnlyHistoryPanel("+((this.model)?(this.model.get("name")):(""))+")"}});var m=['
','
','
',"
",'
',"<% if( history.name ){ %>",'
<%= history.name %>
',"<% } %>","
",'
',"<% if( history.nice_size ){ %>",'
<%= history.nice_size %>
',"<% } %>",'
',"
","<% if( history.deleted ){ %>",'
',c("You are currently viewing a deleted history!"),"
","<% } %>",'
',"<% if( history.message ){ %>",'
<%= history.message %>
',"<% } %>","
",'
',c("You are over your disk quota"),". ",c("Tool execution is on hold until your disk usage drops below your allocated quota"),".","
",'
','
','
','
','",'","
",'","
","
",'
','
',c("This history is empty"),"
"].join("");j.templates={historyPanel:function(n){return _.template(m,n,{variable:"history"})}};return{ReadOnlyHistoryPanel:j}}); \ No newline at end of file diff --git a/templates/webapps/galaxy/history/display.mako b/templates/webapps/galaxy/history/display.mako index e7c601334a6..5ab2db1042a 100644 --- a/templates/webapps/galaxy/history/display.mako +++ b/templates/webapps/galaxy/history/display.mako @@ -53,7 +53,7 @@ require.config({ baseUrl : "${h.url_for( '/static/scripts' )}" - })([ 'mvc/history/annotated-history-panel' ], function( panelMod ){ + })([ 'mvc/history/history-panel-annotated' ], function( panelMod ){ // history module is already in the dpn chain from the panel. We can re-scope it here. var historyModel = require( 'mvc/history/history-model' ), history = new historyModel.History( historyJSON, hdaJSON, { diff --git a/templates/webapps/galaxy/history/display_structured.mako b/templates/webapps/galaxy/history/display_structured.mako index df2a29d571b..70c6ea05e8c 100644 --- a/templates/webapps/galaxy/history/display_structured.mako +++ b/templates/webapps/galaxy/history/display_structured.mako @@ -143,12 +143,11 @@ ## load edit views for each of the hdas