From 47629433416e6ba65f246a9b6a91aeb7cff9d4bf Mon Sep 17 00:00:00 2001 From: Carl Eberhard Date: Thu, 31 Jul 2014 12:05:26 -0400 Subject: [PATCH] Collections view drill-down: (still a work in progress) allow overlay of collection panel view over *current* history panel (not implemented for other history panels), refactoring of history/hda/collections; remove unused init_history_items; pack scripts --- static/scripts/galaxy.base.js | 82 --- static/scripts/mvc/base-mvc.js | 138 +++- .../mvc/collection/collection-model.js | 174 +++-- .../mvc/collection/collection-panel.js | 258 ++++--- .../mvc/collection/dataset-collection-base.js | 467 ++++++++++--- static/scripts/mvc/collection/hdca-base.js | 56 +- static/scripts/mvc/collection/hdca-edit.js | 8 +- static/scripts/mvc/collection/hdca-model.js | 20 +- static/scripts/mvc/dataset/hda-base.js | 66 +- static/scripts/mvc/dataset/hda-edit.js | 66 +- .../mvc/history/current-history-panel.js | 76 ++- .../mvc/history/history-content-base-view.js | 46 +- .../mvc/history/history-content-base.js | 10 +- .../mvc/history/readonly-history-panel.js | 20 +- static/scripts/packed/galaxy.base.js | 2 +- static/scripts/packed/galaxy.tools.js | 2 +- static/scripts/packed/mvc/base-mvc.js | 2 +- .../packed/mvc/collection/collection-model.js | 2 +- .../packed/mvc/collection/collection-panel.js | 2 +- .../mvc/collection/dataset-collection-base.js | 2 +- .../packed/mvc/collection/hdca-base.js | 2 +- .../packed/mvc/collection/hdca-edit.js | 2 +- .../packed/mvc/collection/hdca-model.js | 2 +- static/scripts/packed/mvc/dataset/hda-base.js | 2 +- static/scripts/packed/mvc/dataset/hda-edit.js | 2 +- .../mvc/history/current-history-panel.js | 2 +- .../mvc/history/history-content-base-view.js | 2 +- .../mvc/history/history-content-base.js | 2 +- .../mvc/history/readonly-history-panel.js | 2 +- static/style/blue/base.css | 115 ++-- static/style/src/less/base.less | 193 +----- static/style/src/less/collections.less | 89 ++- static/style/src/less/history.less | 631 +++++++++++------- templates/display_base.mako | 3 - templates/webapps/galaxy/page/display.mako | 8 - 35 files changed, 1584 insertions(+), 972 deletions(-) diff --git a/static/scripts/galaxy.base.js b/static/scripts/galaxy.base.js index d37f09eac84..b2b621d9a2c 100644 --- a/static/scripts/galaxy.base.js +++ b/static/scripts/galaxy.base.js @@ -463,88 +463,6 @@ function async_save_text( click_to_edit_elt, text_elt_id, save_url, }); } -function init_history_items(historywrapper, noinit, nochanges) { - //NOTE: still needed for non-panel history views - - var action = function() { - // Load saved state and show as necessary - try { - var stored = $.jStorage.get("history_expand_state"); - if (stored) { - for (var id in stored) { - $("#" + id + " div.historyItemBody" ).show(); - } - } - } catch(err) { - // Something was wrong with values in storage, so clear storage - $.jStorage.deleteKey("history_expand_state"); - } - - // If Mozilla, hide scrollbars in hidden items since they cause animation bugs - if ( $.browser.mozilla ) { - $( "div.historyItemBody" ).each( function() { - if ( !$(this).is(":visible") ) { $(this).find( "pre.peek" ).css( "overflow", "hidden" ); } - }); - } - - historywrapper.each( function() { - var id = this.id, - body = $(this).children( "div.historyItemBody" ), - peek = body.find( "pre.peek" ); - $(this).find( ".historyItemTitleBar > .historyItemTitle" ).wrap( "" ) - .click( function() { - var prefs; - if ( body.is(":visible") ) { - // Hiding stuff here - if ( $.browser.mozilla ) { peek.css( "overflow", "hidden" ); } - body.slideUp( "fast" ); - - if (!nochanges) { // Ignore embedded item actions - // Save setting - prefs = $.jStorage.get("history_expand_state"); - if (prefs) { - delete prefs[id]; - $.jStorage.set("history_expand_state", prefs); - } - } - } else { - // Showing stuff here - body.slideDown( "fast", function() { - if ( $.browser.mozilla ) { peek.css( "overflow", "auto" ); } - }); - - if (!nochanges) { - // Save setting - prefs = $.jStorage.get("history_expand_state"); - if (!prefs) { prefs = {}; } - prefs[id] = true; - $.jStorage.set("history_expand_state", prefs); - } - } - return false; - }); - }); - - // Generate 'collapse all' link - $("#top-links > a.toggle").click( function() { - var prefs = $.jStorage.get("history_expand_state"); - if (!prefs) { prefs = {}; } - $( "div.historyItemBody:visible" ).each( function() { - if ( $.browser.mozilla ) { - $(this).find( "pre.peek" ).css( "overflow", "hidden" ); - } - $(this).slideUp( "fast" ); - if (prefs) { - delete prefs[$(this).parent().attr("id")]; - } - }); - $.jStorage.set("history_expand_state", prefs); - }).show(); - }; - - action(); -} - function commatize( number ) { number += ''; // Convert to string var rgx = /(\d+)(\d{3})/; diff --git a/static/scripts/mvc/base-mvc.js b/static/scripts/mvc/base-mvc.js index ad4ffddbf71..405d823677c 100644 --- a/static/scripts/mvc/base-mvc.js +++ b/static/scripts/mvc/base-mvc.js @@ -220,11 +220,147 @@ function mixin( mixinHash1, /* mixinHash2, etc: ... variadic */ propsHash ){ } +//============================================================================== +var ExpandableView = Backbone.View.extend( LoggableMixin ).extend({ +//TODO: Although the reasoning behind them is different, this shares a lot with HiddenUntilActivated above: combine them + //PRECONDITION: model must have method hasDetails + + initialize : function( attributes ){ + /** are the details of this view expanded/shown or not? */ + this.expanded = attributes.expanded || false; + this.log( '\t expanded:', this.expanded ); + }, + + // ........................................................................ render main +//TODO: for lack of a better place, add rendering logic here + fxSpeed : 'fast', + + /** Render this content, set up ui. + * @param {Integer} speed the speed of the render + * @fires rendered when rendered + * @fires rendered:ready when first rendered and NO running HDAs + * @returns {Object} this HDABaseView + */ + render : function( speed ){ + var $newRender = this._buildNewRender(); + this._queueNewRender( $newRender, speed ); + return this; + }, + + _buildNewRender : function(){ + // create a new render using a skeleton template, render title buttons, render body, and set up events, etc. + var $newRender = $( this.templates.skeleton( this.model.toJSON() ) ); + if( this.expanded ){ + $newRender.children( '.details' ).replaceWith( this._renderDetails() ); + } + this._setUpBehaviors( $newRender ); + return $newRender; + }, + + /** Fade out the old el, replace with new dom, then fade in. + * @param {Boolean} fade whether or not to fade out/in when re-rendering + * @fires rendered when rendered + * @fires rendered:ready when first rendered and NO running HDAs + */ + _queueNewRender : function( $newRender, speed ) { + speed = ( speed === undefined )?( this.fxSpeed ):( speed ); + var view = this; + + $( view ).queue( 'fx', [ + function( next ){ this.$el.fadeOut( speed, next ); }, + function( next ){ + view._swapNewRender( $newRender ); + next(); + }, + function( next ){ this.$el.fadeIn( speed, next ); }, + function( next ){ + this.trigger( 'rendered', view ); + next(); + } + ]); + }, + + _swapNewRender : function( $newRender ){ + return this.$el.empty().attr( 'class', this.className ).append( $newRender.children() ); + }, + + /** set up js behaviors, event handlers for elements within the given container + * @param {jQuery} $container jq object that contains the elements to process (defaults to this.$el) + */ + _setUpBehaviors : function( $container ){ + $container = $container || this.$el; + // set up canned behavior on children (bootstrap, popupmenus, editable_text, etc.) + make_popup_menus( $container ); + $container.find( '[title]' ).tooltip({ placement : 'bottom' }); + }, + + // ......................................................................... details + _renderDetails : function(){ + // override this + return null; + }, + + // ......................................................................... expansion/details + /** Show or hide the body/details of history content. + * @param {Boolean} expand if true, expand; if false, collapse + */ + toggleExpanded : function( expand ){ + expand = ( expand === undefined )?( !this.expanded ):( expand ); + if( expand ){ + this.expand(); + } else { + this.collapse(); + } + return this; + }, + + /** Render and show the full, detailed body of this view including extra data and controls. + * note: if the model does not have detailed data, fetch that data before showing the body + * @fires expanded when a body has been expanded + */ + expand : function(){ + var view = this; + + function _renderDetailsAndExpand(){ + view.$( '.details' ).replaceWith( view._renderDetails() ); + // needs to be set after the above or the slide will not show + view.expanded = true; + view.$( '.details' ).slideDown( view.fxSpeed, function(){ + view.trigger( 'expanded', view ); + }); + } +//TODO:?? remove + // fetch first if no details in the model + if( !view.model.hasDetails() ){ + // we need the change event on HDCA's for the elements to be processed - so silent == false + view.model.fetch().always( function( model ){ + _renderDetailsAndExpand(); + }); +//TODO: no error handling + } else { + _renderDetailsAndExpand(); + } + }, + + /** Hide the body/details of an HDA. + * @fires collapsed when a body has been collapsed + */ + collapse : function(){ + var view = this; + view.expanded = false; + this.$( '.details' ).slideUp( view.fxSpeed, function(){ + view.trigger( 'collapsed', view ); + }); + } + +}); + //============================================================================== return { LoggableMixin : LoggableMixin, SessionStorageModel : SessionStorageModel, HiddenUntilActivatedViewMixin : HiddenUntilActivatedViewMixin, - mixin : mixin + mixin : mixin, + ExpandableView : ExpandableView }; }); diff --git a/static/scripts/mvc/collection/collection-model.js b/static/scripts/mvc/collection/collection-model.js index 9a82a6333e3..ade887396b1 100644 --- a/static/scripts/mvc/collection/collection-model.js +++ b/static/scripts/mvc/collection/collection-model.js @@ -16,6 +16,7 @@ define([ */ var DatasetCollectionElement = Backbone.Model.extend( BASE_MVC.LoggableMixin ).extend( /** @lends DatasetCollectionElement.prototype */{ + //TODO:?? this model may be unneccessary - it reflects the api structure, but... // if we munge the element with the element.object at parse, we can flatten the entire hierarchy @@ -24,7 +25,6 @@ var DatasetCollectionElement = Backbone.Model.extend( BASE_MVC.LoggableMixin ).e //logger : console, defaults : { - id : null, model_class : 'DatasetCollectionElement', element_identifier : null, element_index : null, @@ -41,33 +41,48 @@ var DatasetCollectionElement = Backbone.Model.extend( BASE_MVC.LoggableMixin ).e this.object = this._createObjectModel(); this.on( 'change:object', function(){ - //console.log( 'change:object' ); + //this.log( 'change:object' ); //TODO: prob. better to update the sub-model instead of re-creating it this.object = this._createObjectModel(); }); }, _createObjectModel : function(){ - //console.log( '_createObjectModel', this.get( 'object' ), this.object ); + //this.log( '_createObjectModel', this.get( 'object' ), this.object ); //TODO: same patterns as HDCA _createElementsModel - refactor to BASE_MVC.hasSubModel? if( _.isUndefined( this.object ) ){ this.object = null; } if( !this.get( 'object' ) ){ return this.object; } - var object = this.get( 'object' ); + var object = this.get( 'object' ), + ObjectClass = this._getObjectClass(); this.unset( 'object', { silent: true }); + this.object = new ObjectClass( object ); + return this.object; + }, + + _getObjectClass : function(){ this.debug( 'DCE, element_type:', this.get( 'element_type' ) ); switch( this.get( 'element_type' ) ){ case 'dataset_collection': - this.object = new DatasetCollection( object ); - break; + return DatasetCollection; case 'hda': - this.object = new HDA_MODEL.HistoryDatasetAssociation( object ); - break; - default: - throw new TypeError( 'Unknown element_type: ' + this.get( 'element_type' ) ); + return HDA_MODEL.HistoryDatasetAssociation; } - return this.object; + throw new TypeError( 'Unknown element_type: ' + this.get( 'element_type' ) ); + }, + + toJSON : function(){ + var json = Backbone.Model.prototype.toJSON.call( this ); + if( this.object ){ + json.object = this.object.toJSON(); + } + return json; + }, + + hasDetails : function(){ + return ( this.object !== null + && this.object.hasDetails() ); }, /** String representation. */ @@ -78,6 +93,52 @@ var DatasetCollectionElement = Backbone.Model.extend( BASE_MVC.LoggableMixin ).e }); +//============================================================================== +/** @class Backbone model for + * @borrows LoggableMixin#logger as #logger + * @borrows LoggableMixin#log as #log + * @constructs + */ +var HDADCE = DatasetCollectionElement.extend( +/** @lends DatasetCollectionElement.prototype */{ + + _getObjectClass : function(){ + return HDA_MODEL.HistoryDatasetAssociation; + }, + + /** String representation. */ + toString : function(){ + var objStr = ( this.object )?( '' + this.object ):( this.get( 'element_identifier' ) ); + return ([ 'HDADCE(', objStr, ')' ].join( '' )); + } +}); + + +//============================================================================== +/** @class Backbone model for + * @borrows LoggableMixin#logger as #logger + * @borrows LoggableMixin#log as #log + * @constructs + */ +var DCDCE = DatasetCollectionElement.extend( +/** @lends DatasetCollectionElement.prototype */{ + + _getObjectClass : function(){ + return DatasetCollection; + }, + + getVisibleContents : function(){ + return this.object? this.object.getVisibleContents(): []; + }, + + /** String representation. */ + toString : function(){ + var objStr = ( this.object )?( '' + this.object ):( this.get( 'element_identifier' ) ); + return ([ 'DCDCE(', objStr, ')' ].join( '' )); + } +}); + + //============================================================================== /** @class Backbone collection for DCEs. * NOTE: used *only* in second level of list:paired collections (a @@ -87,7 +148,7 @@ var DatasetCollectionElement = Backbone.Model.extend( BASE_MVC.LoggableMixin ).e * @borrows LoggableMixin#log as #log * @constructs */ -var DatasetCollectionElementCollection = Backbone.Collection.extend( BASE_MVC.LoggableMixin ).extend( +var DCECollection = Backbone.Collection.extend( BASE_MVC.LoggableMixin ).extend( /** @lends DatasetCollectionElementCollection.prototype */{ model: DatasetCollectionElement, @@ -111,6 +172,40 @@ var DatasetCollectionElementCollection = Backbone.Collection.extend( BASE_MVC.Lo }); +//============================================================================== +/** @class Backbone collection for + * @borrows LoggableMixin#logger as #logger + * @borrows LoggableMixin#log as #log + * @constructs + */ +var HDADCECollection = DCECollection.extend( +/** @lends DatasetCollectionElementCollection.prototype */{ + model: HDADCE, + + /** String representation. */ + toString : function(){ + return ([ 'HDADCECollection(', this.length, ')' ].join( '' )); + } +}); + + +//============================================================================== +/** @class Backbone collection for + * @borrows LoggableMixin#logger as #logger + * @borrows LoggableMixin#log as #log + * @constructs + */ +var DCDCECollection = DCECollection.extend( +/** @lends DatasetCollectionElementCollection.prototype */{ + model: DCDCE, + + /** String representation. */ + toString : function(){ + return ([ 'DCDCECollection(', this.length, ')' ].join( '' )); + } +}); + + //============================================================================== /** @class Backbone model for Dataset Collections. * DCs contain a bbone collection named 'elements' using the class found in @@ -133,7 +228,7 @@ var DatasetCollection = Backbone.Model.extend( BASE_MVC.LoggableMixin ).extend( collection_type : 'list' }, - collectionClass : DatasetCollectionElementCollection, + collectionClass : DCECollection, /** */ initialize : function( model, options ){ @@ -159,11 +254,25 @@ var DatasetCollection = Backbone.Model.extend( BASE_MVC.LoggableMixin ).extend( return this.elements; }, + toJSON : function(){ + var json = Backbone.Model.prototype.toJSON.call( this ); + if( this.elements ){ + json.elements = this.elements.toJSON(); + } + return json; + }, + hasDetails : function(){ //TODO: this is incorrect for (accidentally) empty collections + this.debug( 'hasDetails:', this.elements.length ); return this.elements.length !== 0; }, + getVisibleContents : function( filters ){ + //TODO: filters unused for now + return this.elements; + }, + // ........................................................................ misc /** String representation */ toString : function(){ @@ -173,38 +282,12 @@ var DatasetCollection = Backbone.Model.extend( BASE_MVC.LoggableMixin ).extend( }); -//============================================================================== -/** @class Backbone collection for a collection of collection collections collecting correctly. */ -var DatasetCollectionCollection = Backbone.Collection.extend( BASE_MVC.LoggableMixin ).extend({ - - model: DatasetCollection, - - ///** logger used to record this.log messages, commonly set to console */ - //// comment this out to suppress log output - //logger : console, - - /** Set up. - * @see Backbone.Collection#initialize - */ - initialize : function( models, options ){ - options = options || {}; - this.info( 'DatasetCollectionCollection.initialize:', models, options ); - //this._setUpListeners(); - }, - - /** String representation. */ - toString : function(){ - return ([ 'DatasetCollectionCollection(', this.get( 'name' ), ')' ].join( '' )); - } -}); - - -//NOTE: the following prototypes may not be necessary - but I wanted to specifiy -// them (for now) and allow for the possibility of unique functionality //============================================================================== var ListDatasetCollection = DatasetCollection.extend( /** @lends ListDatasetCollection.prototype */{ + collectionClass : HDADCECollection, + /** String representation. */ toString : function(){ return ([ 'ListDatasetCollection(', this.get( 'name' ), ')' ].join( '' )); @@ -213,7 +296,7 @@ var ListDatasetCollection = DatasetCollection.extend( //============================================================================== -var PairDatasetCollection = DatasetCollection.extend( +var PairDatasetCollection = ListDatasetCollection.extend( /** @lends ListDatasetCollection.prototype */{ /** String representation. */ @@ -227,6 +310,8 @@ var PairDatasetCollection = DatasetCollection.extend( var ListPairedDatasetCollection = DatasetCollection.extend( /** @lends ListDatasetCollection.prototype */{ + collectionClass : DCDCECollection, + // list:paired is the only collection that itself contains collections //collectionClass : DatasetCollectionCollection, @@ -239,10 +324,7 @@ var ListPairedDatasetCollection = DatasetCollection.extend( //============================================================================== return { - DatasetCollectionElement : DatasetCollectionElement, - DatasetCollectionElementCollection : DatasetCollectionElementCollection, - DatasetCollection : DatasetCollection, - DatasetCollectionCollection : DatasetCollectionCollection, + //DatasetCollection : DatasetCollection, ListDatasetCollection : ListDatasetCollection, PairDatasetCollection : PairDatasetCollection, ListPairedDatasetCollection : ListPairedDatasetCollection diff --git a/static/scripts/mvc/collection/collection-panel.js b/static/scripts/mvc/collection/collection-panel.js index 153ef5a576f..36837e625bb 100644 --- a/static/scripts/mvc/collection/collection-panel.js +++ b/static/scripts/mvc/collection/collection-panel.js @@ -1,13 +1,13 @@ define([ "mvc/collection/dataset-collection-base", - "mvc/dataset/hda-base", "mvc/base-mvc", "utils/localization" -], function( DC_BASE, HDA_BASE, BASE_MVC, _l ){ +], function( DC_BASE, BASE_MVC, _l ){ /* ============================================================================= TODO: ============================================================================= */ +// ============================================================================= /** @class non-editable, read-only View/Controller for a dataset collection. * @name CollectionPanel * @@ -18,17 +18,20 @@ TODO: */ var CollectionPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend( /** @lends CollectionPanel.prototype */{ + //MODEL is either a DatasetCollection (or subclass) or a DatasetCollectionElement (list of pairs) /** logger used to record this.log messages, commonly set to console */ // comment this out to suppress log output //logger : console, tagName : 'div', - className : 'history-panel', + className : 'dataset-collection-panel', /** (in ms) that jquery effects will use */ fxSpeed : 'fast', + DCEViewClass : DC_BASE.DCEBaseView, + // ......................................................................... SET UP /** Set up the view, set up storage, bind listeners to HistoryContents events * @param {Object} attributes optional settings for the panel @@ -42,7 +45,10 @@ var CollectionPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend( this.log( this + '.initialize:', attributes ); this.hasUser = attributes.hasUser; - this.HDAViewClass = attributes.HDAViewClass || HDA_BASE.HDABaseView; + this.panelStack = []; + this.parentName = attributes.parentName; + + window.collectionPanel = this; }, /** create any event listeners for the panel @@ -74,7 +80,7 @@ var CollectionPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend( this.log( 'render:', speed, callback ); // send a speed of 0 to have no fade in/out performed speed = ( speed === undefined )?( this.fxSpeed ):( speed ); - //console.debug( this + '.render, fxSpeed:', speed ); + //this.debug( this + '.render, fxSpeed:', speed ); var panel = this, $newRender; @@ -123,7 +129,13 @@ var CollectionPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend( */ renderModel : function( ){ // tmp div for final swap in render - var $newRender = $( '
' ).append( CollectionPanel.templates.panel( this.model.toJSON() ) ); +//TODO: ugh - reuse issue - refactor out + var type = this.model.get( 'collection_type' ) || this.model.object.get( 'collection_type' ), + json = _.extend( this.model.toJSON(), { + parentName : this.parentName, + type : type + }), + $newRender = $( '
' ).append( this.templates.panel( json ) ); this._setUpBehaviours( $newRender ); this.renderContents( $newRender ); return $newRender; @@ -154,13 +166,15 @@ var CollectionPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend( * @returns the number of visible hda views */ renderContents : function( $whereTo ){ - //console.debug( 'renderContents, elements:', this.model.elements ); + //this.debug( 'renderContents, elements:', this.model.elements ); $whereTo = $whereTo || this.$el; + this.warn( this + '.renderContents:, model:', this.model ); var panel = this, contentViews = {}, - visibleContents = this.model.elements || []; - //this.log( 'renderContents, visibleContents:', visibleContents, $whereTo ); + //NOTE: no filtering here + visibleContents = this.model.getVisibleContents(); + this.log( 'renderContents, visibleContents:', visibleContents, $whereTo ); this.$datasetsList( $whereTo ).empty(); if( visibleContents && visibleContents.length ){ @@ -168,66 +182,92 @@ var CollectionPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend( var contentId = content.id, contentView = panel._createContentView( content ); contentViews[ contentId ] = contentView; - panel.attachContentView( contentView.render(), $whereTo ); + panel._attachContentView( contentView.render(), $whereTo ); }); } this.contentViews = contentViews; return this.contentViews; }, - /** - * @param {HistoryDatasetAssociation} content - */ + /** */ _createContentView : function( content ){ - //console.debug( 'content json:', JSON.stringify( content, null, ' ' ) ); + //this.debug( 'content json:', JSON.stringify( content, null, ' ' ) ); var contentView = null, ContentClass = this._getContentClass( content ); - //console.debug( 'content.object json:', JSON.stringify( content.object, null, ' ' ) ); - //console.debug( 'ContentClass:', ContentClass ); - //console.debug( 'content:', content ); - //console.debug( 'content.object:', content.object ); + //this.debug( 'content.object json:', JSON.stringify( content.object, null, ' ' ) ); + this.debug( 'ContentClass:', ContentClass ); + //this.debug( 'content:', content ); + this.debug( 'content.object:', content.object ); contentView = new ContentClass({ - model : content.object, + model : content, linkTarget : this.linkTarget, //draggable : true, hasUser : this.hasUser, logger : this.logger }); - //this._setUpHdaListeners( contentView ); + this.debug( 'contentView:', contentView ); + this._setUpContentListeners( contentView ); return contentView; }, + /** */ _getContentClass : function( content ){ + this.debug( this + '._getContentClass:', content ); switch( content.get( 'element_type' ) ){ case 'hda': - return this.HDAViewClass; + return this.DCEViewClass; case 'dataset_collection': - return DC_BASE.NestedDCEBaseView; + return this.DCEViewClass; } throw new TypeError( 'Unknown element type:', content.get( 'element_type' ) ); }, -// /** 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( 'body-expanded', function( model ){ -// panel.storage.addExpandedHda( model ); -// }); -// hdaView.on( 'body-collapsed', function( id ){ -// panel.storage.removeExpandedHda( id ); -// }); -// return this; -// }, + /** Set up listeners for content view events. In this override, handle collection expansion. */ + _setUpContentListeners : function( contentView ){ + var panel = this; + if( contentView.model.get( 'element_type' ) === 'dataset_collection' ){ + contentView.on( 'expanded', function( collectionView ){ + panel.info( 'expanded', collectionView ); + panel._addCollectionPanel( collectionView ); + }); + } + }, + + /** */ + _addCollectionPanel : function( collectionView ){ + var currPanel = this, + collectionModel = collectionView.model; + + 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' ) + }); + currPanel.panelStack.push( panel ); + + currPanel.$( '.controls' ).add( '.datasets-list' ).hide(); + currPanel.$el.append( panel.$el ); + panel.on( 'close', function(){ + currPanel.render(); + collectionView.collapse(); + currPanel.panelStack.pop(); + }); + + //TODO: to hdca-model, hasDetails + if( !panel.model.hasDetails() ){ + var xhr = panel.model.fetch(); + xhr.done( function(){ + //TODO: (re-)render collection contents + panel.render(); + }); + } else { + panel.render(); + } + }, /** attach an contentView to the panel */ - attachContentView : function( contentView, $whereTo ){ + _attachContentView : function( contentView, $whereTo ){ $whereTo = $whereTo || this.$el; var $datasetsList = this.$datasetsList( $whereTo ); $datasetsList.append( contentView.$el ); @@ -237,90 +277,102 @@ var CollectionPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend( // ------------------------------------------------------------------------ panel events /** event map */ events : { - 'click .panel-navigation-back' : 'close' + 'click .navigation .back' : 'close' }, /** */ close : function( event ){ this.$el.remove(); - this.trigger( 'collection-close' ); + this.trigger( 'close' ); }, // ........................................................................ misc - /** Return a string rep of the history */ + /** string rep */ toString : function(){ return 'CollectionPanel(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')'; } }); +//----------------------------------------------------------------------------- TEMPLATES +/** underscore templates */ +CollectionPanel.templates = CollectionPanel.prototype.templates = (function(){ +// use closure to run underscore template fn only once at module load + var _panelTemplate = _.template([ + '
', + '', -//------------------------------------------------------------------------------ TEMPLATES -var _panelTemplate = [ - '
', - '
', - '', _l( 'Back' ), '', + '
', + '
<%- collection.name || collection.element_identifier %>
', + '
', +//TODO: remove logic from template + '<% if( collection.type === "list" ){ %>', + _l( 'a list of datasets' ), + '<% } else if( collection.type === "paired" ){ %>', + _l( 'a pair of datasets' ), + '<% } else if( collection.type === "list:paired" ){ %>', + _l( 'a list of paired datasets' ), + '<% } %>', + '
', + '
', '
', + // where the datasets/hdas are added + '
' + ].join( '' )); - '
', - '<% if( collection.name ){ %>', - '
<%= collection.hid %> : <%= collection.name %>
', - '<% } %>', - '
', + // we override here in order to pass the localizer (_L) into the template scope - since we use it as a fn within + return { + panel : function( json ){ + return _panelTemplate({ _l: _l, collection: json }); + } + }; +}()); - //'
', - // '<% 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 - '
' - -].join( '' ); - -CollectionPanel.templates = { - panel : function( JSON ){ - return _.template( _panelTemplate, JSON, { variable: 'collection' }); +// ============================================================================= +/** @class non-editable, read-only View/Controller for a dataset collection. */ +var ListCollectionPanel = CollectionPanel.extend({ + DCEViewClass : DC_BASE.HDADCEBaseView, + // ........................................................................ misc + /** string rep */ + toString : function(){ + return 'ListCollectionPanel(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')'; } -}; +}); + + +// ============================================================================= +/** @class non-editable, read-only View/Controller for a dataset collection. */ +var PairCollectionPanel = ListCollectionPanel.extend({ + // ........................................................................ misc + /** string rep */ + toString : function(){ + return 'PairCollectionPanel(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')'; + } +}); + + +// ============================================================================= +/** @class non-editable, read-only View/Controller for a dataset collection. */ +var ListOfPairsCollectionPanel = CollectionPanel.extend({ + DCEViewClass : DC_BASE.DCDCEBaseView, + // ........................................................................ misc + /** string rep */ + toString : function(){ + return 'ListOfPairsCollectionPanel(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')'; + } +}); //============================================================================== return { - CollectionPanel: CollectionPanel + CollectionPanel : CollectionPanel, + ListCollectionPanel : ListCollectionPanel, + PairCollectionPanel : PairCollectionPanel, + ListOfPairsCollectionPanel : ListOfPairsCollectionPanel }; }); diff --git a/static/scripts/mvc/collection/dataset-collection-base.js b/static/scripts/mvc/collection/dataset-collection-base.js index ab0f1f27e12..4914c9cc72f 100644 --- a/static/scripts/mvc/collection/dataset-collection-base.js +++ b/static/scripts/mvc/collection/dataset-collection-base.js @@ -29,7 +29,82 @@ var DCBaseView = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend({ this.log( 'DCBaseView.initialize:', attributes ); }, -//TODO: render has been removed from the inheritance chain here, so this won't work when called as is + // ........................................................................ render main + /** Render this content, set up ui. + * @param {Boolean} fade whether or not to fade out/in when re-rendering + * @fires rendered when rendered + * @fires rendered:ready when first rendered and NO running HDAs + * @returns {Object} this HDABaseView + */ + render : function( fade ){ + var $newRender = this._buildNewRender(); + this._queueNewRender( $newRender, fade ); + return this; + }, + + _buildNewRender : function(){ + // create a new render using a skeleton template, render title buttons, render body, and set up events, etc. + var $newRender = $( this.templates.skeleton( this.model.toJSON() ) ); + $newRender.find( '.primary-actions' ).append( this._render_primaryActions() ); + this._setUpBehaviors( $newRender ); + //this._renderSelectable( $newRender ); + return $newRender; + }, + + /** Fade out the old el, replace with new dom, then fade in. + * @param {Boolean} fade whether or not to fade out/in when re-rendering + * @fires rendered when rendered + * @fires rendered:ready when first rendered and NO running HDAs + */ + _queueNewRender : function( $newRender, fade ) { + fade = ( fade === undefined )?( true ):( fade ); + var view = this; + + // fade the old render out (if desired) + if( fade ){ + $( view ).queue( function( next ){ this.$el.fadeOut( view.fxSpeed, next ); }); + } + // empty the old render, swap in the new render contents + $( view ).queue( function( next ){ +//TODO:?? change to replaceWith pattern? + this.$el.empty().attr( 'class', view.className ).append( $newRender.children() ); + next(); + }); + // fade the new in + if( fade ){ + $( view ).queue( function( next ){ this.$el.fadeIn( view.fxSpeed, next ); }); + } + // trigger an event to know we're ready + $( view ).queue( function( next ){ + this.trigger( 'rendered', view ); + next(); + }); + }, + + /** set up js behaviors, event handlers for elements within the given container + * @param {jQuery} $container jq object that contains the elements to process (defaults to this.$el) + */ + _setUpBehaviors : function( $container ){ + $container = $container || this.$el; + make_popup_menus( $container ); + $container.find( '[title]' ).tooltip({ placement : 'bottom' }); + }, + + // ........................................................................ titlebar buttons + /** Render icon-button group for the common, most easily accessed actions. + * @returns {jQuery} rendered DOM or null + */ + _render_primaryActions : function(){ + // override + return []; + }, + + // ......................................................................... misc + events : { + 'click .title-bar' : function( event ){ + this.trigger( 'expanded', this ); + } + }, // ......................................................................... misc /** String representation */ @@ -40,37 +115,23 @@ var DCBaseView = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend({ }); /** templates for DCBaseViews (skeleton and body) */ -DCBaseView.templates = (function(){ +DCBaseView.templates = DCBaseView.prototype.templates = (function(){ // use closure to run underscore template fn only once at module load var skeletonTemplate = _.template([ - '
', - '
', - '<% if ( collection.deleted ) { %>', - '
', - _l( 'This collection has been deleted.' ), - '
', - '<% } %>', - '<% if ( !collection.visible ) { %>', - '
', - _l( 'This collection has been hidden.' ), - '
', - '<% } %>', - '
', - '
', - '
', - '', - '
', - '<%- collection.name %>', + '
', + '
', + '
', + '
', + '<%- collection.element_identifier %>', '
', '
', - '
', + '
', '
' ].join( '' )); var bodyTemplate = _.template([ - '
', - '
', - _l( 'A dataset collection.' ), + '
', + '
', _l( 'A dataset collection.' ), '
', '
' ].join( '' )); @@ -86,66 +147,312 @@ DCBaseView.templates = (function(){ }()); -//TODO: unused -////============================================================================== -///** @class Read only view for DatasetCollectionElement. -// * @name DCEBaseView -// * -// * @augments Backbone.View -// * @borrows LoggableMixin#logger as #logger -// * @borrows LoggableMixin#log as #log -// * @constructs -// */ -//var NestedDCBaseView = DCBaseView.extend({ -// -// logger : console, -// -// /** */ -// initialize : function( attributes ){ -// if( attributes.logger ){ this.logger = this.model.logger = attributes.logger; } -// this.warn( this + '.initialize:', attributes ); -// DCBaseView.prototype.initialize.call( this, attributes ); -// }, -// -// _template : function(){ -// this.debug( this.model ); -// this.debug( this.model.toJSON() ); -// return NestedDCBaseView.templates.skeleton( this.model.toJSON() ); -// }, -// -// // ......................................................................... misc -// /** String representation */ -// toString : function(){ -// var modelString = ( this.model )?( this.model + '' ):( '(no model)' ); -// return 'NestedDCBaseView(' + modelString + ')'; -// } -//}); -// -////------------------------------------------------------------------------------ TEMPLATES -////TODO: possibly break these out into a sep. module -//NestedDCBaseView.templates = (function(){ -// var skeleton = _.template([ -// '
', -// '
', -// '
', -// '
', -// '<%= collection.name %>', -// '
', -// '
', -// '
' -// ].join( '' )); -// // we override here in order to pass the localizer (_L) into the template scope - since we use it as a fn within -// return { -// skeleton : function( json ){ -// return skeleton({ _l: _l, collection: json }); -// } -// }; -//}()); +//============================================================================== +/** @class Read only view for DatasetCollectionElement. + * @name DCBaseView + * + * @augments Backbone.View + * @borrows LoggableMixin#logger as #logger + * @borrows LoggableMixin#log as #log + * @constructs + */ +var DCEBaseView = BASE_MVC.ExpandableView.extend({ + + /** logger used to record this.log messages, commonly set to console */ + // comment this out to suppress log output + //logger : console, + + /** */ + className : "dataset-collection-element collection-dataset dataset", + /** */ + fxSpeed : 'fast', + + /** */ + initialize : function( attributes ){ + if( attributes.logger ){ this.logger = this.model.logger = attributes.logger; } + this.log( 'DCEBaseView.initialize:', attributes ); + BASE_MVC.ExpandableView.prototype.initialize.call( this, attributes ); + }, + + // ......................................................................... renderers + /** Render the enclosing div of the hda body and, if expanded, the html in the body + * @returns {jQuery} rendered DOM + */ + _renderDetails : function(){ + var $details = $( this.templates.details( this.model.toJSON() ) ); + this._setUpBehaviors( $details ); + // only render the body html if it's being shown + if( this.expanded ){ + $details.show(); + } + return $details; + }, + + // ......................................................................... events + events : { + // expand the body when the title is clicked or when in focus and space or enter is pressed + 'click .title-bar' : '_clickTitleBar', + 'keydown .title-bar' : '_keyDownTitleBar' + }, + + _clickTitleBar : function( event ){ + event.stopPropagation(); + this.toggleExpanded(); + }, + + _keyDownTitleBar : function( event ){ + // bail (with propagation) if keydown and not space or enter + var KEYCODE_SPACE = 32, KEYCODE_RETURN = 13; + if( event && ( event.type === 'keydown' ) + &&( event.keyCode === KEYCODE_SPACE || event.keyCode === KEYCODE_RETURN ) ){ + this.toggleExpanded(); + event.stopPropagation(); + return false; + } + return true; + }, + + // ......................................................................... misc + /** String representation */ + toString : function(){ + var modelString = ( this.model )?( this.model + '' ):( '(no model)' ); + return 'DCEBaseView(' + modelString + ')'; + } +}); + +/** templates for DCBaseViews (skeleton and body) */ +DCEBaseView.templates = DCEBaseView.prototype.templates = (function(){ +// use closure to run underscore template fn only once at module load + var skeletonTemplate = _.template([ + '
', + '
', + '
', + '', + '
', + '<%- collection.element_identifier %>', + '
', + '
', + '
', + '
' + ].join( '' )); + + var bodyTemplate = _.template([ + '
', + '
', + _l( 'A dataset collection element.' ), + '
', + '
' + ].join( '' )); + + // we override here in order to pass the localizer (_L) into the template scope - since we use it as a fn within + return { + skeleton : function( collectionJSON ){ + return skeletonTemplate({ _l: _l, collection: collectionJSON }); + }, + body : function( collectionJSON ){ + return bodyTemplate({ _l: _l, collection: collectionJSON }); + } + }; +}()); + + +//============================================================================== +/** @class Read only view for DatasetCollectionElement. + * @name DCBaseView + * + * @augments Backbone.View + * @borrows LoggableMixin#logger as #logger + * @borrows LoggableMixin#log as #log + * @constructs + */ +var HDADCEBaseView = DCEBaseView.extend({ + + /** logger used to record this.log messages, commonly set to console */ + // comment this out to suppress log output + //logger : console, + + // ......................................................................... misc + /** String representation */ + toString : function(){ + var modelString = ( this.model )?( this.model + '' ):( '(no model)' ); + return 'HDADCEBaseView(' + modelString + ')'; + } +}); + +/** templates for DCBaseViews (skeleton and body) */ +HDADCEBaseView.templates = HDADCEBaseView.prototype.templates = (function(){ +// use closure to run underscore template fn only once at module load + var skeletonTemplate = _.template([ + '
', + '
', + '
', + '', + '
', +//TODO:?? re-check this: in pairs the name and identifier are different - but not otherwise + '<%- element.element_identifier %>', + '
', +// '<% if( element.element_identifier !== hda.name ){ %>', +// '
<%- element.element_identifier %>
', +// '<% } %>', + '
', + '
', + '
' + ].join( '' )); + + var detailsTemplate = _.template([ + '
', + '
', + '<% if( hda.misc_blurb ){ %>', + '
', + '<%- hda.misc_blurb %>', + '
', + '<% } %>', + + '<% if( hda.data_type ){ %>', + '
', + '', + '<%- hda.data_type %>', + '
', + '<% } %>', + + '<% if( hda.metadata_dbkey ){ %>', + '
', + '', + '', + '<%- hda.metadata_dbkey %>', + '', + '
', + '<% } %>', + + '<% if( hda.misc_info ){ %>', + '
', + '<%- hda.misc_info %>', + '
', + '<% } %>', + '
', + // end dataset-summary + + '
', + '
', + '
', + '
', + + '<% if( !hda.deleted ){ %>', + '
', + '
', + + '
', + //TODO: the following two should be compacted + '<% _.each( hda.display_apps, function( app ){ %>', + '
', + '<%- app.label %> ', + '', + '<% _.each( app.links, function( link ){ %>', + '', + '<% print( _l( link.text ) ); %>', + ' ', + '<% }); %>', + '', + '
', + '<% }); %>', + + '<% _.each( hda.display_types, function( app ){ %>', + '
', + '<%- app.label %> ', + '', + '<% _.each( app.links, function( link ){ %>', + '', + '<% print( _l( link.text ) ); %>', + ' ', + '<% }); %>', + '', + '
', + '<% }); %>', + '
', + + '<% if( hda.peek ){ %>', + '
<%= hda.peek %>
', + '<% } %>', + + '<% } %>', + // end if !deleted + + '
' + ].join( '' )); + + // we override here in order to pass the localizer (_L) into the template scope - since we use it as a fn within + return { + skeleton : function( json ){ + return skeletonTemplate({ _l: _l, element: json, hda: json.object }); + }, + details : function( json ){ + return detailsTemplate({ _l: _l, element: json, hda: json.object }); + } + }; +}()); + + +//============================================================================== +/** @class Read only view for DatasetCollectionElement. + * @name DCBaseView + * + * @augments Backbone.View + * @borrows LoggableMixin#logger as #logger + * @borrows LoggableMixin#log as #log + * @constructs + */ +var DCDCEBaseView = DCEBaseView.extend({ + + /** logger used to record this.log messages, commonly set to console */ + // comment this out to suppress log output + //logger : console, + + // ......................................................................... misc + /** String representation */ + expand : function(){ + this.trigger( 'expanded', this ); + }, + + // ......................................................................... misc + /** String representation */ + toString : function(){ + var modelString = ( this.model )?( this.model + '' ):( '(no model)' ); + return 'DCDCEBaseView(' + modelString + ')'; + } +}); + +/** templates for DCBaseViews (skeleton and body) */ +DCDCEBaseView.templates = DCDCEBaseView.prototype.templates = (function(){ +// use closure to run underscore template fn only once at module load + var skeletonTemplate = _.template([ + '
', + '
', + '
', + '', + '
', + '<%- element.element_identifier %>', + '
', +//TODO: currently correct, but needs logic if more nested types are added + '
', _l( 'paired datasets' ), '
', + '
', + '
', + '
' + ].join( '' )); + + // we override here in order to pass the localizer (_L) into the template scope - since we use it as a fn within + return { + skeleton : function( json ){ + return skeletonTemplate({ _l: _l, element: json, collection: json.object }); + } + }; +}()); //============================================================================== return { DCBaseView : DCBaseView, - //NestedDCBaseView : NestedDCBaseView, + DCEBaseView : DCEBaseView, + HDADCEBaseView : HDADCEBaseView, + DCDCEBaseView : DCDCEBaseView }; }); diff --git a/static/scripts/mvc/collection/hdca-base.js b/static/scripts/mvc/collection/hdca-base.js index f44369eef31..f3ec68e5046 100644 --- a/static/scripts/mvc/collection/hdca-base.js +++ b/static/scripts/mvc/collection/hdca-base.js @@ -22,8 +22,9 @@ var HDCABaseView = _super.extend( BASE_MVC.mixin( HCVMixin, { // comment this out to suppress log output //logger : console, +//TODO: not a dataset /** */ - className : "dataset hda history-panel-hda", + className : "dataset hdca history-panel-hda", /** */ initialize : function( attributes ){ @@ -52,6 +53,26 @@ var HDCABaseView = _super.extend( BASE_MVC.mixin( HCVMixin, { return $body; }, + /** In this override, do not slide down or render any body/details - allow the container to handle it + * @fires expanded when a body has been expanded + */ + expand : function(){ + this.warn( this + '.expand' ); + var contentView = this; + + // fetch first if no details in the model + if( this.model.inReadyState() && !this.model.hasDetails() ){ + // we need the change event on HDCA's for the elements to be processed - so silent == false + this.model.fetch().always( function( model ){ + contentView.expanded = true; + contentView.trigger( 'expanded', contentView ); + }); + } else { + contentView.expanded = true; + contentView.trigger( 'expanded', contentView ); + } + }, + // ......................................................................... misc /** String representation */ toString : function(){ @@ -64,7 +85,8 @@ var HDCABaseView = _super.extend( BASE_MVC.mixin( HCVMixin, { HDCABaseView.templates = HDCABaseView.prototype.templates = (function(){ // use closure to run underscore template fn only once at module load var skeletonTemplate = _.template([ - '
', +//TODO: not a dataset + '
', '
', '<% if ( collection.deleted ) { %>', '
', @@ -77,22 +99,32 @@ HDCABaseView.templates = HDCABaseView.prototype.templates = (function(){ '
', '<% } %>', '
', - '
', - '
', - '
', - '', - '
', - '<%- collection.hid %> ', - '<%- collection.name %>', + '
', + '
', + '
', + '', + '
', + '<%- collection.hid %> ', + '<%- collection.name %>', + '
', + '
', +//TODO: remove from template logic + '<% if( collection.collection_type === "list" ){ %>', + _l( 'a list of datasets' ), + '<% } else if( collection.collection_type === "paired" ){ %>', + _l( 'a pair of datasets' ), + '<% } else if( collection.collection_type === "list:paired" ){ %>', + _l( 'a list of paired datasets' ), + '<% } %>', '
', '
', - '
', + '
', '
' ].join( '' )); var bodyTemplate = _.template([ - '
', - '
', + '
', + '
', _l( 'A dataset collection.' ), '
' ].join( '' )); diff --git a/static/scripts/mvc/collection/hdca-edit.js b/static/scripts/mvc/collection/hdca-edit.js index e36c2e3594b..0a76c166de5 100644 --- a/static/scripts/mvc/collection/hdca-edit.js +++ b/static/scripts/mvc/collection/hdca-edit.js @@ -23,13 +23,13 @@ var HDCAEditView = _super.extend({ // ......................................................................... edit attr, delete /** Render icon-button group for the common, most easily accessed actions. - * Overrides _render_titleButtons to include editing related buttons. + * Overrides _render_primaryActions to include editing related buttons. * @returns {jQuery} rendered DOM */ - _render_titleButtons : function(){ - this.log( this + '._render_titleButtons' ); + _render_primaryActions : function(){ + this.log( this + '._render_primaryActions' ); // render the display, edit attr and delete icon-buttons - return _super.prototype._render_titleButtons.call( this ) + return _super.prototype._render_primaryActions.call( this ) .concat([ this._render_deleteButton() ]); diff --git a/static/scripts/mvc/collection/hdca-model.js b/static/scripts/mvc/collection/hdca-model.js index 6b3145c26a3..be217f21b93 100644 --- a/static/scripts/mvc/collection/hdca-model.js +++ b/static/scripts/mvc/collection/hdca-model.js @@ -5,20 +5,15 @@ define([ ], function( HISTORY_CONTENT, DC_MODEL, _l ){ //============================================================================== var hcontentMixin = HISTORY_CONTENT.HistoryContentMixin, -/** @class Backbone model for (generic) Dataset Collection within a History. - * @constructs - */ - HistoryDatasetCollection = DC_MODEL.DatasetCollection.extend( hcontentMixin ); + ListDC = DC_MODEL.ListDatasetCollection, + PairDC = DC_MODEL.PairDatasetCollection, + ListPairedDC = DC_MODEL.ListPairedDatasetCollection; - -//NOTE: the following prototypes may not be necessary - but I wanted to specifiy -// them (for now) and allow for the possibility of unique functionality //============================================================================== -var ListDC = DC_MODEL.ListDatasetCollection, /** @class Backbone model for List Dataset Collection within a History. * @constructs */ - HistoryListDatasetCollection = ListDC.extend( hcontentMixin ).extend( +var HistoryListDatasetCollection = ListDC.extend( hcontentMixin ).extend( /** @lends HistoryListDatasetCollection.prototype */{ initialize : function( model, options ){ @@ -36,11 +31,10 @@ var ListDC = DC_MODEL.ListDatasetCollection, //============================================================================== -var PairDC = DC_MODEL.PairDatasetCollection, /** @class Backbone model for Pair Dataset Collection within a History. * @constructs */ - HistoryPairDatasetCollection = PairDC.extend( hcontentMixin ).extend( +var HistoryPairDatasetCollection = PairDC.extend( hcontentMixin ).extend( /** @lends HistoryPairDatasetCollection.prototype */{ initialize : function( model, options ){ @@ -58,11 +52,10 @@ var PairDC = DC_MODEL.PairDatasetCollection, //============================================================================== -var ListPairedDC = DC_MODEL.ListPairedDatasetCollection, /** @class Backbone model for List of Pairs Dataset Collection within a History. * @constructs */ - HistoryListPairedDatasetCollection = ListPairedDC.extend( hcontentMixin ).extend( +var HistoryListPairedDatasetCollection = ListPairedDC.extend( hcontentMixin ).extend( /** @lends HistoryListPairedDatasetCollection.prototype */{ initialize : function( model, options ){ @@ -81,7 +74,6 @@ var ListPairedDC = DC_MODEL.ListPairedDatasetCollection, //============================================================================== return { - HistoryDatasetCollection : HistoryDatasetCollection, HistoryListDatasetCollection : HistoryListDatasetCollection, HistoryPairDatasetCollection : HistoryPairDatasetCollection, HistoryListPairedDatasetCollection : HistoryListPairedDatasetCollection diff --git a/static/scripts/mvc/dataset/hda-base.js b/static/scripts/mvc/dataset/hda-base.js index 32d534d2edd..114ba129957 100644 --- a/static/scripts/mvc/dataset/hda-base.js +++ b/static/scripts/mvc/dataset/hda-base.js @@ -23,7 +23,7 @@ var HDABaseView = _super.extend( //logger : console, tagName : "div", - className : "dataset hda history-panel-hda", + className : "dataset hda history-content", id : function(){ return 'hda-' + this.model.get( 'id' ); }, fxSpeed : 'fast', @@ -96,7 +96,7 @@ var HDABaseView = _super.extend( /** In this override, render the dataset display button * @returns {jQuery} rendered DOM */ - _render_titleButtons : function(){ + _render_primaryActions : function(){ // render just the display for read-only return [ this._render_displayButton() ]; }, @@ -115,7 +115,7 @@ var HDABaseView = _super.extend( var displayBtnData = { target : this.linkTarget, - classes : 'dataset-display' + classes : 'display-btn' }; // show a disabled display if the data's been purged @@ -181,7 +181,7 @@ var HDABaseView = _super.extend( if( _.isEmpty( meta_files ) ){ return $([ '', + 'class="icon-btn download-btn">', '', '' ].join( '' ) ); @@ -206,7 +206,7 @@ var HDABaseView = _super.extend( '
', '', + 'class="icon-btn download-btn">', '', // join these w/o whitespace or there'll be a gap when rendered '', @@ -256,7 +256,7 @@ var HDABaseView = _super.extend( primaryButtonArray = primaryButtonArray || []; var view = this, $body = $( HDABaseView.templates.body( _.extend( this.model.toJSON(), { body: body }))); - $body.find( '.dataset-actions .left' ).append( + $body.find( '.actions .left' ).append( _.map( primaryButtonArray, function( renderingFn ){ return renderingFn.call( view ); }) @@ -358,7 +358,7 @@ var HDABaseView = _super.extend( $body = $( HDABaseView.templates.body( this.model.toJSON() ) ), // prepend the download btn to the defaults and render btnRenderers = [ this._render_downloadButton ].concat( this.defaultPrimaryActionButtonRenderers ); - $body.find( '.dataset-actions .left' ).append( + $body.find( '.actions .left' ).append( _.map( btnRenderers, function( renderingFn ){ return renderingFn.call( view ); })); @@ -385,11 +385,11 @@ var HDABaseView = _super.extend( var hdaView = this; function _renderBodyAndExpand(){ - hdaView.$el.children( '.dataset-body' ).replaceWith( hdaView._renderBody() ); + hdaView.$el.children( '.details' ).replaceWith( hdaView._renderBody() ); //NOTE: needs to be set after the above or the slide will not show hdaView.expanded = true; - hdaView.$el.children( '.dataset-body' ).slideDown( hdaView.fxSpeed, function(){ - hdaView.trigger( 'expanded', hdaView.model ); + hdaView.$el.children( '.details' ).slideDown( hdaView.fxSpeed, function(){ + hdaView.trigger( 'expanded', hdaView ); }); } // fetch first if no details in the model @@ -429,24 +429,24 @@ var HDABaseView = _super.extend( //TODO: possibly break these out into a sep. module var skeletonTemplate = _.template([ '
', - '
', + '
', // error during index fetch - show error on dataset '<% if( hda.error ){ %>', '
', - _l( 'There was an error getting the data for this dataset' ), ':<%- hda.error %>', + _l( 'There was an error getting the data for this dataset' ), ': <%- hda.error %>', '
', '<% } %>', '<% if( hda.deleted ){ %>', // purged and deleted '<% if( hda.purged ){ %>', - '
', + '
', _l( 'This dataset has been deleted and removed from disk' ) + '.', '
', // deleted not purged '<% } else { %>', - '
', + '
', _l( 'This dataset has been deleted' ) + '.', '
', '<% } %>', @@ -454,61 +454,61 @@ var skeletonTemplate = _.template([ // hidden '<% if( !hda.visible ){ %>', - '
', + '
', _l( 'This dataset has been hidden' ) + '.', '
', '<% } %>', '
', // multi-select checkbox - '
', + '
', '', '
', // space for title bar buttons - '
', + '
', // adding a tabindex here allows focusing the title bar and the use of keydown to expand the dataset display - '
', - '', - '
', + '
', + '', + '
', //TODO: remove whitespace and use margin-right - '<%- hda.hid %> ', - '<%- hda.name %>', + '<%- hda.hid %> ', + '<%- hda.name %>', '
', '
', - '
', + '
', '
' ].join( '' )); var bodyTemplate = _.template([ -'
', +'
', '<% if( hda.body ){ %>', - '
', + '
', '<%= hda.body %>', '
', - '
', + '
', '
', '
', '
', '<% } else { %>', - '
', + '
', '<% if( hda.misc_blurb ){ %>', - '
', + '
', '<%- hda.misc_blurb %>', '
', '<% } %>', '<% if( hda.data_type ){ %>', - '
', + '
', '', '<%- hda.data_type %>', '
', '<% } %>', '<% if( hda.metadata_dbkey ){ %>', - '
', + '
', '', '', '<%- hda.metadata_dbkey %>', @@ -517,14 +517,14 @@ var bodyTemplate = _.template([ '<% } %>', '<% if( hda.misc_info ){ %>', - '
', + '
', '<%- hda.misc_info %>', '
', '<% } %>', '
', // end dataset-summary - '
', + '
', '
', '
', '
', @@ -533,7 +533,7 @@ var bodyTemplate = _.template([ '
', '
', - '
', + '
', //TODO: the following two should be compacted '<% _.each( hda.display_apps, function( app ){ %>', '
', diff --git a/static/scripts/mvc/dataset/hda-edit.js b/static/scripts/mvc/dataset/hda-edit.js index ad35a99d92c..15b9fe200f6 100644 --- a/static/scripts/mvc/dataset/hda-edit.js +++ b/static/scripts/mvc/dataset/hda-edit.js @@ -53,13 +53,13 @@ var HDAEditView = _super.extend( // ......................................................................... edit attr, delete /** Render icon-button group for the common, most easily accessed actions. - * Overrides _render_titleButtons to include edit and delete buttons. - * @see HDABaseView#_render_titleButtons + * Overrides _render_primaryActions to include edit and delete buttons. + * @see HDABaseView#_render_primaryActions * @returns {jQuery} rendered DOM */ - _render_titleButtons : function(){ + _render_primaryActions : function(){ // render the display, edit attr and delete icon-buttons - return _super.prototype._render_titleButtons.call( this ).concat([ + return _super.prototype._render_primaryActions.call( this ).concat([ this._render_editButton(), this._render_deleteButton() ]); @@ -85,7 +85,7 @@ var HDAEditView = _super.extend( title : _l( 'Edit attributes' ), href : this.urls.edit, target : this.linkTarget, - classes : 'dataset-edit' + classes : 'edit-btn' }; // disable if purged or deleted and explain why in the tooltip @@ -124,10 +124,10 @@ var HDAEditView = _super.extend( var self = this, deleteBtnData = { title : _l( 'Delete' ), - classes : 'dataset-delete', + classes : 'delete-btn', onclick : function() { // ...bler... tooltips being left behind in DOM (hover out never called on deletion) - self.$el.find( '.icon-btn.dataset-delete' ).trigger( 'mouseout' ); + self.$el.find( '.icon-btn.delete-btn' ).trigger( 'mouseout' ); self.model[ 'delete' ](); } }; @@ -152,7 +152,7 @@ var HDAEditView = _super.extend( return faIconButton({ title : _l( 'View or report this error' ), href : this.urls.report_error, - classes : 'dataset-report-error-btn', + classes : 'report-error-btn', target : this.linkTarget, faIcon : 'fa-bug' }); @@ -165,7 +165,7 @@ var HDAEditView = _super.extend( return faIconButton({ title : _l( 'Run this job again' ), href : this.urls.rerun, - classes : 'dataset-rerun-btn', + classes : 'rerun-btn', target : this.linkTarget, faIcon : 'fa-refresh' }); @@ -205,7 +205,7 @@ var HDAEditView = _super.extend( var $icon = faIconButton({ title : _l( 'Visualize' ), - classes : 'dataset-visualize-btn', + classes : 'visualize-btn', faIcon : 'fa-bar-chart-o' }); @@ -254,7 +254,7 @@ var HDAEditView = _super.extend( } var $icon = faIconButton({ title : _l( 'Visualize' ), - classes : 'dataset-visualize-btn', + classes : 'visualize-btn', faIcon : 'fa-bar-chart-o' }); @@ -298,18 +298,18 @@ var HDAEditView = _super.extend( return [ '', t, '' ].join( '' ); }; - $newRender.find( '.dataset-deleted-msg' ).append([ - br, link( _l( 'Undelete it' ), 'dataset-undelete' ), p + $newRender.find( '.deleted-msg' ).append([ + br, link( _l( 'Undelete it' ), 'undelete-link' ), p ].join( '' )); if( this.purgeAllowed ){ - $newRender.find( '.dataset-deleted-msg' ).append([ - br, link( _l( 'Permanently remove it from disk' ), 'dataset-purge' ), p + $newRender.find( '.deleted-msg' ).append([ + br, link( _l( 'Permanently remove it from disk' ), 'purge-link' ), p ].join( '' )); } - $newRender.find( '.dataset-hidden-msg' ).append([ - br, link( _l( 'Unhide it' ), 'dataset-unhide' ), p + $newRender.find( '.hidden-msg' ).append([ + br, link( _l( 'Unhide it' ), 'unhide-link' ), p ].join( '' )); return $newRender; @@ -336,7 +336,7 @@ var HDAEditView = _super.extend( */ _render_body_error : function(){ var $body = _super.prototype._render_body_error.call( this ); - $body.find( '.dataset-actions .left' ).prepend( this._render_errButton() ); + $body.find( '.actions .left' ).prepend( this._render_errButton() ); return $body; }, @@ -351,11 +351,11 @@ var HDAEditView = _super.extend( if( this.model.isDeletedOrPurged() ){ return $body; } - this.makeDbkeyEditLink( $body ); + this._makeDbkeyEditLink( $body ); // more actions/buttons if( this.hasUser ){ - $body.find( '.dataset-actions .left' ).append( this._render_visualizationsButton() ); + $body.find( '.actions .left' ).append( this._render_visualizationsButton() ); //TODO: might be better to move these into the render() and call setElement here this._renderTags( $body ); this._renderAnnotation( $body ); @@ -363,6 +363,7 @@ var HDAEditView = _super.extend( return $body; }, + /** */ _renderTags : function( $where ){ var view = this; this.tagsEditor = new TAGS.TagsEditor({ @@ -374,12 +375,14 @@ var HDAEditView = _super.extend( onhide : function(){ view.tagsEditorShown = false; }, $activator : faIconButton({ title : _l( 'Edit dataset tags' ), - classes : 'dataset-tag-btn', + classes : 'tag-btn', faIcon : 'fa-tags' - }).appendTo( $where.find( '.dataset-actions .right' ) ) + }).appendTo( $where.find( '.actions .right' ) ) }); if( this.tagsEditorShown ){ this.tagsEditor.toggle( true ); } }, + + /** */ _renderAnnotation : function( $where ){ var view = this; this.annotationEditor = new ANNOTATIONS.AnnotationEditor({ @@ -391,34 +394,35 @@ var HDAEditView = _super.extend( onhide : function(){ view.annotationEditorShown = false; }, $activator : faIconButton({ title : _l( 'Edit dataset annotation' ), - classes : 'dataset-annotate-btn', + classes : 'annotate-btn', faIcon : 'fa-comment' - }).appendTo( $where.find( '.dataset-actions .right' ) ) + }).appendTo( $where.find( '.actions .right' ) ) }); if( this.annotationEditorShown ){ this.annotationEditor.toggle( true ); } }, - makeDbkeyEditLink : function( $body ){ + /** */ + _makeDbkeyEditLink : function( $body ){ // make the dbkey a link to editing if( this.model.get( 'metadata_dbkey' ) === '?' && !this.model.isDeletedOrPurged() ){ var editableDbkey = $( '?' ) .attr( 'href', this.urls.edit ) .attr( 'target', this.linkTarget ); - $body.find( '.dataset-dbkey .value' ).replaceWith( editableDbkey ); + $body.find( '.dbkey .value' ).replaceWith( editableDbkey ); } }, // ......................................................................... events /** event map */ events : _.extend( _.clone( _super.prototype.events ), { - 'click .dataset-undelete' : function( ev ){ this.model.undelete(); return false; }, - 'click .dataset-unhide' : function( ev ){ this.model.unhide(); return false; }, - 'click .dataset-purge' : 'confirmPurge' + 'click .undelete-link' : function( ev ){ this.model.undelete(); return false; }, + 'click .unhide-link' : function( ev ){ this.model.unhide(); return false; }, + 'click .purge-link' : '_confirmPurge' }), /** listener for item purge */ - confirmPurge : function _confirmPurge( ev ){ + _confirmPurge : function _confirmPurge( ev ){ //TODO: confirm dialog this.model.purge(); return false; @@ -444,7 +448,7 @@ var HDAEditView = _super.extend( //TODO: should be imported from trackster.js //TODO: This function is redundant and also exists in data.js // create action - function create_trackster_action_fn (vis_url, dataset_params, dbkey) { + function create_trackster_action_fn(vis_url, dataset_params, dbkey) { return function() { var listTracksParams = {}; if (dbkey){ diff --git a/static/scripts/mvc/history/current-history-panel.js b/static/scripts/mvc/history/current-history-panel.js index 818d33b53b1..fc80ce70e2a 100644 --- a/static/scripts/mvc/history/current-history-panel.js +++ b/static/scripts/mvc/history/current-history-panel.js @@ -34,7 +34,7 @@ TODO: var _super = HISTORY_PANEL.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). + * panel (current right hand panel) of the analysis page. * @name HistoryPanel * * @augments Backbone.View @@ -43,15 +43,12 @@ var _super = HISTORY_PANEL.HistoryPanel; * @constructs */ var CurrentHistoryPanel = _super.extend( -/** @lends HistoryPanel.prototype */{ +/** @lends CurrentHistoryPanel.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_EDIT.HDAEditView, - emptyMsg : _l( "This history is empty. Click 'Get Data' on the left tool menu to start" ), noneFoundMsg : _l( "No matching datasets found" ), @@ -87,7 +84,7 @@ var CurrentHistoryPanel = _super.extend( /** loads a history & hdas w/ details and makes them the current history */ switchToHistory : function( historyId, attributes ){ - //console.info( 'switchToHistory:', historyId, attributes ); + //this.info( 'switchToHistory:', historyId, attributes ); var panel = this, historyFn = function(){ // make this current and get history data with one call @@ -139,7 +136,7 @@ var CurrentHistoryPanel = _super.extend( // update the quota meter when current history changes size if( Galaxy && Galaxy.quotaMeter ){ this.listenTo( this.model, 'change:nice_size', function(){ - //console.info( '!! model size changed:', this.model.get( 'nice_size' ) ) + //this.info( '!! model size changed:', this.model.get( 'nice_size' ) ) //TODO: global Galaxy.quotaMeter.update(); }); @@ -243,7 +240,7 @@ var CurrentHistoryPanel = _super.extend( $toolMenu.find( 'span:contains("Get Data")' ) .click(); //.fadeTo( 200, 0.1, function(){ - // console.debug( this ) + // this.debug( this ) // $( this ).fadeTo( 200, 1.0 ); //}); }); @@ -302,36 +299,43 @@ var CurrentHistoryPanel = _super.extend( _setUpHdaListeners : function( hdaView ){ _super.prototype._setUpHdaListeners.call( this, hdaView ); - //var historyView = this; - //hdaView.on( 'expanded', function( event, collectionView ){ - // //console.info( 'collection-expanded', event, collectionView ); - // historyView._addCollectionPanel( collectionView.model ); - //}); + var historyView = this; + if( hdaView instanceof historyView.HDCAViewClass ){ + hdaView.off( 'expanded' ); + hdaView.on( 'expanded', function( collectionView ){ + this.info( 'expanded', collectionView ); + historyView._addCollectionPanel( collectionView ); + }); + hdaView.off( 'collapsed' ); + } }, - _addCollectionPanel : function( model ){ - var historyView = this; + _addCollectionPanel : function( collectionView ){ + var historyView = this, + collectionModel = collectionView.model; - var panel = new ( this._getCollectionPanelClass( model ) )({ - model : model, - HDAViewClass : this.HDAViewClass + this.debug( 'history panel (stack), collectionModel:', collectionModel ); + var panel = new ( this._getCollectionPanelClass( collectionModel ) )({ + model : collectionModel, + HDAViewClass : this.HDAViewClass, + parentName : this.model.get( 'name' ) }); - //console.debug( panel.$el ); - //console.debug( JSON.stringify( panel.model.toJSON(), null, ' ' ) ); historyView.panelStack.push( panel ); - historyView.$el.hide().parent().append( panel.$el ); - panel.on( 'collection-close', function(){ - historyView.$el.fadeIn( historyView.fxSpeed ); + historyView.$( '.history-controls' ).add( '.datasets-list' ).hide(); + historyView.$el.append( panel.$el ); + panel.on( 'close', function(){ + historyView.render(); + collectionView.collapse(); historyView.panelStack.pop(); }); //TODO: to hdca-model, hasDetails - if( !panel.model.get( 'elements' ) ){ + if( !panel.model.hasDetails() ){ var xhr = panel.model.fetch(); xhr.done( function(){ - //console.debug( 'collection data fetched' ); - //console.debug( JSON.stringify( panel.model.toJSON(), null, ' ' ) ); + //this.debug( 'collection data fetched' ); + //this.debug( JSON.stringify( panel.model.toJSON(), null, ' ' ) ); //TODO: (re-)render collection contents panel.render(); }); @@ -341,7 +345,25 @@ var CurrentHistoryPanel = _super.extend( }, _getCollectionPanelClass : function( model ){ - return DC_PANEL.CollectionPanel; + switch( model.get( 'collection_type' ) ){ + case 'list': + return DC_PANEL.ListCollectionPanel; + case 'paired': + return DC_PANEL.PairCollectionPanel; + case 'list:paired': + return DC_PANEL.ListOfPairsCollectionPanel; + } + throw new TypeError( 'Uknown collection_type: ' + model.get( 'collection_type' ) ); + }, + + /** In this override, check for any overlaid panels first + * @param {HistoryDatasetAssociation} hda + */ + addContentView : function( hda ){ + if( this.panelStack.length ){ + return this; + } + return _super.prototype.addContentView.call( this, hda ); }, // ........................................................................ external objects/MVC diff --git a/static/scripts/mvc/history/history-content-base-view.js b/static/scripts/mvc/history/history-content-base-view.js index fd4ece43bdf..586af18ff5c 100644 --- a/static/scripts/mvc/history/history-content-base-view.js +++ b/static/scripts/mvc/history/history-content-base-view.js @@ -8,6 +8,7 @@ define([ * Functionality here should be history-centric. */ var HistoryContentViewMixin = { + //PRECONDITION: expects to be mixed into an BASE_MVC.ExpandableView //TODO: most of the fns/attrs here are basal to any sort of list view - consider moving initialize : function( attributes ){ @@ -42,9 +43,8 @@ var HistoryContentViewMixin = { _buildNewRender : function(){ // create a new render using a skeleton template, render title buttons, render body, and set up events, etc. var $newRender = $( this.templates.skeleton( this.model.toJSON() ) ); - var titleButtons = this._render_titleButtons(); - $newRender.find( '.dataset-primary-actions' ).append( this._render_titleButtons() ); - $newRender.children( '.dataset-body' ).replaceWith( this._renderBody() ); + $newRender.find( '.primary-actions' ).append( this._render_primaryActions() ); + $newRender.children( '.details' ).replaceWith( this._renderBody() ); this._setUpBehaviors( $newRender ); //this._renderSelectable( $newRender ); return $newRender; @@ -103,7 +103,7 @@ var HistoryContentViewMixin = { /** Render icon-button group for the common, most easily accessed actions. * @returns {jQuery} rendered DOM or null */ - _render_titleButtons : function(){ + _render_primaryActions : function(){ // override return []; }, @@ -120,7 +120,6 @@ var HistoryContentViewMixin = { */ toggleExpanded : function( expand ){ expand = ( expand === undefined )?( !this.expanded ):( expand ); - this.warn( this + '.toggleExpanded, expand:', expand ); if( expand ){ this.expand(); } else { @@ -138,11 +137,11 @@ var HistoryContentViewMixin = { var contentView = this; function _renderBodyAndExpand(){ - contentView.$el.children( '.dataset-body' ).replaceWith( contentView._renderBody() ); + contentView.$( '.details' ).replaceWith( contentView._renderBody() ); // needs to be set after the above or the slide will not show contentView.expanded = true; - contentView.$el.children( '.dataset-body' ).slideDown( contentView.fxSpeed, function(){ - contentView.trigger( 'expanded', contentView.model ); + contentView.$( '.details' ).slideDown( contentView.fxSpeed, function(){ + contentView.trigger( 'expanded', contentView ); }); } // fetch first if no details in the model @@ -162,8 +161,8 @@ var HistoryContentViewMixin = { collapse : function(){ var contentView = this; contentView.expanded = false; - this.$el.children( '.dataset-body' ).slideUp( contentView.fxSpeed, function(){ - contentView.trigger( 'collapsed', contentView.model.id ); + this.$( '.details' ).slideUp( contentView.fxSpeed, function(){ + contentView.trigger( 'collapsed', contentView ); }); }, @@ -181,8 +180,8 @@ var HistoryContentViewMixin = { this.selectable = true; this.trigger( 'selectable', true, this ); - this.$( '.dataset-primary-actions' ).hide(); - this.$( '.dataset-selector' ).show(); + this.$( '.primary-actions' ).hide(); + this.$( '.selector' ).show(); }, /** remove the selection checkbox */ @@ -191,13 +190,13 @@ var HistoryContentViewMixin = { this.selectable = false; this.trigger( 'selectable', false, this ); - this.$( '.dataset-selector' ).hide(); - this.$( '.dataset-primary-actions' ).show(); + this.$( '.selector' ).hide(); + this.$( '.primary-actions' ).show(); }, /** */ toggleSelector : function(){ - if( !this.$el.find( '.dataset-selector' ).is( ':visible' ) ){ + if( !this.$el.find( '.selector' ).is( ':visible' ) ){ this.showSelector(); } else { this.hideSelector(); @@ -207,7 +206,7 @@ var HistoryContentViewMixin = { /** event handler for selection (also programmatic selection) */ select : function( event ){ // switch icon, set selected, and trigger event - this.$el.find( '.dataset-selector span' ) + this.$el.find( '.selector span' ) .removeClass( 'fa-square-o' ).addClass( 'fa-check-square-o' ); if( !this.selected ){ this.trigger( 'selected', this, event ); @@ -219,7 +218,7 @@ var HistoryContentViewMixin = { /** event handler for clearing selection (also programmatic deselection) */ deselect : function( event ){ // switch icon, set selected, and trigger event - this.$el.find( '.dataset-selector span' ) + this.$el.find( '.selector span' ) .removeClass( 'fa-check-square-o' ).addClass( 'fa-square-o' ); if( this.selected ){ this.trigger( 'de-selected', this, event ); @@ -243,14 +242,14 @@ var HistoryContentViewMixin = { draggableOn : function(){ this.draggable = true; //TODO: I have no idea why this doesn't work with the events hash or jq.on()... - //this.$el.find( '.dataset-title-bar' ) + //this.$el.find( '.title-bar' ) // .attr( 'draggable', true ) // .bind( 'dragstart', this.dragStartHandler, false ) // .bind( 'dragend', this.dragEndHandler, false ); this.dragStartHandler = _.bind( this._dragStartHandler, this ); this.dragEndHandler = _.bind( this._dragEndHandler, this ); - var titleBar = this.$el.find( '.dataset-title-bar' ).attr( 'draggable', true ).get(0); + var titleBar = this.$el.find( '.title-bar' ).attr( 'draggable', true ).get(0); titleBar.addEventListener( 'dragstart', this.dragStartHandler, false ); titleBar.addEventListener( 'dragend', this.dragEndHandler, false ); }, @@ -258,7 +257,7 @@ var HistoryContentViewMixin = { /** */ draggableOff : function(){ this.draggable = false; - var titleBar = this.$el.find( '.dataset-title-bar' ).attr( 'draggable', false ).get(0); + var titleBar = this.$el.find( '.title-bar' ).attr( 'draggable', false ).get(0); titleBar.removeEventListener( 'dragstart', this.dragStartHandler, false ); titleBar.removeEventListener( 'dragend', this.dragEndHandler, false ); }, @@ -292,14 +291,14 @@ var HistoryContentViewMixin = { // ......................................................................... events events : { // expand the body when the title is clicked or when in focus and space or enter is pressed - 'click .dataset-title-bar' : '_clickTitleBar', - 'keydown .dataset-title-bar' : '_keyDownTitleBar', + 'click .title-bar' : '_clickTitleBar', + 'keydown .title-bar' : '_keyDownTitleBar', // dragging - don't work, originalEvent === null //'dragstart .dataset-title-bar' : 'dragStartHandler', //'dragend .dataset-title-bar' : 'dragEndHandler' - 'click .dataset-selector' : 'toggleSelect' + 'click .selector' : 'toggleSelect' }, _clickTitleBar : function( event ){ @@ -337,6 +336,7 @@ var HistoryContentBaseView = Backbone.View.extend( BASE_MVC.LoggableMixin ).exte //TODO: not sure base view class is warranted or even wise + //============================================================================== return { HistoryContentViewMixin : HistoryContentViewMixin, diff --git a/static/scripts/mvc/history/history-content-base.js b/static/scripts/mvc/history/history-content-base.js index f59eef96c8f..8f5a8348608 100644 --- a/static/scripts/mvc/history/history-content-base.js +++ b/static/scripts/mvc/history/history-content-base.js @@ -105,11 +105,11 @@ var HistoryContentMixin = { return ( this.isDeletedOrPurged() || ready ); }, - /** Does this model already contain detailed data (as opposed to just summary level data)? */ - hasDetails : function(){ - // override - return true; - }, + ///** Does this model already contain detailed data (as opposed to just summary level data)? */ + //hasDetails : function(){ + // // override + // return true; + //}, /** Convenience function to match hda.has_data. */ hasData : function(){ diff --git a/static/scripts/mvc/history/readonly-history-panel.js b/static/scripts/mvc/history/readonly-history-panel.js index 937d5afa59d..721e420a8b2 100644 --- a/static/scripts/mvc/history/readonly-history-panel.js +++ b/static/scripts/mvc/history/readonly-history-panel.js @@ -23,9 +23,9 @@ var HistoryPrefs = BASE_MVC.SessionStorageModel.extend({ 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( id ){ + removeExpandedHda : function( model ){ var key = 'expandedHdas'; - this.save( key, _.omit( this.get( key ), id ) ); + this.save( key, _.omit( this.get( key ), model.id ) ); }, toString : function(){ return 'HistoryPrefs(' + this.id + ')'; @@ -196,7 +196,7 @@ var ReadOnlyHistoryPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend * @param {Object} msg optional object containing error details */ errorHandler : function( model, xhr, options, msg, details ){ - console.error( model, xhr, options, msg, details ); + this.error( model, xhr, options, msg, details ); //TODO: getting JSON parse errors from jq migrate // interrupted ajax @@ -262,7 +262,7 @@ var ReadOnlyHistoryPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend /** loads a history & hdas w/ details (but does not make them the current history) */ loadHistoryWithHDADetails : function( historyId, attributes, historyFn, hdaFn ){ - //console.info( 'loadHistoryWithHDADetails:', 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 @@ -277,7 +277,7 @@ var ReadOnlyHistoryPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend attributes = attributes || {}; panel.trigger( 'loading-history', panel ); - //console.info( 'loadHistory:', historyId, attributes, historyFn, hdaFn, hdaDetailIds ); + //this.info( 'loadHistory:', historyId, attributes, historyFn, hdaFn, hdaDetailIds ); var xhr = HISTORY_MODEL.History.getHistoryData( historyId, { historyFn : historyFn, hdaFn : hdaFn, @@ -652,11 +652,11 @@ var ReadOnlyHistoryPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend panel.errorHandler( model, xhr, options, msg ); }); // maintain a list of hdas whose bodies are expanded - hdaView.on( 'expanded', function( model ){ - panel.storage.addExpandedHda( model ); + hdaView.on( 'expanded', function( view ){ + panel.storage.addExpandedHda( view.model ); }); - hdaView.on( 'collapsed', function( id ){ - panel.storage.removeExpandedHda( id ); + hdaView.on( 'collapsed', function( view ){ + panel.storage.removeExpandedHda( view.model ); }); return this; }, @@ -743,8 +743,6 @@ var ReadOnlyHistoryPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend //}, hdaViewRange : function( viewA, viewB ){ - //console.debug( 'a: ', viewA, viewA.model ); - //console.debug( 'b: ', viewB, viewB.model ); 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, diff --git a/static/scripts/packed/galaxy.base.js b/static/scripts/packed/galaxy.base.js index c0c5b3bb550..19287351925 100644 --- a/static/scripts/packed/galaxy.base.js +++ b/static/scripts/packed/galaxy.base.js @@ -1 +1 @@ -(function(){var b=0;var c=["ms","moz","webkit","o"];for(var a=0;a");var f=b.data("menu_options");if(obj_length(f)<=0){$("
  • No Options.
  • ").appendTo(g)}$.each(f,function(j,i){if(i){var l=i.action||i;g.append($("
  • ").append($("
    ").attr("href",i.url).html(j).click(l)))}else{g.append($("
  • ").addClass("head").append($("
    ").html(j)))}});var h=$("
    ").append(g).appendTo("body");var e=d.pageX-h.width()/2;e=Math.min(e,$(document).scrollLeft()+$(window).width()-$(h).width()-5);e=Math.max(e,$(document).scrollLeft()+5);h.css({top:d.pageY,left:e})},10);setTimeout(function(){var f=function(h){$(h).bind("click.close_popup",function(){$(".popmenu-wrapper").remove();h.unbind("click.close_popup")})};f($(window.document));f($(window.top.document));for(var e=window.top.frames.length;e--;){var g=$(window.top.frames[e].document);f(g)}},50);return false})}function make_popup_menus(a){a=a||document;$(a).find("div[popupmenu]").each(function(){var b={};var d=$(this);d.find("a").each(function(){var g=$(this),i=g.get(0),e=i.getAttribute("confirm"),f=i.getAttribute("href"),h=i.getAttribute("target");if(!f){b[g.text()]=null}else{b[g.text()]={url:f,action:function(){if(!e||confirm(e)){if(h){window.open(f,h);return false}else{g.click()}}}}}});var c=$(a).find("#"+d.attr("popupmenu"));c.find("a").bind("click",function(f){f.stopPropagation();return true});make_popupmenu(c,b);c.addClass("popup");d.remove()})}function naturalSort(j,h){var p=/(-?[0-9\.]+)/g,k=j.toString().toLowerCase()||"",g=h.toString().toLowerCase()||"",l=String.fromCharCode(0),n=k.replace(p,l+"$1"+l).split(l),e=g.replace(p,l+"$1"+l).split(l),d=(new Date(k)).getTime(),o=d?(new Date(g)).getTime():null;if(o){if(do){return 1}}}var m,f;for(var i=0,c=Math.max(n.length,e.length);if){return 1}}}return 0}$.fn.refresh_select2=function(){var b=$(this);var a={width:"resolve",closeOnSelect:!b.is("[MULTIPLE]")};return b.select2(a)};function replace_big_select_inputs(a,c,b){if(!jQuery.fn.select2){return}if(a===undefined){a=20}if(c===undefined){c=3000}b=b||$("select");b.each(function(){var e=$(this).not("[multiple]");var d=e.find("option").length;if((dc)){return}if(e.hasClass("no-autocomplete")){return}e.refresh_select2()})}$.fn.make_text_editable=function(g){var d=("num_cols" in g?g.num_cols:30),c=("num_rows" in g?g.num_rows:4),e=("use_textarea" in g?g.use_textarea:false),b=("on_finish" in g?g.on_finish:null),f=("help_text" in g?g.help_text:null);var a=$(this);a.addClass("editable-text").click(function(l){if($(this).children(":input").length>0){return}a.removeClass("editable-text");var i=function(m){a.find(":input").remove();if(m!==""){a.text(m)}else{a.html("
    ")}a.addClass("editable-text");if(b){b(m)}};var h=("cur_text" in g?g.cur_text:a.text()),k,j;if(e){k=$("").attr({rows:i,cols:c}).text($.trim(k))}else{j=$("").attr({value:$.trim(k),size:c})}j.attr("id","renaming-active");j.blur(function(){$(this).remove();l.show();if(b){b(j)}});j.keyup(function(n){if(n.keyCode===27){$(this).trigger("blur")}else{if(n.keyCode===13){var m={};m[a]=$(this).val();$(this).trigger("blur");$.ajax({url:e,data:m,error:function(){alert("Text editing for elt "+f+" failed")},success:function(o){if(o!==""){l.text(o)}else{l.html("None")}if(b){b(j)}}})}}});if(g){g(j)}l.hide();j.insertAfter(l);j.focus();j.select();return})}function init_history_items(d,a,c){var b=function(){try{var e=$.jStorage.get("history_expand_state");if(e){for(var g in e){$("#"+g+" div.historyItemBody").show()}}}catch(f){$.jStorage.deleteKey("history_expand_state")}if($.browser.mozilla){$("div.historyItemBody").each(function(){if(!$(this).is(":visible")){$(this).find("pre.peek").css("overflow","hidden")}})}d.each(function(){var j=this.id,h=$(this).children("div.historyItemBody"),i=h.find("pre.peek");$(this).find(".historyItemTitleBar > .historyItemTitle").wrap("").click(function(){var k;if(h.is(":visible")){if($.browser.mozilla){i.css("overflow","hidden")}h.slideUp("fast");if(!c){k=$.jStorage.get("history_expand_state");if(k){delete k[j];$.jStorage.set("history_expand_state",k)}}}else{h.slideDown("fast",function(){if($.browser.mozilla){i.css("overflow","auto")}});if(!c){k=$.jStorage.get("history_expand_state");if(!k){k={}}k[j]=true;$.jStorage.set("history_expand_state",k)}}return false})});$("#top-links > a.toggle").click(function(){var h=$.jStorage.get("history_expand_state");if(!h){h={}}$("div.historyItemBody:visible").each(function(){if($.browser.mozilla){$(this).find("pre.peek").css("overflow","hidden")}$(this).slideUp("fast");if(h){delete h[$(this).parent().attr("id")]}});$.jStorage.set("history_expand_state",h)}).show()};b()}function commatize(b){b+="";var a=/(\d+)(\d{3})/;while(a.test(b)){b=b.replace(a,"$1,$2")}return b}function reset_tool_search(a){var c=$("#galaxy_tools").contents();if(c.length===0){c=$(document)}$(this).removeClass("search_active");c.find(".toolTitle").removeClass("search_match");c.find(".toolSectionBody").hide();c.find(".toolTitle").show();c.find(".toolPanelLabel").show();c.find(".toolSectionWrapper").each(function(){if($(this).attr("id")!=="recently_used_wrapper"){$(this).show()}else{if($(this).hasClass("user_pref_visible")){$(this).show()}}});c.find("#search-no-results").hide();c.find("#search-spinner").hide();if(a){var b=c.find("#tool-search-query");b.val("search tools")}}var GalaxyAsync=function(a){this.url_dict={};this.log_action=(a===undefined?false:a)};GalaxyAsync.prototype.set_func_url=function(a,b){this.url_dict[a]=b};GalaxyAsync.prototype.set_user_pref=function(a,b){var c=this.url_dict[arguments.callee];if(c===undefined){return false}$.ajax({url:c,data:{pref_name:a,pref_value:b},error:function(){return false},success:function(){return true}})};GalaxyAsync.prototype.log_user_action=function(c,b,d){if(!this.log_action){return}var a=this.url_dict[arguments.callee];if(a===undefined){return false}$.ajax({url:a,data:{action:c,context:b,params:d},error:function(){return false},success:function(){return true}})};function init_refresh_on_change(){$("select[refresh_on_change='true']").off("change").change(function(){var a=$(this),e=a.val(),d=false,c=a.attr("refresh_on_change_values");if(c){c=c.split(",");var b=a.attr("last_selected_value");if($.inArray(e,c)===-1&&$.inArray(b,c)===-1){return}}$(window).trigger("refresh_on_change");$(document).trigger("convert_to_values");a.get(0).form.submit()});$(":checkbox[refresh_on_change='true']").off("click").click(function(){var a=$(this),e=a.val(),d=false,c=a.attr("refresh_on_change_values");if(c){c=c.split(",");var b=a.attr("last_selected_value");if($.inArray(e,c)===-1&&$.inArray(b,c)===-1){return}}$(window).trigger("refresh_on_change");a.get(0).form.submit()});$("a[confirm]").off("click").click(function(){return confirm($(this).attr("confirm"))})}$(document).ready(function(){init_refresh_on_change();if($.fn.tooltip){$(".unified-panel-header [title]").tooltip({placement:"bottom"});$("[title]").tooltip()}make_popup_menus();replace_big_select_inputs(20,1500);$("a").click(function(){var b=$(this);var c=(parent.frames&&parent.frames.galaxy_main);if((b.attr("target")=="galaxy_main")&&(!c)){var a=b.attr("href");if(a.indexOf("?")==-1){a+="?"}else{a+="&"}a+="use_panels=True";b.attr("href",a);b.attr("target","_self")}return b})}); \ No newline at end of file +(function(){var b=0;var c=["ms","moz","webkit","o"];for(var a=0;a");var f=b.data("menu_options");if(obj_length(f)<=0){$("
  • No Options.
  • ").appendTo(g)}$.each(f,function(j,i){if(i){var l=i.action||i;g.append($("
  • ").append($("").attr("href",i.url).html(j).click(l)))}else{g.append($("
  • ").addClass("head").append($("
    ").html(j)))}});var h=$("
    ").append(g).appendTo("body");var e=d.pageX-h.width()/2;e=Math.min(e,$(document).scrollLeft()+$(window).width()-$(h).width()-5);e=Math.max(e,$(document).scrollLeft()+5);h.css({top:d.pageY,left:e})},10);setTimeout(function(){var f=function(h){$(h).bind("click.close_popup",function(){$(".popmenu-wrapper").remove();h.unbind("click.close_popup")})};f($(window.document));f($(window.top.document));for(var e=window.top.frames.length;e--;){var g=$(window.top.frames[e].document);f(g)}},50);return false})}function make_popup_menus(a){a=a||document;$(a).find("div[popupmenu]").each(function(){var b={};var d=$(this);d.find("a").each(function(){var g=$(this),i=g.get(0),e=i.getAttribute("confirm"),f=i.getAttribute("href"),h=i.getAttribute("target");if(!f){b[g.text()]=null}else{b[g.text()]={url:f,action:function(){if(!e||confirm(e)){if(h){window.open(f,h);return false}else{g.click()}}}}}});var c=$(a).find("#"+d.attr("popupmenu"));c.find("a").bind("click",function(f){f.stopPropagation();return true});make_popupmenu(c,b);c.addClass("popup");d.remove()})}function naturalSort(j,h){var p=/(-?[0-9\.]+)/g,k=j.toString().toLowerCase()||"",g=h.toString().toLowerCase()||"",l=String.fromCharCode(0),n=k.replace(p,l+"$1"+l).split(l),e=g.replace(p,l+"$1"+l).split(l),d=(new Date(k)).getTime(),o=d?(new Date(g)).getTime():null;if(o){if(do){return 1}}}var m,f;for(var i=0,c=Math.max(n.length,e.length);if){return 1}}}return 0}$.fn.refresh_select2=function(){var b=$(this);var a={width:"resolve",closeOnSelect:!b.is("[MULTIPLE]")};return b.select2(a)};function replace_big_select_inputs(a,c,b){if(!jQuery.fn.select2){return}if(a===undefined){a=20}if(c===undefined){c=3000}b=b||$("select");b.each(function(){var e=$(this).not("[multiple]");var d=e.find("option").length;if((dc)){return}if(e.hasClass("no-autocomplete")){return}e.refresh_select2()})}$.fn.make_text_editable=function(g){var d=("num_cols" in g?g.num_cols:30),c=("num_rows" in g?g.num_rows:4),e=("use_textarea" in g?g.use_textarea:false),b=("on_finish" in g?g.on_finish:null),f=("help_text" in g?g.help_text:null);var a=$(this);a.addClass("editable-text").click(function(l){if($(this).children(":input").length>0){return}a.removeClass("editable-text");var i=function(m){a.find(":input").remove();if(m!==""){a.text(m)}else{a.html("
    ")}a.addClass("editable-text");if(b){b(m)}};var h=("cur_text" in g?g.cur_text:a.text()),k,j;if(e){k=$("").attr({rows:i,cols:c}).text($.trim(k))}else{j=$("").attr({value:$.trim(k),size:c})}j.attr("id","renaming-active");j.blur(function(){$(this).remove();l.show();if(b){b(j)}});j.keyup(function(n){if(n.keyCode===27){$(this).trigger("blur")}else{if(n.keyCode===13){var m={};m[a]=$(this).val();$(this).trigger("blur");$.ajax({url:e,data:m,error:function(){alert("Text editing for elt "+f+" failed")},success:function(o){if(o!==""){l.text(o)}else{l.html("None")}if(b){b(j)}}})}}});if(g){g(j)}l.hide();j.insertAfter(l);j.focus();j.select();return})}function commatize(b){b+="";var a=/(\d+)(\d{3})/;while(a.test(b)){b=b.replace(a,"$1,$2")}return b}function reset_tool_search(a){var c=$("#galaxy_tools").contents();if(c.length===0){c=$(document)}$(this).removeClass("search_active");c.find(".toolTitle").removeClass("search_match");c.find(".toolSectionBody").hide();c.find(".toolTitle").show();c.find(".toolPanelLabel").show();c.find(".toolSectionWrapper").each(function(){if($(this).attr("id")!=="recently_used_wrapper"){$(this).show()}else{if($(this).hasClass("user_pref_visible")){$(this).show()}}});c.find("#search-no-results").hide();c.find("#search-spinner").hide();if(a){var b=c.find("#tool-search-query");b.val("search tools")}}var GalaxyAsync=function(a){this.url_dict={};this.log_action=(a===undefined?false:a)};GalaxyAsync.prototype.set_func_url=function(a,b){this.url_dict[a]=b};GalaxyAsync.prototype.set_user_pref=function(a,b){var c=this.url_dict[arguments.callee];if(c===undefined){return false}$.ajax({url:c,data:{pref_name:a,pref_value:b},error:function(){return false},success:function(){return true}})};GalaxyAsync.prototype.log_user_action=function(c,b,d){if(!this.log_action){return}var a=this.url_dict[arguments.callee];if(a===undefined){return false}$.ajax({url:a,data:{action:c,context:b,params:d},error:function(){return false},success:function(){return true}})};function init_refresh_on_change(){$("select[refresh_on_change='true']").off("change").change(function(){var a=$(this),e=a.val(),d=false,c=a.attr("refresh_on_change_values");if(c){c=c.split(",");var b=a.attr("last_selected_value");if($.inArray(e,c)===-1&&$.inArray(b,c)===-1){return}}$(window).trigger("refresh_on_change");$(document).trigger("convert_to_values");a.get(0).form.submit()});$(":checkbox[refresh_on_change='true']").off("click").click(function(){var a=$(this),e=a.val(),d=false,c=a.attr("refresh_on_change_values");if(c){c=c.split(",");var b=a.attr("last_selected_value");if($.inArray(e,c)===-1&&$.inArray(b,c)===-1){return}}$(window).trigger("refresh_on_change");a.get(0).form.submit()});$("a[confirm]").off("click").click(function(){return confirm($(this).attr("confirm"))})}$(document).ready(function(){init_refresh_on_change();if($.fn.tooltip){$(".unified-panel-header [title]").tooltip({placement:"bottom"});$("[title]").tooltip()}make_popup_menus();replace_big_select_inputs(20,1500);$("a").click(function(){var b=$(this);var c=(parent.frames&&parent.frames.galaxy_main);if((b.attr("target")=="galaxy_main")&&(!c)){var a=b.attr("href");if(a.indexOf("?")==-1){a+="?"}else{a+="&"}a+="use_panels=True";b.attr("href",a);b.attr("target","_self")}return b})}); \ No newline at end of file diff --git a/static/scripts/packed/galaxy.tools.js b/static/scripts/packed/galaxy.tools.js index 259e4805e9c..c8921b0cd68 100644 --- a/static/scripts/packed/galaxy.tools.js +++ b/static/scripts/packed/galaxy.tools.js @@ -1 +1 @@ -define(["libs/underscore","mvc/tools"],function(c,b){var a=function(g,f){$("input[name='"+g+"'][type='checkbox']").attr("checked",!!f)};$("div.checkUncheckAllPlaceholder").each(function(){var f=$(this).attr("checkbox_name");select_link=$("").text("Select All").click(function(){a(f,true)});unselect_link=$("").text("Unselect All").click(function(){a(f,false)});$(this).append(select_link).append(" ").append(unselect_link)});var e={select_single:{icon_class:"fa-file-o",select_by:"Run tool on single input",allow_remap:true},select_multiple:{icon_class:"fa-files-o",select_by:"Run tool in parallel across multiple datasets",allow_remap:false,min_option_count:2},select_collection:{icon_class:"fa-folder-o",select_by:"Run tool in parallel across dataset collection",allow_remap:false},multiselect_single:{icon_class:"fa-list-alt",select_by:"Run tool over multiple datasets",allow_remap:true},multiselect_collection:{icon_class:"fa-folder-o",select_by:"Run tool over dataset collection",allow_remap:false,},select_single_collection:{icon_class:"fa-file-o",select_by:"Run tool on single collection",allow_remap:true},select_map_over_collections:{icon_class:"fa-folder-o",select_by:"Map tool over compontents of nested collection",allow_remap:false,}};var d=Backbone.View.extend({initialize:function(l){var g=l.default_option;var m=null;var k=l.switch_options;this.switchOptions=k;this.prefix=l.prefix;var j=this.$el;var f=this;var h=0;var i=0;c.each(this.switchOptions,function(r,t){var n=c.size(r.options);var q=e[t];var p=h++;var s=false;if(g==t){m=p}else{if(n<(q.min_option_count||1)){s=true}}if(!s){i++;var o=$('').click(function(){f.enableSelectBy(p,t)}).attr("title",q.select_by).data("index",p);f.formRow().find("label").append(o)}});if(i<2){f.formRow().find("i.runOptionIcon").hide()}if(m!=null){f.enableSelectBy(m,g)}},formRow:function(){return this.$el.closest(".form-row")},render:function(){},enableSelectBy:function(k,j){var h=e[j];if(h.allow_remap){$("div#remap-row").css("display","inherit")}else{$("div#remap-row").css("display","none")}this.formRow().find("i").each(function(n,o){var l=$(o);var m=l.data("index");if(m==k){l.css("color","black")}else{l.css("color","Gray")}});var g=this.$("select");var f=this.switchOptions[j];g.attr("name",this.prefix+f.name);g.attr("multiple",f.multiple);var i=this.$(".select2-container").length>0;g.html("");c.each(f.options,function(m){var o=m[0];var n=m[1];var l=m[2];g.append($("