commit/galaxy-central: 2 new changesets
2 new commits in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/changeset/2d1402caf21a/ changeset: 2d1402caf21a user: carlfeberhard date: 2012-11-15 17:25:18 summary: static/scripts/mvc: jsDocs on all. I've used jsdoc-toolkit via node with success on these; the Rhino version should work also. affected #: 11 files diff -r 94627de6252824193ff0ff659807d17e59e4f94f -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e static/scripts/mvc/base-mvc.js --- a/static/scripts/mvc/base-mvc.js +++ b/static/scripts/mvc/base-mvc.js @@ -43,14 +43,19 @@ //============================================================================== -/** - * Adds logging capabilities to your Models/Views - * can be used with plain browser console (or something more complex like an AJAX logger) +/** @class Mixin to add logging capabilities to an object. + * Designed to allow switching an objects log output off/on at one central + * statement. Can be used with plain browser console (or something more + * complex like an AJAX logger). + * <br />NOTE: currently only uses the console.debug log function + * (as opposed to debug, error, warn, etc.) + * @name LoggableMixin * - * add to your models/views at the definition using chaining: + * @example + * // Add to your models/views at the definition using chaining: * var MyModel = BaseModel.extend( LoggableMixin ).extend({ // ... }); * - * or - more explicitly AFTER the definition: + * // or - more explicitly AFTER the definition: * var MyModel = BaseModel.extend({ * logger : console * // ... @@ -58,12 +63,19 @@ * }) * _.extend( MyModel.prototype, LoggableMixin ) * - * NOTE: currently only uses the console.debug log function (as opposed to debug, error, warn, etc.) */ -var LoggableMixin = { +var LoggableMixin = /** @lends LoggableMixin# */{ + + /** The logging object whose log function will be used to output + * messages. Null will supress all logging. Commonly set to console. + */ // replace null with console (if available) to see all logs logger : null, + /** Output log messages/arguments to logger. + * @param {Arguments} ... (this function is variadic) + * @returns undefined if not this.logger + */ log : function(){ if( this.logger ){ return this.logger.log.apply( this.logger, arguments ); @@ -74,21 +86,29 @@ // ============================================================================= -/** Global string localization object (and global short form alias) - * set with either: - * GalaxyLocalization.setLocalizedString( original, localized ) - * GalaxyLocalization.setLocalizedString({ original1 : localized1, original2 : localized2 }) - * get with either: - * GalaxyLocalization.localize( string ) - * _l( string ) +/** @class string localizer (and global short form alias) + * + * @example + * // set with either: + * GalaxyLocalization.setLocalizedString( original, localized ) + * GalaxyLocalization.setLocalizedString({ original1 : localized1, original2 : localized2 }) + * // get with either: + * GalaxyLocalization.localize( string ) + * _l( string ) + * + * @constructs */ //TODO: move to Galaxy.Localization (maybe galaxy.base.js) var GalaxyLocalization = jQuery.extend( {}, { + /** shortened, alias reference to GalaxyLocalization.localize */ ALIAS_NAME : '_l', + /** map of available localized strings (english -> localized) */ localizedStrings : {}, - // Set a single English string -> localized string association, or set an entire map of those associations - // Pass in either two strings (english, localized) or just an obj (map) of english : localized + /** Set a single English string -> localized string association, or set an entire map of those associations + * @param {String or Object} str_or_obj english (key) string or a map of english -> localized strings + * @param {String} localized string if str_or_obj was a string + */ setLocalizedString : function( str_or_obj, localizedString ){ //console.debug( this + '.setLocalizedString:', str_or_obj, localizedString ); var self = this; @@ -117,7 +137,10 @@ } }, - // Attempt to get a localized string for strToLocalize. If not found, return the original strToLocalize + /** Attempt to get a localized string for strToLocalize. If not found, return the original strToLocalize. + * @param {String} strToLocalize the string to localize + * @returns either the localized string if found or strToLocalize if not found + */ localize : function( strToLocalize ){ //console.debug( this + '.localize:', strToLocalize ); @@ -132,6 +155,7 @@ return this.localizedStrings[ strToLocalize ] || strToLocalize; }, + /** String representation. */ toString : function(){ return 'GalaxyLocalization'; } }); @@ -146,16 +170,17 @@ //============================================================================== /** - * @class PersistantStorage - * persistant storage adapter to: - * provide an easy interface to object based storage using method chaining - * allow easy change of the storage engine used (h5's local storage?) + * @class persistant storage adapter. + * Provides an easy interface to object based storage using method chaining. + * Allows easy change of the storage engine used (h5's local storage?). + * @augments StorageRecursionHelper * * @param {String} storageKey : the key the storage engine will place the storage object under * @param {Object} storageDefaults : [optional] initial object to set up storage with * - * @example : - * HistoryPanel.storage = new PersistanStorage( HistoryPanel.toString(), { visibleItems, {} }) + * @example + * // example of construction and use + * HistoryPanel.storage = new PersistanStorage( HistoryPanel.toString(), { visibleItems, {} }); * itemView.bind( 'toggleBodyVisibility', function( id, visible ){ * if( visible ){ * HistoryPanel.storage.get( 'visibleItems' ).set( id, true ); @@ -163,6 +188,7 @@ * HistoryPanel.storage.get( 'visibleItems' ).deleteKey( id ); * } * }); + * @constructor */ var PersistantStorage = function( storageKey, storageDefaults ){ if( !storageKey ){ @@ -176,16 +202,21 @@ STORAGE_ENGINE_SETTER = jQuery.jStorage.set, STORAGE_ENGINE_KEY_DELETER = jQuery.jStorage.deleteKey; - // recursion helper for method chaining access - var StorageRecursionHelper = function( data, parent ){ + /** Inner, recursive, private class for method chaining access. + * @name StorageRecursionHelper + * @constructor + */ + function StorageRecursionHelper( data, parent ){ //console.debug( 'new StorageRecursionHelper. data:', data ); data = data || {}; parent = parent || null; - return { - // get a value from the storage obj named 'key', - // if it's an object - return a new StorageRecursionHelper wrapped around it - // if it's something simpler - return the value - // if this isn't passed a key - return the data at this level of recursion + + return /** @lends StorageRecursionHelper.prototype */{ + /** get a value from the storage obj named 'key', + * if it's an object - return a new StorageRecursionHelper wrapped around it + * if it's something simpler - return the value + * if this isn't passed a key - return the data at this level of recursion + */ get : function( key ){ //console.debug( this + '.get', key ); if( key === undefined ){ @@ -197,32 +228,33 @@ } return undefined; }, + /** get the underlying data based on this key */ // set a value on the current data - then pass up to top to save current entire object in storage set : function( key, value ){ //TODO: add parameterless variation setting the data somehow // ??: difficult bc of obj by ref, closure //console.debug( this + '.set', key, value ); data[ key ] = value; - this.save(); + this._save(); return this; }, // remove a key at this level - then save entire (as 'set' above) deleteKey : function( key ){ //console.debug( this + '.deleteKey', key ); delete data[ key ]; - this.save(); + this._save(); return this; }, // pass up the recursion chain (see below for base case) - save : function(){ + _save : function(){ //console.debug( this + '.save', parent ); - return parent.save(); + return parent._save(); }, toString : function(){ return ( 'StorageRecursionHelper(' + data + ')' ); } }; - }; + } //??: more readable to make another class? var returnedStorage = {}; @@ -238,17 +270,26 @@ // the object returned by this constructor will be a modified StorageRecursionHelper returnedStorage = new StorageRecursionHelper( data ); - // the base case for save()'s upward recursion - save everything to storage - returnedStorage.save = function( newData ){ - //console.debug( returnedStorage, '.save:', JSON.stringify( returnedStorage.get() ) ); - STORAGE_ENGINE_SETTER( storageKey, returnedStorage.get() ); - }; - // delete function to remove the base data object from the storageEngine - returnedStorage.destroy = function(){ - //console.debug( returnedStorage, '.destroy:' ); - STORAGE_ENGINE_KEY_DELETER( storageKey ); - }; - returnedStorage.toString = function(){ return 'PersistantStorage(' + data + ')'; }; + + jQuery.extend( returnedStorage, /** @lends PersistantStorage.prototype */{ + /** The base case for save()'s upward recursion - save everything to storage. + * @private + * @param {Any} newData data object to save to storage + */ + _save : function( newData ){ + //console.debug( returnedStorage, '._save:', JSON.stringify( returnedStorage.get() ) ); + return STORAGE_ENGINE_SETTER( storageKey, returnedStorage.get() ); + }, + /** Delete function to remove the entire base data object from the storageEngine. + */ + destroy : function(){ + //console.debug( returnedStorage, '.destroy:' ); + return STORAGE_ENGINE_KEY_DELETER( storageKey ); + }, + /** String representation. + */ + toString : function(){ return 'PersistantStorage(' + data + ')'; } + }); return returnedStorage; }; diff -r 94627de6252824193ff0ff659807d17e59e4f94f -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e static/scripts/mvc/dataset/hda-base.js --- a/static/scripts/mvc/dataset/hda-base.js +++ b/static/scripts/mvc/dataset/hda-base.js @@ -2,33 +2,47 @@ // "../mvc/base-mvc" //], function(){ //============================================================================== -/** read only view for HistoryDatasetAssociations - * +/** @class Read only view for HistoryDatasetAssociation. + * @name HDABaseView + * + * @augments BaseView + * @borrows LoggableMixin#logger as #logger + * @borrows LoggableMixin#log as #log + * @constructs */ -var HDABaseView = BaseView.extend( LoggableMixin ).extend({ - //??TODO: add alias in initialize this.hda = this.model? - // view for HistoryDatasetAssociation model above +var HDABaseView = BaseView.extend( LoggableMixin ).extend( +/** @lends HDABaseView.prototype */{ - // uncomment this out see log messages + ///** logger used to record this.log messages, commonly set to console */ + //// comment this out to suppress log output //logger : console, tagName : "div", className : "historyItemContainer", - // ................................................................................ SET UP + // ......................................................................... SET UP + /** Set up the view, cache url templates, bind listeners + * @param {Object} attributes + * @config {Object} urlTemplates nested object containing url templates for this view + * @throws 'needs urlTemplates' if urlTemplates isn't present + * @see Backbone.View#initialize + */ initialize : function( attributes ){ this.log( this + '.initialize:', attributes ); - // which buttons go in most states (ok/failed meta are more complicated) + /** list of rendering functions for the default, primary icon-buttons. */ this.defaultPrimaryActionButtonRenderers = [ this._render_showParamsButton ]; // render urlTemplates (gen. provided by GalaxyPaths) to urls + //TODO:?? render urls here or in render()? if( !attributes.urlTemplates ){ throw( 'HDAView needs urlTemplates on initialize' ); } - this.urls = this.renderUrls( attributes.urlTemplates, this.model.toJSON() ); + /** web controller urls for functions relating to this hda. These + * are rendered from urlTemplates using the model data. */ + this.urls = this._renderUrls( attributes.urlTemplates, this.model.toJSON() ); - // whether the body of this hda is expanded (shown) + /** is the body of this hda view expanded/not. */ this.expanded = attributes.expanded || false; // re-render the entire view on any model change @@ -38,22 +52,25 @@ //}, this ); }, - // urlTemplates is a map (or nested map) of underscore templates (currently, anyhoo) - // use the templates to create the apropo urls for each action this ds could use - renderUrls : function( urlTemplates, modelJson ){ + /** render the urls for this hda using the model data and the url templates from initialize. + * @param {Object} urlTemplates a map (or nested map) of underscore templates (currently, anyhoo) + * @param {Object} modelJson data from the model + * @returns {Object} the templated urls + */ + _renderUrls : function( urlTemplates, modelJson ){ var hdaView = this, urls = {}; _.each( urlTemplates, function( urlTemplateOrObj, urlKey ){ // object == nested templates: recurse if( _.isObject( urlTemplateOrObj ) ){ - urls[ urlKey ] = hdaView.renderUrls( urlTemplateOrObj, modelJson ); + urls[ urlKey ] = hdaView._renderUrls( urlTemplateOrObj, modelJson ); // string == template: } else { // meta_down load is a special case (see renderMetaDownloadUrls) //TODO: should be a better (gen.) way to handle this case if( urlKey === 'meta_download' ){ - urls[ urlKey ] = hdaView.renderMetaDownloadUrls( urlTemplateOrObj, modelJson ); + urls[ urlKey ] = hdaView._renderMetaDownloadUrls( urlTemplateOrObj, modelJson ); } else { urls[ urlKey ] = _.template( urlTemplateOrObj, modelJson ); } @@ -62,8 +79,13 @@ return urls; }, - // there can be more than one meta_file to download, so return a list of url and file_type for each - renderMetaDownloadUrls : function( urlTemplate, modelJson ){ + /** there can be more than one meta_file (e.g. bam index) to download, + * so return a list of url and file_type for each + * @param {Object} urlTemplate underscore templates for meta download urls + * @param {Object} modelJson data from the model + * @returns {Object} url and filetype for each meta file + */ + _renderMetaDownloadUrls : function( urlTemplate, modelJson ){ return _.map( modelJson.meta_files, function( meta_file ){ return { url : _.template( urlTemplate, { id: modelJson.id, file_type: meta_file.file_type }), @@ -72,8 +94,14 @@ }); }, - // ................................................................................ RENDER MAIN - // events: rendered, rendered:ready, rendered:initial, rendered:ready:initial + // ......................................................................... RENDER MAIN + /** Render this HDA, set up ui. + * @fires rendered:ready when rendered and NO running HDAs + * @fires rendered when rendered and running HDAs + * @fires rendered:initial on first render with running HDAs + * @fires rendered:initial:ready when first rendered and NO running HDAs + * @returns {Object} this HDABaseView + */ render : function(){ var view = this, id = this.model.get( 'id' ), @@ -118,15 +146,19 @@ return this; }, - // ................................................................................ RENDER WARNINGS - // hda warnings including: is deleted, is purged, is hidden (including links to further actions (undelete, etc.)) + // ................................................................................ RENDER titlebar + /** Render any hda warnings including: is deleted, is purged, is hidden. + * (including links to further actions (undelete, etc.)) + * @returns {jQuery} rendered DOM + */ _render_warnings : function(){ // jQ errs on building dom with whitespace - if there are no messages, trim -> '' return $( jQuery.trim( HDABaseView.templates.messages( this.model.toJSON() ))); }, - // ................................................................................ RENDER TITLEBAR - // the part of an hda always shown (whether the body is expanded or not): title link, title buttons + /** Render the part of an hda always shown (whether the body is expanded or not): title link, title buttons. + * @returns {jQuery} rendered DOM + */ _render_titleBar : function(){ var titleBar = $( '<div class="historyItemTitleBar" style="overflow: hidden"></div>' ); titleBar.append( this._render_titleButtons() ); @@ -135,9 +167,9 @@ return titleBar; }, - // ................................................................................ display, edit attr, delete - // icon-button group for the common, most easily accessed actions - //NOTE: these are generally displayed for almost every hda state (tho poss. disabled) + /** Render icon-button group for the common, most easily accessed actions. + * @returns {jQuery} rendered DOM + */ _render_titleButtons : function(){ // render the display, edit attr and delete icon-buttons var buttonDiv = $( '<div class="historyItemButtons"></div>' ); @@ -145,7 +177,9 @@ return buttonDiv; }, - // icon-button to display this hda in the galaxy main iframe + /** Render icon-button to display this hda in the galaxy main iframe. + * @returns {jQuery} rendered DOM + */ _render_displayButton : function(){ // don't show display if not in ready state, error'd, or not accessible if( ( !this.model.inReadyState() ) @@ -175,23 +209,30 @@ return this.displayButton.render().$el; }, - // ................................................................................ titleLink - // render the hid and hda.name as a link (that will expand the body) + /** Render the hid and hda.name as a link (that will expand the body). + * @returns {jQuery} rendered DOM + */ _render_titleLink : function(){ return $( jQuery.trim( HDABaseView.templates.titleLink( + //TODO?? does this need urls? _.extend( this.model.toJSON(), { urls: this.urls } ) ))); }, - // ................................................................................ RENDER BODY - // render the data/metadata summary (format, size, misc info, etc.) + // ......................................................................... RENDER BODY + /** Render the data/metadata summary (format, size, misc info, etc.). + * @returns {jQuery} rendered DOM + */ _render_hdaSummary : function(){ var modelData = _.extend( this.model.toJSON(), { urls: this.urls } ); return HDABaseView.templates.hdaSummary( modelData ); }, - // ................................................................................ primary actions - // render the icon-buttons gen. placed underneath the hda summary + // ......................................................................... primary actions + /** Render the icon-buttons gen. placed underneath the hda summary (e.g. download, show params, etc.) + * @param {Array} buttonRenderingFuncs array of rendering functions appending the results in order + * @returns {jQuery} rendered DOM + */ _render_primaryActionButtons : function( buttonRenderingFuncs ){ var view = this, primaryActionButtons = $( '<div/>' ).attr( 'id', 'primary-actions-' + this.model.get( 'id' ) ); @@ -201,7 +242,9 @@ return primaryActionButtons; }, - // icon-button/popupmenu to down the data (and/or the associated meta files (bai, etc.)) for this hda + /** Render icon-button/popupmenu to download the data (and/or the associated meta files (bai, etc.)) for this hda. + * @returns {jQuery} rendered DOM + */ _render_downloadButton : function(){ // don't show anything if the data's been purged if( this.model.get( 'purged' ) || !this.model.hasData() ){ return null; } @@ -215,7 +258,9 @@ return $( downloadLinkHTML ); }, - // icon-button to show the input and output (stdout/err) for the job that created this hda + /** Render icon-button to show the input and output (stdout/err) for the job that created this hda. + * @returns {jQuery} rendered DOM + */ _render_showParamsButton : function(){ // gen. safe to show in all cases this.showParamsButton = new IconButtonView({ model : new IconButton({ @@ -227,8 +272,10 @@ return this.showParamsButton.render().$el; }, - // ................................................................................ other elements - // render links to external genome display applications (igb, gbrowse, etc.) + // ......................................................................... other elements + /** Render links to external genome display applications (igb, gbrowse, etc.). + * @returns {jQuery} rendered DOM + */ //TODO: not a fan of the style on these _render_displayApps : function(){ if( !this.model.hasData() ){ return null; } @@ -250,7 +297,9 @@ return displayAppsDiv; }, - // render the data peek + /** Render the data peek. + * @returns {jQuery} rendered DOM + */ //TODO: curr. pre-formatted into table on the server side - may not be ideal/flexible _render_peek : function(){ if( !this.model.get( 'peek' ) ){ return null; } @@ -262,28 +311,99 @@ ); }, - // ................................................................................ state body renderers - // _render_body fns for the various states + // ......................................................................... state body renderers + /** Render the (expanded) body of an HDA, dispatching to other functions based on the HDA state + * @returns {jQuery} rendered DOM + */ //TODO: only render these on expansion (or already expanded) + _render_body : function(){ + //this.log( this + '_render_body' ); + + var body = $( '<div/>' ) + .attr( 'id', 'info-' + this.model.get( 'id' ) ) + .addClass( 'historyItemBody' ) + .attr( 'style', 'display: block' ); + + //TODO: not a fan of this dispatch + switch( this.model.get( 'state' ) ){ + case HistoryDatasetAssociation.STATES.NOT_VIEWABLE : + this._render_body_not_viewable( body ); + break; + case HistoryDatasetAssociation.STATES.UPLOAD : + this._render_body_uploading( body ); + break; + case HistoryDatasetAssociation.STATES.QUEUED : + this._render_body_queued( body ); + break; + case HistoryDatasetAssociation.STATES.RUNNING : + this._render_body_running( body ); + break; + case HistoryDatasetAssociation.STATES.ERROR : + this._render_body_error( body ); + break; + case HistoryDatasetAssociation.STATES.DISCARDED : + this._render_body_discarded( body ); + break; + case HistoryDatasetAssociation.STATES.SETTING_METADATA : + this._render_body_setting_metadata( body ); + break; + case HistoryDatasetAssociation.STATES.EMPTY : + this._render_body_empty( body ); + break; + case HistoryDatasetAssociation.STATES.FAILED_METADATA : + this._render_body_failed_metadata( body ); + break; + case HistoryDatasetAssociation.STATES.OK : + this._render_body_ok( body ); + break; + default: + //??: no body? + body.append( $( '<div>Error: unknown dataset state "' + state + '".</div>' ) ); + } + body.append( '<div style="clear: both"></div>' ); + + if( this.expanded ){ + body.show(); + } else { + body.hide(); + } + return body; + }, + + /** Render inaccessible, not-owned by curr user. + * @param {jQuery} parent DOM to which to append this body + */ _render_body_not_viewable : function( parent ){ //TODO: revisit - still showing display, edit, delete (as common) - that CAN'T be right parent.append( $( '<div>' + _l( 'You do not have permission to view dataset' ) + '.</div>' ) ); }, + /** Render an HDA still being uploaded. + * @param {jQuery} parent DOM to which to append this body + */ _render_body_uploading : function( parent ){ parent.append( $( '<div>' + _l( 'Dataset is uploading' ) + '</div>' ) ); }, + /** Render an HDA whose job is queued. + * @param {jQuery} parent DOM to which to append this body + */ _render_body_queued : function( parent ){ parent.append( $( '<div>' + _l( 'Job is waiting to run' ) + '.</div>' ) ); parent.append( this._render_primaryActionButtons( this.defaultPrimaryActionButtonRenderers )); }, + /** Render an HDA whose job is running. + * @param {jQuery} parent DOM to which to append this body + */ _render_body_running : function( parent ){ parent.append( '<div>' + _l( 'Job is currently running' ) + '.</div>' ); parent.append( this._render_primaryActionButtons( this.defaultPrimaryActionButtonRenderers )); }, + /** Render an HDA whose job has failed. + * @param {jQuery} parent DOM to which to append this body + */ _render_body_error : function( parent ){ if( !this.model.get( 'purged' ) ){ parent.append( $( '<div>' + this.model.get( 'misc_blurb' ) + '</div>' ) ); @@ -295,15 +415,24 @@ )); }, + /** Render an HDA which was deleted during upload. + * @param {jQuery} parent DOM to which to append this body + */ _render_body_discarded : function( parent ){ parent.append( '<div>' + _l( 'The job creating this dataset was cancelled before completion' ) + '.</div>' ); parent.append( this._render_primaryActionButtons( this.defaultPrimaryActionButtonRenderers )); }, + /** Render an HDA where the metadata is still being determined. + * @param {jQuery} parent DOM to which to append this body + */ _render_body_setting_metadata : function( parent ){ parent.append( $( '<div>' + _l( 'Metadata is being auto-detected' ) + '.</div>' ) ); }, + /** Render an empty/no data HDA. + * @param {jQuery} parent DOM to which to append this body + */ _render_body_empty : function( parent ){ //TODO: replace i with dataset-misc-info class //?? why are we showing the file size when we know it's zero?? @@ -311,6 +440,9 @@ parent.append( this._render_primaryActionButtons( this.defaultPrimaryActionButtonRenderers )); }, + /** Render an HDA where the metadata wasn't produced correctly. + * @param {jQuery} parent DOM to which to append this body + */ _render_body_failed_metadata : function( parent ){ //TODO: the css for this box is broken (unlike the others) // add a message box about the failure at the top of the body... @@ -319,6 +451,9 @@ this._render_body_ok( parent ); }, + /** Render an HDA that's done running and where everything worked. + * @param {jQuery} parent DOM to which to append this body + */ _render_body_ok : function( parent ){ // most common state renderer and the most complicated parent.append( this._render_hdaSummary() ); @@ -344,67 +479,18 @@ parent.append( this._render_peek() ); }, - _render_body : function(){ - //this.log( this + '_render_body' ); - - var body = $( '<div/>' ) - .attr( 'id', 'info-' + this.model.get( 'id' ) ) - .addClass( 'historyItemBody' ) - .attr( 'style', 'display: block' ); - - //TODO: not a fan of this dispatch - switch( this.model.get( 'state' ) ){ - case HistoryDatasetAssociation.STATES.NOT_VIEWABLE : - this._render_body_not_viewable( body ); - break; - case HistoryDatasetAssociation.STATES.UPLOAD : - this._render_body_uploading( body ); - break; - case HistoryDatasetAssociation.STATES.QUEUED : - this._render_body_queued( body ); - break; - case HistoryDatasetAssociation.STATES.RUNNING : - this._render_body_running( body ); - break; - case HistoryDatasetAssociation.STATES.ERROR : - this._render_body_error( body ); - break; - case HistoryDatasetAssociation.STATES.DISCARDED : - this._render_body_discarded( body ); - break; - case HistoryDatasetAssociation.STATES.SETTING_METADATA : - this._render_body_setting_metadata( body ); - break; - case HistoryDatasetAssociation.STATES.EMPTY : - this._render_body_empty( body ); - break; - case HistoryDatasetAssociation.STATES.FAILED_METADATA : - this._render_body_failed_metadata( body ); - break; - case HistoryDatasetAssociation.STATES.OK : - this._render_body_ok( body ); - break; - default: - //??: no body? - body.append( $( '<div>Error: unknown dataset state "' + state + '".</div>' ) ); - } - body.append( '<div style="clear: both"></div>' ); - - if( this.expanded ){ - body.show(); - } else { - body.hide(); - } - return body; - }, - - // ................................................................................ EVENTS + // ......................................................................... EVENTS + /** event map */ events : { 'click .historyItemTitle' : 'toggleBodyVisibility' }, - // expand/collapse body - // event: body-visible, body-hidden + /** Render an HDA that's done running and where everything worked. + * @param {Event} event the event that triggered this (@link HDABaseView#events) + * @param {Boolean} expanded if true, expand; if false, collapse + * @fires body-expanded when a body has been expanded + * @fires body-collapsed when a body has been collapsed + */ toggleBodyVisibility : function( event, expanded ){ var hdaView = this, $body = this.$el.find( '.historyItemBody' ); @@ -413,23 +499,23 @@ if( expanded ){ $body.slideDown( 'fast', function(){ - hdaView.trigger( 'body-visible', hdaView.model.get( 'id' ) ); + hdaView.trigger( 'body-expanded', hdaView.model.get( 'id' ) ); }); } else { $body.slideUp( 'fast', function(){ - hdaView.trigger( 'body-hidden', hdaView.model.get( 'id' ) ); + hdaView.trigger( 'body-collapsed', hdaView.model.get( 'id' ) ); }); } }, - // ................................................................................ UTILTIY + // ......................................................................... MISC toString : function(){ var modelString = ( this.model )?( this.model + '' ):( '(no model)' ); return 'HDABaseView(' + modelString + ')'; } }); -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ TEMPLATES HDABaseView.templates = { warningMsg : Handlebars.templates[ 'template-warningmessagesmall' ], diff -r 94627de6252824193ff0ff659807d17e59e4f94f -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e static/scripts/mvc/dataset/hda-edit.js --- a/static/scripts/mvc/dataset/hda-edit.js +++ b/static/scripts/mvc/dataset/hda-edit.js @@ -2,25 +2,42 @@ // "../mvc/base-mvc" //], function(){ //============================================================================== -/** editing view for HistoryDatasetAssociations +/** @class Editing view for HistoryDatasetAssociation. + * @name HDAEditView * + * @augments HDABaseView + * @borrows LoggableMixin#logger as #logger + * @borrows LoggableMixin#log as #log + * @constructs */ -var HDAEditView = HDABaseView.extend({ +var HDAEditView = HDABaseView.extend( LoggableMixin ).extend( +/** @lends HDAEditView.prototype */{ - // ................................................................................ SET UP + // ......................................................................... SET UP + /** Set up the view, cache url templates, bind listeners. + * Overrides HDABaseView.initialize to change default actions (adding re-run). + * @param {Object} attributes + * @config {Object} urlTemplates nested object containing url templates for this view + * @throws 'needs urlTemplates' if urlTemplates isn't present + * @see HDABaseView#initialize + */ initialize : function( attributes ){ HDABaseView.prototype.initialize.call( this, attributes ); - // which buttons go in most states (ok/failed meta are more complicated) - // HDAEdit gets the rerun button on almost all states + /** list of rendering functions for the default, primary icon-buttons. */ this.defaultPrimaryActionButtonRenderers = [ this._render_showParamsButton, + // HDAEdit gets the rerun button on almost all states this._render_rerunButton ]; }, - // ................................................................................ RENDER WARNINGS - // hda warnings including: is deleted, is purged, is hidden (including links to further actions (undelete, etc.)) + // ......................................................................... RENDER WARNINGS + /** Render any hda warnings including: is deleted, is purged, is hidden. + * Overrides _render_warnings to include links to further actions (undelete, etc.)). + * @returns {Object} the templated urls + * @see HDABaseView#_render_warnings + */ _render_warnings : function(){ // jQ errs on building dom with whitespace - if there are no messages, trim -> '' return $( jQuery.trim( HDABaseView.templates.messages( @@ -28,9 +45,12 @@ ))); }, - // ................................................................................ display, edit attr, delete - // icon-button group for the common, most easily accessed actions - //NOTE: these are generally displayed for almost every hda state (tho poss. disabled) + // ......................................................................... 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 + * @returns {jQuery} rendered DOM + */ _render_titleButtons : function(){ // render the display, edit attr and delete icon-buttons var buttonDiv = $( '<div class="historyItemButtons"></div>' ); @@ -40,7 +60,9 @@ return buttonDiv; }, - // icon-button to edit the attributes (format, permissions, etc.) this hda + /** Render icon-button to edit the attributes (format, permissions, etc.) this hda. + * @returns {jQuery} rendered DOM + */ _render_editButton : function(){ // don't show edit while uploading //TODO??: error? @@ -76,7 +98,9 @@ return this.editButton.render().$el; }, - // icon-button to delete this hda + /** Render icon-button to delete this hda. + * @returns {jQuery} rendered DOM + */ _render_deleteButton : function(){ // don't show delete if... //TODO??: not viewable/accessible are essentially the same (not viewable set from accessible) @@ -103,8 +127,12 @@ return this.deleteButton.render().$el; }, - // ................................................................................ RENDER BODY - // render the data/metadata summary (format, size, misc info, etc.) + // ......................................................................... RENDER BODY + /** Render the data/metadata summary (format, size, misc info, etc.). + * Overrides _render_hdaSummary to include edit link in dbkey. + * @see HDABaseView#_render_hdaSummary + * @returns {jQuery} rendered DOM + */ _render_hdaSummary : function(){ var modelData = _.extend( this.model.toJSON(), { urls: this.urls } ); // if there's no dbkey and it's editable : pass a flag to the template to render a link to editing in the '?' @@ -116,8 +144,10 @@ return HDABaseView.templates.hdaSummary( modelData ); }, - // ................................................................................ primary actions - // icon-button to show the input and output (stdout/err) for the job that created this hda + // ......................................................................... primary actions + /** Render icon-button to report an error on this hda to the galaxy admin. + * @returns {jQuery} rendered DOM + */ _render_errButton : function(){ if( this.model.get( 'state' ) !== HistoryDatasetAssociation.STATES.ERROR ){ this.errButton = null; @@ -133,7 +163,9 @@ return this.errButton.render().$el; }, - // icon-button to re run the job that created this hda + /** Render icon-button to re-run the job that created this hda. + * @returns {jQuery} rendered DOM + */ _render_rerunButton : function(){ this.rerunButton = new IconButtonView({ model : new IconButton({ title : _l( 'Run this job again' ), @@ -144,8 +176,10 @@ return this.rerunButton.render().$el; }, - // build an icon-button or popupmenu based on the number of applicable visualizations - // also map button/popup clicks to viz setup functions + /** Render an icon-button or popupmenu based on the number of applicable visualizations + * and map button/popup clicks to viz setup functions. + * @returns {jQuery} rendered DOM + */ _render_visualizationsButton : function(){ var dbkey = this.model.get( 'dbkey' ), visualizations = this.model.get( 'visualizations' ), @@ -179,6 +213,7 @@ // Add dbkey to params if it exists. if( dbkey ){ params.dbkey = dbkey; } + /** @inner */ function create_viz_action( visualization ) { switch( visualization ){ case 'trackster': @@ -208,8 +243,11 @@ return $icon; }, - // ................................................................................ secondary actions - // secondary actions: currently tagging and annotation (if user is allowed) + // ......................................................................... secondary actions + /** Render secondary actions: currently tagging and annotation (if user is allowed). + * @param {Array} buttonRenderingFuncs array of rendering functions appending the results in order + * @returns {jQuery} rendered DOM + */ _render_secondaryActionButtons : function( buttonRenderingFuncs ){ // move to the right (same level as primary) var secondaryActionButtons = $( '<div/>' ), @@ -224,7 +262,9 @@ return secondaryActionButtons; }, - // icon-button to load and display tagging html + /** Render icon-button to load and display tagging html. + * @returns {jQuery} rendered DOM + */ //TODO: these should be a sub-MV _render_tagButton : function(){ //TODO: check for User @@ -243,7 +283,9 @@ return this.tagButton.render().$el; }, - // icon-button to load and display annotation html + /** Render icon-button to load and display annotation html. + * @returns {jQuery} rendered DOM + */ //TODO: these should be a sub-MV _render_annotateButton : function(){ //TODO: check for User @@ -261,10 +303,12 @@ return this.annotateButton.render().$el; }, - // ................................................................................ other elements + // ......................................................................... other elements + /** Render area to display tags. + * @returns {jQuery} rendered DOM + */ //TODO: into sub-MV //TODO: check for User - // render the area used to load tag display _render_tagArea : function(){ if( !this.urls.tags.set ){ return null; } //TODO: move to mvc/tags.js @@ -273,9 +317,11 @@ )); }, + /** Render area to display annotation. + * @returns {jQuery} rendered DOM + */ //TODO: into sub-MV //TODO: check for User - // render the area used to load annotation display _render_annotationArea : function(){ if( !this.urls.annotation.get ){ return null; } //TODO: move to mvc/annotations.js @@ -284,14 +330,23 @@ )); }, - // ................................................................................ state body renderers + // ......................................................................... state body renderers + /** Render an HDA whose job has failed. + * Overrides _render_body_error to prepend error report button to primary actions strip. + * @param {jQuery} parent DOM to which to append this body + * @see HDABaseView#_render_body_error + */ _render_body_error : function( parent ){ - // overridden to prepend error report button to primary actions strip HDABaseView.prototype._render_body_error.call( this, parent ); var primaryActions = parent.find( '#primary-actions-' + this.model.get( 'id' ) ); primaryActions.prepend( this._render_errButton() ); }, + /** Render an HDA that's done running and where everything worked. + * Overrides _render_body_ok to add tag/annotation functionality and additional primary actions + * @param {jQuery} parent DOM to which to append this body + * @see HDABaseView#_render_body_ok + */ _render_body_ok : function( parent ){ // most common state renderer and the most complicated parent.append( this._render_hdaSummary() ); @@ -327,15 +382,17 @@ parent.append( this._render_peek() ); }, - // ................................................................................ EVENTS + // ......................................................................... EVENTS + /** event map */ events : { 'click .historyItemTitle' : 'toggleBodyVisibility', 'click a.icon-button.tags' : 'loadAndDisplayTags', 'click a.icon-button.annotate' : 'loadAndDisplayAnnotation' }, - // ................................................................................ STATE CHANGES / MANIPULATION - // find the tag area and, if initial: (via ajax) load the html for displaying them; otherwise, unhide/hide + // ......................................................................... STATE CHANGES / MANIPULATION + /** Find the tag area and, if initial: load the html (via ajax) for displaying them; otherwise, unhide/hide + */ //TODO: into sub-MV loadAndDisplayTags : function( event ){ //BUG: broken with latest @@ -369,7 +426,8 @@ return false; }, - // find the annotation area and, if initial: (via ajax) load the html for displaying it; otherwise, unhide/hide + /** Find the annotation area and, if initial: load the html (via ajax) for displaying them; otherwise, unhide/hide + */ //TODO: into sub-MV loadAndDisplayAnnotation : function( event ){ //TODO: this is a drop in from history.mako - should use MV as well @@ -411,7 +469,8 @@ return false; }, - // ................................................................................ UTILTIY + // ......................................................................... UTILTIY + /** string rep */ toString : function(){ var modelString = ( this.model )?( this.model + '' ):( '(no model)' ); return 'HDAView(' + modelString + ')'; @@ -427,8 +486,12 @@ //============================================================================== //TODO: these belong somewhere else -//TODO: should be imported from scatterplot.js -//TODO: OR abstracted to 'load this in the galaxy_main frame' +/** Create scatterplot loading/set up function for use with the visualizations popupmenu. + * @param {String} url url (gen. 'visualizations') to which to append 'scatterplot' and params + * @param {Object} params parameters to convert to query string for splot page + * @returns function that loads the scatterplot + */ +//TODO: should be imported from scatterplot.js OR abstracted to 'load this in the galaxy_main frame' function create_scatterplot_action_fn( url, params ){ action = function() { var galaxy_main = $( window.parent.document ).find( 'iframe#galaxy_main' ), @@ -442,7 +505,12 @@ } // ----------------------------------------------------------------------------- -// Create trackster action function. +/** Create trackster loading/set up function for use with the visualizations popupmenu. + * Shows modal dialog for load old/create new. + * @param {String} vis_url visualizations url (gen. 'visualizations') + * @param {Object} dataset_params parameters to pass to trackster in the query string. + * @returns function that displays modal, loads trackster + */ //TODO: should be imported from trackster.js function create_trackster_action_fn(vis_url, dataset_params, dbkey) { return function() { diff -r 94627de6252824193ff0ff659807d17e59e4f94f -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e static/scripts/mvc/dataset/hda-model.js --- a/static/scripts/mvc/dataset/hda-model.js +++ b/static/scripts/mvc/dataset/hda-model.js @@ -2,15 +2,23 @@ // "../mvc/base-mvc" //], function(){ //============================================================================== -/** +/** @class (HDA) model for a Galaxy dataset + * related to a history. + * @name HistoryDatasetAssociation * + * @augments BaseModel + * @borrows LoggableMixin#logger as #logger + * @borrows LoggableMixin#log as #log + * @constructs */ -var HistoryDatasetAssociation = BaseModel.extend( LoggableMixin ).extend({ - // a single HDA model +var HistoryDatasetAssociation = BaseModel.extend( LoggableMixin ).extend( +/** @lends HistoryDatasetAssociation.prototype */{ - // uncomment this out see log messages + ///** logger used to record this.log messages, commonly set to console */ + //// comment this out to suppress log output //logger : console, + /** default attributes for a model */ defaults : { // ---these are part of an HDA proper: @@ -46,18 +54,22 @@ accessible : false }, - // fetch location of this history in the api + /** fetch location of this history in the api */ + urlRoot: 'api/histories/', url : function(){ //TODO: get this via url router return 'api/histories/' + this.get( 'history_id' ) + '/contents/' + this.get( 'id' ); }, - // (curr) only handles changing state of non-accessible hdas to STATES.NOT_VIEWABLE + /** Set up the model, determine if accessible, bind listeners + * @see Backbone.Model#initialize + */ //TODO:? use initialize (or validate) to check purged AND deleted -> purged XOR deleted initialize : function(){ this.log( this + '.initialize', this.attributes ); this.log( '\tparent history_id: ' + this.get( 'history_id' ) ); + // (curr) only handles changing state of non-accessible hdas to STATES.NOT_VIEWABLE //!! this state is not in trans.app.model.Dataset.states - set it here - //TODO: change to server side. if( !this.get( 'accessible' ) ){ @@ -81,12 +93,18 @@ //}); }, + /** Is this hda deleted or purged? + */ isDeletedOrPurged : function(){ return ( this.get( 'deleted' ) || this.get( 'purged' ) ); }, - // based on show_deleted, show_hidden (gen. from the container control), would this ds show in the list of ds's? - //TODO: too many visibles + /** based on show_deleted, show_hidden (gen. from the container control), + * would this ds show in the list of ds's? + * @param {Boolean} show_deleted are we showing deleted hdas? + * @param {Boolean} show_hidden are we showing hidden hdas? + */ + //TODO: too many 'visible's isVisible : function( show_deleted, show_hidden ){ var isVisible = true; if( ( !show_deleted ) @@ -100,7 +118,11 @@ return isVisible; }, - // 'ready' states are states where no processing (for the ds) is left to do on the server + /** Is this HDA in a 'ready' state; where 'Ready' states are states where no + * processing (for the ds) is left to do on the server. + * Currently: NEW, OK, EMPTY, FAILED_METADATA, NOT_VIEWABLE, DISCARDED, + * and ERROR + */ inReadyState : function(){ var state = this.get( 'state' ); return ( @@ -114,12 +136,15 @@ ); }, - // convenience fn to match hda.has_data + /** Convenience function to match hda.has_data. + */ hasData : function(){ //TODO:?? is this equivalent to all possible hda.has_data calls? return ( this.get( 'file_size' ) > 0 ); }, + /** String representation + */ toString : function(){ var nameAndId = this.get( 'id' ) || ''; if( this.get( 'name' ) ){ @@ -130,48 +155,83 @@ }); //------------------------------------------------------------------------------ +/** Class level map of possible HDA states to their string equivalents. + * A port of galaxy.model.Dataset.states. + */ HistoryDatasetAssociation.STATES = { + // NOT ready states + /** is uploading and not ready */ UPLOAD : 'upload', + /** the job that will produce the dataset queued in the runner */ QUEUED : 'queued', + /** the job that will produce the dataset is running */ RUNNING : 'running', + /** metadata for the dataset is being discovered/set */ SETTING_METADATA : 'setting_metadata', + // ready states + /** was created without a tool */ NEW : 'new', + /** has no data */ + EMPTY : 'empty', + /** has successfully completed running */ OK : 'ok', - EMPTY : 'empty', + /** metadata discovery/setting failed or errored (but otherwise ok) */ FAILED_METADATA : 'failed_metadata', + /** not accessible to the current user (i.e. due to permissions) */ NOT_VIEWABLE : 'noPermission', // not in trans.app.model.Dataset.states + /** deleted while uploading */ DISCARDED : 'discarded', + /** the tool producing this dataset failed */ ERROR : 'error' }; //============================================================================== -/** +/** @class Backbone collection of (HDA) models * + * @borrows LoggableMixin#logger as #logger + * @borrows LoggableMixin#log as #log + * @constructs */ -var HDACollection = Backbone.Collection.extend( LoggableMixin ).extend({ +var HDACollection = Backbone.Collection.extend( LoggableMixin ).extend( +/** @lends HDACollection.prototype */{ model : HistoryDatasetAssociation, - //logger : console, + ///** 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(){ //this.bind( 'all', function( event ){ // this.log( this + '', arguments ); //}); }, - // return the ids of every hda in this collection + /** Get the ids of every hda in this collection + * @returns array of encoded ids + */ ids : function(){ return this.map( function( item ){ return item.id; }); }, - // return an HDA collection containing every 'shown' hda based on show_deleted/hidden + /** Get every 'shown' hda in this collection based on show_deleted/hidden + * @param {Boolean} show_deleted are we showing deleted hdas? + * @param {Boolean} show_hidden are we showing hidden hdas? + * @returns array of hda models + * @see HistoryDatasetAssociation#isVisible + */ getVisible : function( show_deleted, show_hidden ){ return this.filter( function( item ){ return item.isVisible( show_deleted, show_hidden ); }); }, - // get a map where <possible hda state> : [ <list of hda ids in that state> ] + /** For each possible hda state, get an array of all hda ids in that state + * @returns a map of states -> hda ids + * @see HistoryDatasetAssociation#STATES + */ getStateLists : function(){ var stateLists = {}; _.each( _.values( HistoryDatasetAssociation.STATES ), function( state ){ @@ -184,7 +244,10 @@ return stateLists; }, - // returns the id of every hda still running (not in a ready state) + /** Get the id of every hda in this collection not in a 'ready' state (running). + * @returns an array of hda ids + * @see HistoryDatasetAssociation#inReadyState + */ running : function(){ var idList = []; this.each( function( item ){ @@ -195,7 +258,10 @@ return idList; }, - // update (fetch -> render) the hdas with the ids given + /** Update (fetch) the data of the hdas with the given ids. + * @param {String[]} ids an array of hda ids to update + * @see HistoryDatasetAssociation#fetch + */ update : function( ids ){ this.log( this + 'update:', ids ); @@ -208,6 +274,7 @@ }); }, + /** String representation. */ toString : function(){ return ( 'HDACollection(' + this.ids().join(',') + ')' ); } diff -r 94627de6252824193ff0ff659807d17e59e4f94f -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e static/scripts/mvc/history/history-model.js --- a/static/scripts/mvc/history/history-model.js +++ b/static/scripts/mvc/history/history-model.js @@ -2,13 +2,21 @@ // "../mvc/base-mvc" //], function(){ //============================================================================== -/** +/** @class Model for a Galaxy history resource - both a record of user + * tool use and a collection of the datasets those tools produced. + * @name History * + * @augments BaseModel + * @borrows LoggableMixin#logger as #logger + * @borrows LoggableMixin#log as #log + * @constructs */ -var History = BaseModel.extend( LoggableMixin ).extend({ +var History = BaseModel.extend( LoggableMixin ).extend( +/** @lends History.prototype */{ //TODO: bind change events from items and collection to this (itemLengths, states) - // uncomment this out see log messages + ///** logger used to record this.log messages, commonly set to console */ + //// comment this out to suppress log output //logger : console, // values from api (may need more) @@ -27,15 +35,23 @@ message : null }, + //TODO: hardcoded + urlRoot: 'api/histories/', + /** url for fetch */ url : function(){ // api location of history resource - //TODO: hardcoded return 'api/histories/' + this.get( 'id' ); }, + /** Set up the hdas collection + * @param {Object} initialSettings model data for this History + * @param {Object[]} initialHdas array of model data for this History's HDAs + * @see BaseModel#initialize + */ initialize : function( initialSettings, initialHdas ){ this.log( this + ".initialize:", initialSettings, initialHdas ); + /** HDACollection of the HDAs contained in this history. */ this.hdas = new HDACollection(); // if we've got hdas passed in the constructor, load them and set up updates if needed @@ -44,6 +60,7 @@ this.checkForUpdates(); } + // events //this.on( 'change', function( currModel, changedList ){ // this.log( this + ' has changed:', currModel, changedList ); //}); @@ -53,7 +70,11 @@ //}); }, - // get data via the api (alternative to sending options,hdas to initialize) + /** get data via the api (alternative to sending options, hdas to initialize) + * @param {String} historyId encoded id + * @param {Object[]} success + * @see BaseModel#initialize + */ //TODO: this needs work - move to more straightforward deferred // events: loaded, loaded:user, loaded:hdas loadFromApi : function( historyId, success ){ @@ -178,13 +199,22 @@ }); //============================================================================== -/** A collection of histories (per user or admin) - * (stub) currently unused +/** @class A collection of histories (per user). + * (stub) currently unused. + * @name HistoryCollection + * + * @borrows LoggableMixin#logger as #logger + * @borrows LoggableMixin#log as #log + * @constructs */ -var HistoryCollection = Backbone.Collection.extend( LoggableMixin ).extend({ +var HistoryCollection = Backbone.Collection.extend( LoggableMixin ).extend( +/** @lends HistoryCollection.prototype */{ model : History, - urlRoot : 'api/histories', - //logger : console + urlRoot : 'api/histories' + + ///** logger used to record this.log messages, commonly set to console */ + //// comment this out to suppress log output + //logger : console, }); //============================================================================== diff -r 94627de6252824193ff0ff659807d17e59e4f94f -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e static/scripts/mvc/history/history-panel.js --- a/static/scripts/mvc/history/history-panel.js +++ b/static/scripts/mvc/history/history-panel.js @@ -102,22 +102,43 @@ sorting, re-shuffling ============================================================================= */ -/** view for the HDACollection (as per current right hand panel) +/** @class View/Controller for the history model as used in the history + * panel (current right hand panel). + * @name HistoryPanel * + * @augments BaseView + * @borrows LoggableMixin#logger as #logger + * @borrows LoggableMixin#log as #log + * @constructs */ -var HistoryPanel = BaseView.extend( LoggableMixin ).extend({ +var HistoryPanel = BaseView.extend( LoggableMixin ).extend( +/** @lends HistoryPanel.prototype */{ - // uncomment this out see log messages + ///** logger used to record this.log messages, commonly set to console */ + //// comment this out to suppress log output //logger : console, // direct attachment to existing element el : 'body.historyPage', + /** which class to use for constructing the HDA views */ //HDAView : HDABaseView, HDAView : HDAEditView, - // init with the model, urlTemplates, set up storage, bind HDACollection events - //NOTE: this will create or load PersistantStorage keyed under 'HistoryView.<id>' - //pre: you'll need to pass in the urlTemplates (urlTemplates : { history : {...}, hda : {...} }) + /** event map + */ + events : { + 'click #history-tag' : 'loadAndDisplayTags' + }, + + // ......................................................................... SET UP + /** Set up the view, set up storage, bind listeners to HDACollection events + * @param {Object} attributes + * @config {Object} urlTemplates.history nested object containing url templates for this view + * @config {Object} urlTemplates.hda nested object containing url templates for HDAViews + * @throws 'needs urlTemplates' if urlTemplates.history or urlTemplates.hda aren't present + * @see PersistantStorage + * @see Backbone.View#initialize + */ initialize : function( attributes ){ this.log( this + '.initialize:', attributes ); @@ -128,81 +149,93 @@ if( !attributes.urlTemplates.history ){ throw( this + ' needs urlTemplates.history on initialize' ); } if( !attributes.urlTemplates.hda ){ throw( this + ' needs urlTemplates.hda on initialize' ); } this.urlTemplates = attributes.urlTemplates.history; + /** map web controller urls for history related actions */ this.hdaUrlTemplates = attributes.urlTemplates.hda; + this._setUpWebStorage( attributes.initiallyExpanded, attributes.show_deleted, attributes.show_hidden ); + + // bind events from the model's hda collection + // don't need to re-render entire model on all changes, just render disk size when it changes + //this.model.bind( 'change', this.render, this ); + this.model.bind( 'change:nice_size', this.updateHistoryDiskSize, this ); + this.model.hdas.bind( 'add', this.add, this ); + this.model.hdas.bind( 'reset', this.addAll, this ); + //this.bind( 'all', function(){ + // this.log( arguments ); + //}, this ); + + // set up instance vars + /** map of hda model ids to hda views */ + this.hdaViews = {}; + /** map web controller urls for history related actions */ + this.urls = {}; + }, + + /** Set up client side storage. Currently PersistanStorage keyed under 'HistoryPanel.<id>' + * @param {Object} initiallyExpanded + * @param {Boolean} show_deleted whether to show deleted HDAs (overrides stored) + * @param {Boolean} show_hidden + * @see PersistantStorage + */ + _setUpWebStorage : function( initiallyExpanded, show_deleted, show_hidden ){ + // data that needs to be persistant over page refreshes // (note the key function which uses the history id as well) this.storage = new PersistantStorage( 'HistoryView.' + this.model.get( 'id' ), { + //TODOL initiallyExpanded only works on first load right now expandedHdas : {}, show_deleted : false, show_hidden : false }); this.log( 'this.storage:', this.storage.get() ); - // get the show_deleted/hidden settings giving priority to values passed into initialize, but + // expanded Hdas is a map of hda.ids -> a boolean rep'ing whether this hda's body is expanded + // store any pre-expanded ids passed in + if( initiallyExpanded ){ + this.storage.set( 'exandedHdas', initiallyExpanded ); + } + + // get the show_deleted/hidden settings giving priority to values passed in, // using web storage otherwise - this.log( 'show_deleted:', attributes.show_deleted, 'show_hidden', attributes.show_hidden ); + //this.log( 'show_deleted:', show_deleted, 'show_hidden', show_hidden ); // if the page has specifically requested show_deleted/hidden, these will be either true or false // (as opposed to undefined, null) - and we give priority to that setting - if( ( attributes.show_deleted === true ) || ( attributes.show_deleted === false ) ){ + if( ( show_deleted === true ) || ( show_deleted === false ) ){ // save them to web storage - this.storage.set( 'show_deleted', attributes.show_deleted ); + this.storage.set( 'show_deleted', show_deleted ); } - if( ( attributes.show_hidden === true ) || ( attributes.show_hidden === false ) ){ - this.storage.set( 'show_hidden', attributes.show_hidden ); + if( ( show_hidden === true ) || ( show_hidden === false ) ){ + this.storage.set( 'show_hidden', show_hidden ); } - // pull show_deleted/hidden from the web storage if the page hasn't specified whether to show_deleted/hidden, + // if the page hasn't specified whether to show_deleted/hidden, pull show_deleted/hidden from the web storage this.show_deleted = this.storage.get( 'show_deleted' ); this.show_hidden = this.storage.get( 'show_hidden' ); - this.log( 'this.show_deleted:', this.show_deleted, 'show_hidden', this.show_hidden ); - this.log( '(now) this.storage:', this.storage.get() ); - - // bind events from the model's hda collection - //this.model.bind( 'change', this.render, this ); - this.model.bind( 'change:nice_size', this.updateHistoryDiskSize, this ); - - this.model.hdas.bind( 'add', this.add, this ); - this.model.hdas.bind( 'reset', this.addAll, this ); - this.model.hdas.bind( 'all', this.all, this ); - - //this.bind( 'all', function(){ - // this.log( arguments ); - //}, this ); - - // set up instance vars - this.hdaViews = {}; - this.urls = {}; + //this.log( 'this.show_deleted:', this.show_deleted, 'show_hidden', this.show_hidden ); + this.log( '(init\'d) this.storage:', this.storage.get() ); }, + /** Add an hda to this history's collection + * @param {HistoryDatasetAssociation} hda hda to add to the collection + */ add : function( hda ){ //console.debug( 'add.' + this, hda ); //TODO }, + /** Event hander to respond when hdas are reset + */ addAll : function(){ //console.debug( 'addAll.' + this ); // re render when all hdas are reset this.render(); }, - all : function( event ){ - //console.debug( 'allItemEvents.' + this, event ); - //...for which to do the debuggings - }, - - // render the urls for this view using urlTemplates and the model data - renderUrls : function( modelJson ){ - var historyView = this; - - historyView.urls = {}; - _.each( this.urlTemplates, function( urlTemplate, urlKey ){ - historyView.urls[ urlKey ] = _.template( urlTemplate, modelJson ); - }); - return historyView.urls; - }, - - // render urls, historyView body, and hdas (if any are shown), fade out, swap, fade in, set up behaviours - // events: rendered, rendered:initial + // ......................................................................... RENDERING + /** Render urls, historyPanel body, and hdas (if any are shown) + * @see Backbone.View#render + */ + /** event rendered triggered when the panel rendering is complete */ + /** event rendered:initial triggered when the FIRST panel rendering is complete */ render : function(){ var historyView = this, setUpQueueName = historyView.toString() + '.set-up', @@ -213,13 +246,13 @@ //console.debug( this + '.render, initialRender:', initialRender ); // render the urls and add them to the model json - modelJson.urls = this.renderUrls( modelJson ); + modelJson.urls = this._renderUrls( modelJson ); // render the main template, tooltips //NOTE: this is done before the items, since item views should handle theirs themselves newRender.append( HistoryPanel.templates.historyPanel( modelJson ) ); newRender.find( '.tooltip' ).tooltip({ placement: 'bottom' }); - this.setUpActionButton( newRender.find( '#history-action-popup' ) ); + this._setUpActionButton( newRender.find( '#history-action-popup' ) ); // render hda views (if any and any shown (show_deleted/hidden) //TODO: this seems too elaborate @@ -244,7 +277,7 @@ this.log( historyView + ' rendered:', historyView.$el ); //TODO: ideally, these would be set up before the fade in (can't because of async save text) - historyView.setUpBehaviours(); + historyView._setUpBehaviours(); if( initialRender ){ historyView.trigger( 'rendered:initial' ); @@ -258,7 +291,24 @@ return this; }, - setUpActionButton : function( $button ){ + /** Render the urls for this view using urlTemplates and the model data + * @param {Object} modelJson data from the model used to fill templates + */ + _renderUrls : function( modelJson ){ + var historyView = this; + + historyView.urls = {}; + _.each( this.urlTemplates, function( urlTemplate, urlKey ){ + historyView.urls[ urlKey ] = _.template( urlTemplate, modelJson ); + }); + return historyView.urls; + }, + + /** Set up history actions popup menu + * @param {jQuery} $button jQuery dom object to turn into the 'button' that activates the menu + * @see make_popupmenu (galaxy-base.js) + */ + _setUpActionButton : function( $button ){ var historyPanel = this, show_deletedText = ( this.storage.get( 'show_deleted' ) )?( 'Hide deleted' ):( 'Show deleted' ), show_hiddenText = ( this.storage.get( 'show_hidden' ) )?( 'Hide hidden' ):( 'Show hidden' ), @@ -270,7 +320,11 @@ make_popupmenu( $button, menuActions ); }, - // set up a view for each item to be shown, init with model and listeners, cache to map ( model.id : view ) + /** Set up/render a view for each HDA to be shown, init with model and listeners. + * HDA views are cached to the map this.hdaViews (using the model.id as key). + * @param {jQuery} $whereTo what dom element to prepend the HDA views to + * @returns the number of visible hda views + */ renderItems : function( $whereTo ){ this.hdaViews = {}; var historyView = this, @@ -290,7 +344,7 @@ expanded : expanded, urlTemplates : historyView.hdaUrlTemplates }); - historyView.setUpHdaListeners( historyView.hdaViews[ hdaId ] ); + historyView._setUpHdaListeners( historyView.hdaViews[ hdaId ] ); // render it (NOTE: reverse order, newest on top (prepend)) //TODO: by default send a reverse order list (although this may be more efficient - it's more confusing) @@ -299,21 +353,25 @@ return visibleHdas.length; }, - // set up HistoryView->HDAView listeners - setUpHdaListeners : function( hdaView ){ + /** Set up HistoryPanel listeners for HDAView events. Currently binds: + * HDAView#body-visible, HDAView#body-hidden to store expanded states + * @param {HDAView} hdaView HDAView (base or edit) to listen to + */ + _setUpHdaListeners : function( hdaView ){ var historyView = this; - // use storage to maintain a list of hdas whose bodies are expanded - hdaView.bind( 'body-visible', function( id ){ + // maintain a list of hdas whose bodies are expanded + hdaView.bind( 'body-expanded', function( id ){ historyView.storage.get( 'expandedHdas' ).set( id, true ); }); - hdaView.bind( 'body-hidden', function( id ){ + hdaView.bind( 'body-collapsed', function( id ){ historyView.storage.get( 'expandedHdas' ).deleteKey( id ); }); }, - // set up js/widget behaviours: tooltips, + /** Set up HistoryPanel js/widget behaviours + */ //TODO: these should be either sub-MVs, or handled by events - setUpBehaviours : function(){ + _setUpBehaviours : function(){ // anon users shouldn't have access to any of these if( !( this.model.get( 'user' ) && this.model.get( 'user' ).email ) ){ return; } @@ -337,40 +395,51 @@ this.urls.annotate, "new_annotation", 18, true, 4 ); }, - // update the history size display (curr. upper right of panel) + // ......................................................................... EVENTS + /** Update the history size display (curr. upper right of panel). + */ updateHistoryDiskSize : function(){ this.$el.find( '#history-size' ).text( this.model.get( 'nice_size' ) ); }, - events : { - 'click #history-tag' : 'loadAndDisplayTags' - }, - + /** Show the over quota message (which happens to be in the history panel). + */ //TODO: this seems more like a per user message than a history message; IOW, this doesn't belong here - showQuotaMessage : function( userData ){ + showQuotaMessage : function(){ var msg = this.$el.find( '#quota-message-container' ); //this.log( this + ' showing quota message:', msg, userData ); if( msg.is( ':hidden' ) ){ msg.slideDown( 'fast' ); } }, + /** Hide the over quota message (which happens to be in the history panel). + */ //TODO: this seems more like a per user message than a history message - hideQuotaMessage : function( userData ){ + hideQuotaMessage : function(){ var msg = this.$el.find( '#quota-message-container' ); //this.log( this + ' hiding quota message:', msg, userData ); if( !msg.is( ':hidden' ) ){ msg.slideUp( 'fast' ); } }, - toggleShowDeleted : function( x, y, z ){ + /** Handle the user toggling the deleted visibility by: + * (1) storing the new value in the persistant storage + * (2) re-rendering the history + */ + toggleShowDeleted : function(){ this.storage.set( 'show_deleted', !this.storage.get( 'show_deleted' ) ); this.render(); }, + /** Handle the user toggling the deleted visibility by: + * (1) storing the new value in the persistant storage + * (2) re-rendering the history + */ toggleShowHidden : function(){ this.storage.set( 'show_hidden', !this.storage.get( 'show_hidden' ) ); this.render(); }, - // collapse all hda bodies + /** Collapse all hda bodies and clear expandedHdas in the storage + */ hideAllHdaBodies : function(){ _.each( this.hdaViews, function( item ){ item.toggleBodyVisibility( null, false ); @@ -378,7 +447,8 @@ this.storage.set( 'expandedHdas', {} ); }, - // find the tag area and, if initial: (via ajax) load the html for displaying them; otherwise, unhide/hide + /** Find the tag area and, if initial: load the html (via ajax) for displaying them; otherwise, unhide/hide + */ //TODO: into sub-MV loadAndDisplayTags : function( event ){ this.log( this + '.loadAndDisplayTags', event ); @@ -414,13 +484,16 @@ return false; }, + // ......................................................................... MISC + /** Return a string rep of the history + */ toString : function(){ var nameString = this.model.get( 'name' ) || ''; - return 'HistoryView(' + nameString + ')'; + return 'HistoryPanel(' + nameString + ')'; } }); -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ TEMPLATES HistoryPanel.templates = { historyPanel : Handlebars.templates[ 'template-history-historyPanel' ] }; diff -r 94627de6252824193ff0ff659807d17e59e4f94f -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e static/scripts/mvc/user/user-model.js --- a/static/scripts/mvc/user/user-model.js +++ b/static/scripts/mvc/user/user-model.js @@ -1,15 +1,37 @@ -var User = BaseModel.extend( LoggableMixin ).extend({ - //logger : console, +/** @class Model for a Galaxy user (including anonymous users). + * @name User + * + * @augments BaseModel + * @borrows LoggableMixin#logger as #logger + * @borrows LoggableMixin#log as #log + * @constructs + */ +var User = BaseModel.extend( LoggableMixin ).extend( +/** @lends User.prototype */{ + + ///** logger used to record this.log messages, commonly set to console */ + //// comment this out to suppress log output + //logger : console, + + /** API location for this resource */ urlRoot : 'api/users', - defaults : { + /** Model defaults + * Note: don't check for anon-users with the username as the default is '(anonymous user)' + * a safer method is if( !user.get( 'email' ) ) -> anon user + */ + defaults : /** @lends User.prototype */{ id : null, username : '(' + _l( "anonymous user" ) + ')', email : "", total_disk_usage : 0, - nice_total_disk_usage : "0 bytes" + nice_total_disk_usage : "0 bytes", + quota_percent : null }, + /** Set up and bind events + * @param {Object} data Initial model data. + */ initialize : function( data ){ this.log( 'User.initialize:', data ); @@ -17,12 +39,25 @@ this.on( 'change', function( model, data ){ this.log( this + ' has changed:', model, data.changes ); }); }, - // events: loaded + isAnonymous : function(){ + return ( !this.get( 'email' ) ); + }, + + /** Load a user with the API using an id. + * If getting an anonymous user or no access to a user id, pass the User.CURRENT_ID_STR + * (e.g. 'current') and the API will return the current transaction's user data. + * @param {String} idOrCurrent encoded user id or the User.CURRENT_ID_STR + * @param {Object} options hash to pass to Backbone.Model.fetch. Can contain success, error fns. + * @fires loaded when the model has been loaded from the API, passing the newModel and AJAX response. + */ loadFromApi : function( idOrCurrent, options ){ idOrCurrent = idOrCurrent || User.CURRENT_ID_STR; + options = options || {}; var model = this, userFn = options.success; + + /** @ignore */ options.success = function( newModel, response ){ model.trigger( 'loaded', newModel, response ); if( userFn ){ userFn( newModel, response ); } @@ -35,6 +70,7 @@ return BaseModel.prototype.fetch.call( this, options ); }, + /** string representation */ toString : function(){ var userInfo = [ this.get( 'username' ) ]; if( this.get( 'id' ) ){ diff -r 94627de6252824193ff0ff659807d17e59e4f94f -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e static/scripts/mvc/user/user-quotameter.js --- a/static/scripts/mvc/user/user-quotameter.js +++ b/static/scripts/mvc/user/user-quotameter.js @@ -1,17 +1,27 @@ -// strange view that spans two frames: renders to two separate elements based on a User's disk usage: -// a quota/usage bar (curr. masthead), and -// an over-quota message (curr. history panel) +/** @class View to display a user's disk/storage usage + * either as a progress bar representing the percentage of a quota used + * or a simple text element displaying the human readable size used. + * @name UserQuotaMeter + * + * @augments BaseModel + * @borrows LoggableMixin#logger as #logger + * @borrows LoggableMixin#log as #log + * @constructs + */ +var UserQuotaMeter = BaseView.extend( LoggableMixin ).extend( +/** @lends UserQuotaMeter.prototype */{ + + ///** logger used to record this.log messages, commonly set to console */ + //// comment this out to suppress log output + //logger : console, -// for now, keep the view in the history panel (where the message is), but render ALSO to the masthead - -var UserQuotaMeter = BaseView.extend( LoggableMixin ).extend({ - //logger : console, - + /** Defaults for optional settings passed to initialize */ options : { warnAtPercent : 85, errorAtPercent : 100 }, + /** Set up, accept options, and bind events */ initialize : function( options ){ this.log( this + '.initialize:', options ); _.extend( this.options, options ); @@ -20,18 +30,29 @@ this.model.bind( 'change:quota_percent change:total_disk_usage', this.render, this ); }, + /** Re-load user model data from the api */ update : function( options ){ this.log( this + ' updating user data...', options ); this.model.loadFromApi( this.model.get( 'id' ), options ); return this; }, + /** Is the user over their quota (if there is one)? + * @returns {Boolean} true if over quota, false if no quota or under quota + */ isOverQuota : function(){ return ( this.model.get( 'quota_percent' ) !== null && this.model.get( 'quota_percent' ) >= this.options.errorAtPercent ); }, - // events: quota:over, quota:under, quota:under:approaching, quota:under:ok + /** Render the meter when they have an applicable quota. Will render as a progress bar + * with their percentage of that quota in text over the bar. + * @fires quota:over when user is over quota (>= this.errorAtPercent) + * @fires quota:under when user is under quota + * @fires quota:under:approaching when user is >= this.warnAtPercent of their quota + * @fires quota:under:ok when user is below this.warnAtPercent + * @returns {jQuery} the rendered meter + */ _render_quota : function(){ var modelJson = this.model.toJSON(), //prevPercent = this.model.previous( 'quota_percent' ), @@ -63,12 +84,20 @@ return meter; }, + /** Render the meter when the user has NO applicable quota. Will render as text + * showing the human readable sum storage their data is using. + * @returns {jQuery} the rendered text + */ _render_usage : function(){ var usage = $( UserQuotaMeter.templates.usage( this.model.toJSON() ) ); this.log( this + '.rendering usage:', usage ); return usage; }, + /** Render either the quota percentage meter or the human readable disk usage + * depending on whether the user model has quota info (quota_percent === null -> no quota) + * @returns {Object} this UserQuotaMeter + */ render : function(){ //this.log( this + '.rendering' ); var meterHtml = null; @@ -93,6 +122,9 @@ return 'UserQuotaMeter(' + this.model + ')'; } }); + + +//------------------------------------------------------------------------------ TEMPLATES UserQuotaMeter.templates = { quota : Handlebars.templates[ 'template-user-quotaMeter-quota' ], usage : Handlebars.templates[ 'template-user-quotaMeter-usage' ] diff -r 94627de6252824193ff0ff659807d17e59e4f94f -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e static/scripts/templates/compiled/template-history-historyPanel.js --- a/static/scripts/templates/compiled/template-history-historyPanel.js +++ b/static/scripts/templates/compiled/template-history-historyPanel.js @@ -193,7 +193,8 @@ return "Your history is empty. Click 'Get Data' on the left pane to start";} - buffer += "\n<div id=\"history-controls\">\n <div id=\"history-title-area\" class=\"historyLinks\">\n\n <div id=\"history-name-container\" style=\"float: left;\">\n "; + buffer += "<div id=\"history-controls\">\n <div id=\"history-title-area\" class=\"historyLinks\">\n\n "; + buffer += "\n <div id=\"history-name-container\" style=\"float: left;\">\n "; buffer += "\n "; stack1 = depth0.user; stack1 = stack1 == null || stack1 === false ? stack1 : stack1.email; @@ -205,7 +206,7 @@ else { stack1 = depth0.local; stack1 = typeof stack1 === functionType ? stack1() : stack1; } if (!helpers.local) { stack1 = blockHelperMissing.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(7, program7, data)}); } if(stack1 || stack1 === 0) { buffer += stack1; } - buffer += "\"\n href=\"javascript:void(0);\" style=\"float: right;\">\n <span class=\"ficon cog large\"></span>\n </a>\n <div style=\"clear: both;\"></div>\n </div>\n\n <div id=\"history-subtitle-area\">\n <div id=\"history-size\" style=\"float:left;\">"; + buffer += "\"\n href=\"javascript:void(0);\" style=\"float: right;\">\n <span class=\"ficon cogs large\"></span>\n </a>\n <div style=\"clear: both;\"></div>\n </div>\n\n <div id=\"history-subtitle-area\">\n <div id=\"history-size\" style=\"float:left;\">"; foundHelper = helpers.nice_size; if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{}}); } else { stack1 = depth0.nice_size; stack1 = typeof stack1 === functionType ? stack1() : stack1; } diff -r 94627de6252824193ff0ff659807d17e59e4f94f -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e static/scripts/templates/history-templates.html --- a/static/scripts/templates/history-templates.html +++ b/static/scripts/templates/history-templates.html @@ -19,7 +19,7 @@ <a id="history-action-popup" class="tooltip" title="{{#local}}Click to see more actions{{/local}}" href="javascript:void(0);" style="float: right;"> - <span class="ficon cog large"></span> + <span class="ficon cogs large"></span></a><div style="clear: both;"></div></div> diff -r 94627de6252824193ff0ff659807d17e59e4f94f -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e templates/root/alternate_history.mako --- a/templates/root/alternate_history.mako +++ b/templates/root/alternate_history.mako @@ -423,7 +423,6 @@ width: 90%; margin: -2px 0px -3px -4px; font-weight: bold; - font-size: 110%; color: black; } https://bitbucket.org/galaxy/galaxy-central/changeset/4e50648f6e5d/ changeset: 4e50648f6e5d user: carlfeberhard date: 2012-11-15 17:25:58 summary: pack scripts affected #: 9 files diff -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e -r 4e50648f6e5d015d253cb3c9e68dd731729b06f7 static/scripts/packed/mvc/base-mvc.js --- a/static/scripts/packed/mvc/base-mvc.js +++ b/static/scripts/packed/mvc/base-mvc.js @@ -1,1 +1,1 @@ -var BaseModel=Backbone.RelationalModel.extend({defaults:{name:null,hidden:false},show:function(){this.set("hidden",false)},hide:function(){this.set("hidden",true)},is_visible:function(){return !this.attributes.hidden}});var BaseView=Backbone.View.extend({initialize:function(){this.model.on("change:hidden",this.update_visible,this);this.update_visible()},update_visible:function(){if(this.model.attributes.hidden){this.$el.hide()}else{this.$el.show()}}});var LoggableMixin={logger:null,log:function(){if(this.logger){return this.logger.log.apply(this.logger,arguments)}return undefined}};var GalaxyLocalization=jQuery.extend({},{ALIAS_NAME:"_l",localizedStrings:{},setLocalizedString:function(b,a){var c=this;var d=function(f,e){if(f!==e){c.localizedStrings[f]=e}};if(jQuery.type(b)==="string"){d(b,a)}else{if(jQuery.type(b)==="object"){jQuery.each(b,function(e,f){d(e,f)})}else{throw ("Localization.setLocalizedString needs either a string or object as the first argument, given: "+b)}}},localize:function(a){return this.localizedStrings[a]||a},toString:function(){return"GalaxyLocalization"}});window[GalaxyLocalization.ALIAS_NAME]=function(a){return GalaxyLocalization.localize(a)};var PersistantStorage=function(g,d){if(!g){throw ("PersistantStorage needs storageKey argument")}d=d||{};var b=jQuery.jStorage.get,c=jQuery.jStorage.set,a=jQuery.jStorage.deleteKey;var e=function(i,h){i=i||{};h=h||null;return{get:function(j){if(j===undefined){return i}else{if(i.hasOwnProperty(j)){return(jQuery.type(i[j])==="object")?(new e(i[j],this)):(i[j])}}return undefined},set:function(j,k){i[j]=k;this.save();return this},deleteKey:function(j){delete i[j];this.save();return this},save:function(){return h.save()},toString:function(){return("StorageRecursionHelper("+i+")")}}};var f={};data=b(g);if(data===null){data=jQuery.extend(true,{},d);c(g,data)}f=new e(data);f.save=function(h){c(g,f.get())};f.destroy=function(){a(g)};f.toString=function(){return"PersistantStorage("+data+")"};return f}; \ No newline at end of file +var BaseModel=Backbone.RelationalModel.extend({defaults:{name:null,hidden:false},show:function(){this.set("hidden",false)},hide:function(){this.set("hidden",true)},is_visible:function(){return !this.attributes.hidden}});var BaseView=Backbone.View.extend({initialize:function(){this.model.on("change:hidden",this.update_visible,this);this.update_visible()},update_visible:function(){if(this.model.attributes.hidden){this.$el.hide()}else{this.$el.show()}}});var LoggableMixin={logger:null,log:function(){if(this.logger){return this.logger.log.apply(this.logger,arguments)}return undefined}};var GalaxyLocalization=jQuery.extend({},{ALIAS_NAME:"_l",localizedStrings:{},setLocalizedString:function(b,a){var c=this;var d=function(f,e){if(f!==e){c.localizedStrings[f]=e}};if(jQuery.type(b)==="string"){d(b,a)}else{if(jQuery.type(b)==="object"){jQuery.each(b,function(e,f){d(e,f)})}else{throw ("Localization.setLocalizedString needs either a string or object as the first argument, given: "+b)}}},localize:function(a){return this.localizedStrings[a]||a},toString:function(){return"GalaxyLocalization"}});window[GalaxyLocalization.ALIAS_NAME]=function(a){return GalaxyLocalization.localize(a)};var PersistantStorage=function(g,d){if(!g){throw ("PersistantStorage needs storageKey argument")}d=d||{};var b=jQuery.jStorage.get,c=jQuery.jStorage.set,a=jQuery.jStorage.deleteKey;function e(i,h){i=i||{};h=h||null;return{get:function(j){if(j===undefined){return i}else{if(i.hasOwnProperty(j)){return(jQuery.type(i[j])==="object")?(new e(i[j],this)):(i[j])}}return undefined},set:function(j,k){i[j]=k;this._save();return this},deleteKey:function(j){delete i[j];this._save();return this},_save:function(){return h._save()},toString:function(){return("StorageRecursionHelper("+i+")")}}}var f={};data=b(g);if(data===null){data=jQuery.extend(true,{},d);c(g,data)}f=new e(data);jQuery.extend(f,{_save:function(h){return c(g,f.get())},destroy:function(){return a(g)},toString:function(){return"PersistantStorage("+data+")"}});return f}; \ No newline at end of file diff -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e -r 4e50648f6e5d015d253cb3c9e68dd731729b06f7 static/scripts/packed/mvc/dataset/hda-base.js --- a/static/scripts/packed/mvc/dataset/hda-base.js +++ b/static/scripts/packed/mvc/dataset/hda-base.js @@ -1,1 +1,1 @@ -var HDABaseView=BaseView.extend(LoggableMixin).extend({tagName:"div",className:"historyItemContainer",initialize:function(a){this.log(this+".initialize:",a);this.defaultPrimaryActionButtonRenderers=[this._render_showParamsButton];if(!a.urlTemplates){throw ("HDAView needs urlTemplates on initialize")}this.urls=this.renderUrls(a.urlTemplates,this.model.toJSON());this.expanded=a.expanded||false;this.model.bind("change",this.render,this)},renderUrls:function(d,a){var b=this,c={};_.each(d,function(e,f){if(_.isObject(e)){c[f]=b.renderUrls(e,a)}else{if(f==="meta_download"){c[f]=b.renderMetaDownloadUrls(e,a)}else{c[f]=_.template(e,a)}}});return c},renderMetaDownloadUrls:function(b,a){return _.map(a.meta_files,function(c){return{url:_.template(b,{id:a.id,file_type:c.file_type}),file_type:c.file_type}})},render:function(){var b=this,e=this.model.get("id"),c=this.model.get("state"),a=$("<div/>").attr("id","historyItem-"+e),d=(this.$el.children().size()===0);this.$el.attr("id","historyItemContainer-"+e);a.addClass("historyItemWrapper").addClass("historyItem").addClass("historyItem-"+c);a.append(this._render_warnings());a.append(this._render_titleBar());this.body=$(this._render_body());a.append(this.body);make_popup_menus(a);a.find(".tooltip").tooltip({placement:"bottom"});this.$el.fadeOut("fast",function(){b.$el.children().remove();b.$el.append(a).fadeIn("fast",function(){b.log(b+" rendered:",b.$el);var f="rendered";if(d){f+=":initial"}else{if(b.model.inReadyState()){f+=":ready"}}b.trigger(f)})});return this},_render_warnings:function(){return $(jQuery.trim(HDABaseView.templates.messages(this.model.toJSON())))},_render_titleBar:function(){var a=$('<div class="historyItemTitleBar" style="overflow: hidden"></div>');a.append(this._render_titleButtons());a.append('<span class="state-icon"></span>');a.append(this._render_titleLink());return a},_render_titleButtons:function(){var a=$('<div class="historyItemButtons"></div>');a.append(this._render_displayButton());return a},_render_displayButton:function(){if((!this.model.inReadyState())||(this.model.get("state")===HistoryDatasetAssociation.STATES.ERROR)||(this.model.get("state")===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){this.displayButton=null;return null}var a={icon_class:"display",target:"galaxy_main"};if(this.model.get("purged")){a.enabled=false;a.title=_l("Cannot display datasets removed from disk")}else{a.title=_l("Display data in browser");a.href=this.urls.display}this.displayButton=new IconButtonView({model:new IconButton(a)});return this.displayButton.render().$el},_render_titleLink:function(){return $(jQuery.trim(HDABaseView.templates.titleLink(_.extend(this.model.toJSON(),{urls:this.urls}))))},_render_hdaSummary:function(){var a=_.extend(this.model.toJSON(),{urls:this.urls});return HDABaseView.templates.hdaSummary(a)},_render_primaryActionButtons:function(c){var a=this,b=$("<div/>").attr("id","primary-actions-"+this.model.get("id"));_.each(c,function(d){b.append(d.call(a))});return b},_render_downloadButton:function(){if(this.model.get("purged")||!this.model.hasData()){return null}var a=HDABaseView.templates.downloadLinks(_.extend(this.model.toJSON(),{urls:this.urls}));return $(a)},_render_showParamsButton:function(){this.showParamsButton=new IconButtonView({model:new IconButton({title:_l("View details"),href:this.urls.show_params,target:"galaxy_main",icon_class:"information"})});return this.showParamsButton.render().$el},_render_displayApps:function(){if(!this.model.hasData()){return null}var a=$("<div/>").addClass("display-apps");if(!_.isEmpty(this.model.get("display_types"))){a.append(HDABaseView.templates.displayApps({displayApps:this.model.get("display_types")}))}if(!_.isEmpty(this.model.get("display_apps"))){a.append(HDABaseView.templates.displayApps({displayApps:this.model.get("display_apps")}))}return a},_render_peek:function(){if(!this.model.get("peek")){return null}return $("<div/>").append($("<pre/>").attr("id","peek"+this.model.get("id")).addClass("peek").append(this.model.get("peek")))},_render_body_not_viewable:function(a){a.append($("<div>"+_l("You do not have permission to view dataset")+".</div>"))},_render_body_uploading:function(a){a.append($("<div>"+_l("Dataset is uploading")+"</div>"))},_render_body_queued:function(a){a.append($("<div>"+_l("Job is waiting to run")+".</div>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_running:function(a){a.append("<div>"+_l("Job is currently running")+".</div>");a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_error:function(a){if(!this.model.get("purged")){a.append($("<div>"+this.model.get("misc_blurb")+"</div>"))}a.append((_l("An error occurred running this job")+": <i>"+$.trim(this.model.get("misc_info"))+"</i>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers.concat([this._render_downloadButton])))},_render_body_discarded:function(a){a.append("<div>"+_l("The job creating this dataset was cancelled before completion")+".</div>");a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_setting_metadata:function(a){a.append($("<div>"+_l("Metadata is being auto-detected")+".</div>"))},_render_body_empty:function(a){a.append($("<div>"+_l("No data")+": <i>"+this.model.get("misc_blurb")+"</i></div>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_failed_metadata:function(a){a.append($(HDABaseView.templates.failedMetadata(this.model.toJSON())));this._render_body_ok(a)},_render_body_ok:function(a){a.append(this._render_hdaSummary());if(this.model.isDeletedOrPurged()){a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton]));return}a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton]));a.append('<div class="clear"/>');a.append(this._render_displayApps());a.append(this._render_peek())},_render_body:function(){var a=$("<div/>").attr("id","info-"+this.model.get("id")).addClass("historyItemBody").attr("style","display: block");switch(this.model.get("state")){case HistoryDatasetAssociation.STATES.NOT_VIEWABLE:this._render_body_not_viewable(a);break;case HistoryDatasetAssociation.STATES.UPLOAD:this._render_body_uploading(a);break;case HistoryDatasetAssociation.STATES.QUEUED:this._render_body_queued(a);break;case HistoryDatasetAssociation.STATES.RUNNING:this._render_body_running(a);break;case HistoryDatasetAssociation.STATES.ERROR:this._render_body_error(a);break;case HistoryDatasetAssociation.STATES.DISCARDED:this._render_body_discarded(a);break;case HistoryDatasetAssociation.STATES.SETTING_METADATA:this._render_body_setting_metadata(a);break;case HistoryDatasetAssociation.STATES.EMPTY:this._render_body_empty(a);break;case HistoryDatasetAssociation.STATES.FAILED_METADATA:this._render_body_failed_metadata(a);break;case HistoryDatasetAssociation.STATES.OK:this._render_body_ok(a);break;default:a.append($('<div>Error: unknown dataset state "'+state+'".</div>'))}a.append('<div style="clear: both"></div>');if(this.expanded){a.show()}else{a.hide()}return a},events:{"click .historyItemTitle":"toggleBodyVisibility"},toggleBodyVisibility:function(c,a){var b=this,d=this.$el.find(".historyItemBody");a=(a===undefined)?(!d.is(":visible")):(a);if(a){d.slideDown("fast",function(){b.trigger("body-visible",b.model.get("id"))})}else{d.slideUp("fast",function(){b.trigger("body-hidden",b.model.get("id"))})}},toString:function(){var a=(this.model)?(this.model+""):("(no model)");return"HDABaseView("+a+")"}});HDABaseView.templates={warningMsg:Handlebars.templates["template-warningmessagesmall"],messages:Handlebars.templates["template-hda-warning-messages"],titleLink:Handlebars.templates["template-hda-titleLink"],hdaSummary:Handlebars.templates["template-hda-hdaSummary"],downloadLinks:Handlebars.templates["template-hda-downloadLinks"],failedMetadata:Handlebars.templates["template-hda-failedMetaData"],displayApps:Handlebars.templates["template-hda-displayApps"]}; \ No newline at end of file +var HDABaseView=BaseView.extend(LoggableMixin).extend({tagName:"div",className:"historyItemContainer",initialize:function(a){this.log(this+".initialize:",a);this.defaultPrimaryActionButtonRenderers=[this._render_showParamsButton];if(!a.urlTemplates){throw ("HDAView needs urlTemplates on initialize")}this.urls=this._renderUrls(a.urlTemplates,this.model.toJSON());this.expanded=a.expanded||false;this.model.bind("change",this.render,this)},_renderUrls:function(d,a){var b=this,c={};_.each(d,function(e,f){if(_.isObject(e)){c[f]=b._renderUrls(e,a)}else{if(f==="meta_download"){c[f]=b._renderMetaDownloadUrls(e,a)}else{c[f]=_.template(e,a)}}});return c},_renderMetaDownloadUrls:function(b,a){return _.map(a.meta_files,function(c){return{url:_.template(b,{id:a.id,file_type:c.file_type}),file_type:c.file_type}})},render:function(){var b=this,e=this.model.get("id"),c=this.model.get("state"),a=$("<div/>").attr("id","historyItem-"+e),d=(this.$el.children().size()===0);this.$el.attr("id","historyItemContainer-"+e);a.addClass("historyItemWrapper").addClass("historyItem").addClass("historyItem-"+c);a.append(this._render_warnings());a.append(this._render_titleBar());this.body=$(this._render_body());a.append(this.body);make_popup_menus(a);a.find(".tooltip").tooltip({placement:"bottom"});this.$el.fadeOut("fast",function(){b.$el.children().remove();b.$el.append(a).fadeIn("fast",function(){b.log(b+" rendered:",b.$el);var f="rendered";if(d){f+=":initial"}else{if(b.model.inReadyState()){f+=":ready"}}b.trigger(f)})});return this},_render_warnings:function(){return $(jQuery.trim(HDABaseView.templates.messages(this.model.toJSON())))},_render_titleBar:function(){var a=$('<div class="historyItemTitleBar" style="overflow: hidden"></div>');a.append(this._render_titleButtons());a.append('<span class="state-icon"></span>');a.append(this._render_titleLink());return a},_render_titleButtons:function(){var a=$('<div class="historyItemButtons"></div>');a.append(this._render_displayButton());return a},_render_displayButton:function(){if((!this.model.inReadyState())||(this.model.get("state")===HistoryDatasetAssociation.STATES.ERROR)||(this.model.get("state")===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){this.displayButton=null;return null}var a={icon_class:"display",target:"galaxy_main"};if(this.model.get("purged")){a.enabled=false;a.title=_l("Cannot display datasets removed from disk")}else{a.title=_l("Display data in browser");a.href=this.urls.display}this.displayButton=new IconButtonView({model:new IconButton(a)});return this.displayButton.render().$el},_render_titleLink:function(){return $(jQuery.trim(HDABaseView.templates.titleLink(_.extend(this.model.toJSON(),{urls:this.urls}))))},_render_hdaSummary:function(){var a=_.extend(this.model.toJSON(),{urls:this.urls});return HDABaseView.templates.hdaSummary(a)},_render_primaryActionButtons:function(c){var a=this,b=$("<div/>").attr("id","primary-actions-"+this.model.get("id"));_.each(c,function(d){b.append(d.call(a))});return b},_render_downloadButton:function(){if(this.model.get("purged")||!this.model.hasData()){return null}var a=HDABaseView.templates.downloadLinks(_.extend(this.model.toJSON(),{urls:this.urls}));return $(a)},_render_showParamsButton:function(){this.showParamsButton=new IconButtonView({model:new IconButton({title:_l("View details"),href:this.urls.show_params,target:"galaxy_main",icon_class:"information"})});return this.showParamsButton.render().$el},_render_displayApps:function(){if(!this.model.hasData()){return null}var a=$("<div/>").addClass("display-apps");if(!_.isEmpty(this.model.get("display_types"))){a.append(HDABaseView.templates.displayApps({displayApps:this.model.get("display_types")}))}if(!_.isEmpty(this.model.get("display_apps"))){a.append(HDABaseView.templates.displayApps({displayApps:this.model.get("display_apps")}))}return a},_render_peek:function(){if(!this.model.get("peek")){return null}return $("<div/>").append($("<pre/>").attr("id","peek"+this.model.get("id")).addClass("peek").append(this.model.get("peek")))},_render_body:function(){var a=$("<div/>").attr("id","info-"+this.model.get("id")).addClass("historyItemBody").attr("style","display: block");switch(this.model.get("state")){case HistoryDatasetAssociation.STATES.NOT_VIEWABLE:this._render_body_not_viewable(a);break;case HistoryDatasetAssociation.STATES.UPLOAD:this._render_body_uploading(a);break;case HistoryDatasetAssociation.STATES.QUEUED:this._render_body_queued(a);break;case HistoryDatasetAssociation.STATES.RUNNING:this._render_body_running(a);break;case HistoryDatasetAssociation.STATES.ERROR:this._render_body_error(a);break;case HistoryDatasetAssociation.STATES.DISCARDED:this._render_body_discarded(a);break;case HistoryDatasetAssociation.STATES.SETTING_METADATA:this._render_body_setting_metadata(a);break;case HistoryDatasetAssociation.STATES.EMPTY:this._render_body_empty(a);break;case HistoryDatasetAssociation.STATES.FAILED_METADATA:this._render_body_failed_metadata(a);break;case HistoryDatasetAssociation.STATES.OK:this._render_body_ok(a);break;default:a.append($('<div>Error: unknown dataset state "'+state+'".</div>'))}a.append('<div style="clear: both"></div>');if(this.expanded){a.show()}else{a.hide()}return a},_render_body_not_viewable:function(a){a.append($("<div>"+_l("You do not have permission to view dataset")+".</div>"))},_render_body_uploading:function(a){a.append($("<div>"+_l("Dataset is uploading")+"</div>"))},_render_body_queued:function(a){a.append($("<div>"+_l("Job is waiting to run")+".</div>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_running:function(a){a.append("<div>"+_l("Job is currently running")+".</div>");a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_error:function(a){if(!this.model.get("purged")){a.append($("<div>"+this.model.get("misc_blurb")+"</div>"))}a.append((_l("An error occurred running this job")+": <i>"+$.trim(this.model.get("misc_info"))+"</i>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers.concat([this._render_downloadButton])))},_render_body_discarded:function(a){a.append("<div>"+_l("The job creating this dataset was cancelled before completion")+".</div>");a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_setting_metadata:function(a){a.append($("<div>"+_l("Metadata is being auto-detected")+".</div>"))},_render_body_empty:function(a){a.append($("<div>"+_l("No data")+": <i>"+this.model.get("misc_blurb")+"</i></div>"));a.append(this._render_primaryActionButtons(this.defaultPrimaryActionButtonRenderers))},_render_body_failed_metadata:function(a){a.append($(HDABaseView.templates.failedMetadata(this.model.toJSON())));this._render_body_ok(a)},_render_body_ok:function(a){a.append(this._render_hdaSummary());if(this.model.isDeletedOrPurged()){a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton]));return}a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton]));a.append('<div class="clear"/>');a.append(this._render_displayApps());a.append(this._render_peek())},events:{"click .historyItemTitle":"toggleBodyVisibility"},toggleBodyVisibility:function(c,a){var b=this,d=this.$el.find(".historyItemBody");a=(a===undefined)?(!d.is(":visible")):(a);if(a){d.slideDown("fast",function(){b.trigger("body-expanded",b.model.get("id"))})}else{d.slideUp("fast",function(){b.trigger("body-collapsed",b.model.get("id"))})}},toString:function(){var a=(this.model)?(this.model+""):("(no model)");return"HDABaseView("+a+")"}});HDABaseView.templates={warningMsg:Handlebars.templates["template-warningmessagesmall"],messages:Handlebars.templates["template-hda-warning-messages"],titleLink:Handlebars.templates["template-hda-titleLink"],hdaSummary:Handlebars.templates["template-hda-hdaSummary"],downloadLinks:Handlebars.templates["template-hda-downloadLinks"],failedMetadata:Handlebars.templates["template-hda-failedMetaData"],displayApps:Handlebars.templates["template-hda-displayApps"]}; \ No newline at end of file diff -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e -r 4e50648f6e5d015d253cb3c9e68dd731729b06f7 static/scripts/packed/mvc/dataset/hda-edit.js --- a/static/scripts/packed/mvc/dataset/hda-edit.js +++ b/static/scripts/packed/mvc/dataset/hda-edit.js @@ -1,1 +1,1 @@ -var HDAEditView=HDABaseView.extend({initialize:function(a){HDABaseView.prototype.initialize.call(this,a);this.defaultPrimaryActionButtonRenderers=[this._render_showParamsButton,this._render_rerunButton]},_render_warnings:function(){return $(jQuery.trim(HDABaseView.templates.messages(_.extend(this.model.toJSON(),{urls:this.urls}))))},_render_titleButtons:function(){var a=$('<div class="historyItemButtons"></div>');a.append(this._render_displayButton());a.append(this._render_editButton());a.append(this._render_deleteButton());return a},_render_editButton:function(){if((this.model.get("state")===HistoryDatasetAssociation.STATES.UPLOAD)||(this.model.get("state")===HistoryDatasetAssociation.STATES.ERROR)||(this.model.get("state")===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){this.editButton=null;return null}var c=this.model.get("purged"),a=this.model.get("deleted"),b={title:_l("Edit Attributes"),href:this.urls.edit,target:"galaxy_main",icon_class:"edit"};if(a||c){b.enabled=false;if(c){b.title=_l("Cannot edit attributes of datasets removed from disk")}else{if(a){b.title=_l("Undelete dataset to edit attributes")}}}this.editButton=new IconButtonView({model:new IconButton(b)});return this.editButton.render().$el},_render_deleteButton:function(){if((this.model.get("state")===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){this.deleteButton=null;return null}var a={title:_l("Delete"),href:this.urls["delete"],id:"historyItemDeleter-"+this.model.get("id"),icon_class:"delete"};if(this.model.get("deleted")||this.model.get("purged")){a={title:_l("Dataset is already deleted"),icon_class:"delete",enabled:false}}this.deleteButton=new IconButtonView({model:new IconButton(a)});return this.deleteButton.render().$el},_render_hdaSummary:function(){var a=_.extend(this.model.toJSON(),{urls:this.urls});if(this.model.get("metadata_dbkey")==="?"&&!this.model.isDeletedOrPurged()){_.extend(a,{dbkey_unknown_and_editable:true})}return HDABaseView.templates.hdaSummary(a)},_render_errButton:function(){if(this.model.get("state")!==HistoryDatasetAssociation.STATES.ERROR){this.errButton=null;return null}this.errButton=new IconButtonView({model:new IconButton({title:_l("View or report this error"),href:this.urls.report_error,target:"galaxy_main",icon_class:"bug"})});return this.errButton.render().$el},_render_rerunButton:function(){this.rerunButton=new IconButtonView({model:new IconButton({title:_l("Run this job again"),href:this.urls.rerun,target:"galaxy_main",icon_class:"arrow-circle"})});return this.rerunButton.render().$el},_render_visualizationsButton:function(){var c=this.model.get("dbkey"),a=this.model.get("visualizations"),f=this.urls.visualization,d={},g={dataset_id:this.model.get("id"),hda_ldda:"hda"};if(!(this.model.hasData())||!(a&&a.length)||!(f)){this.visualizationsButton=null;return null}this.visualizationsButton=new IconButtonView({model:new IconButton({title:_l("Visualize"),href:f,icon_class:"chart_curve"})});var b=this.visualizationsButton.render().$el;b.addClass("visualize-icon");if(c){g.dbkey=c}function e(h){switch(h){case"trackster":return create_trackster_action_fn(f,g,c);case"scatterplot":return create_scatterplot_action_fn(f,g);default:return function(){window.parent.location=f+"/"+h+"?"+$.param(g)}}}if(a.length===1){b.attr("title",a[0]);b.click(e(a[0]))}else{_.each(a,function(i){var h=i.charAt(0).toUpperCase()+i.slice(1);d[_l(h)]=e(i)});make_popupmenu(b,d)}return b},_render_secondaryActionButtons:function(b){var c=$("<div/>"),a=this;c.attr("style","float: right;").attr("id","secondary-actions-"+this.model.get("id"));_.each(b,function(d){c.append(d.call(a))});return c},_render_tagButton:function(){if(!(this.model.hasData())||(!this.urls.tags.get)){this.tagButton=null;return null}this.tagButton=new IconButtonView({model:new IconButton({title:_l("Edit dataset tags"),target:"galaxy_main",href:this.urls.tags.get,icon_class:"tags"})});return this.tagButton.render().$el},_render_annotateButton:function(){if(!(this.model.hasData())||(!this.urls.annotation.get)){this.annotateButton=null;return null}this.annotateButton=new IconButtonView({model:new IconButton({title:_l("Edit dataset annotation"),target:"galaxy_main",icon_class:"annotate"})});return this.annotateButton.render().$el},_render_tagArea:function(){if(!this.urls.tags.set){return null}return $(HDAEditView.templates.tagArea(_.extend(this.model.toJSON(),{urls:this.urls})))},_render_annotationArea:function(){if(!this.urls.annotation.get){return null}return $(HDAEditView.templates.annotationArea(_.extend(this.model.toJSON(),{urls:this.urls})))},_render_body_error:function(a){HDABaseView.prototype._render_body_error.call(this,a);var b=a.find("#primary-actions-"+this.model.get("id"));b.prepend(this._render_errButton())},_render_body_ok:function(a){a.append(this._render_hdaSummary());if(this.model.isDeletedOrPurged()){a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton,this._render_rerunButton]));return}a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton,this._render_rerunButton,this._render_visualizationsButton]));a.append(this._render_secondaryActionButtons([this._render_tagButton,this._render_annotateButton]));a.append('<div class="clear"/>');a.append(this._render_tagArea());a.append(this._render_annotationArea());a.append(this._render_displayApps());a.append(this._render_peek())},events:{"click .historyItemTitle":"toggleBodyVisibility","click a.icon-button.tags":"loadAndDisplayTags","click a.icon-button.annotate":"loadAndDisplayAnnotation"},loadAndDisplayTags:function(b){this.log(this+".loadAndDisplayTags",b);var c=this.$el.find(".tag-area"),a=c.find(".tag-elt");if(c.is(":hidden")){if(!jQuery.trim(a.html())){$.ajax({url:this.urls.tags.get,error:function(){alert(_l("Tagging failed"))},success:function(d){a.html(d);a.find(".tooltip").tooltip();c.slideDown("fast")}})}else{c.slideDown("fast")}}else{c.slideUp("fast")}return false},loadAndDisplayAnnotation:function(b){this.log(this+".loadAndDisplayAnnotation",b);var d=this.$el.find(".annotation-area"),c=d.find(".annotation-elt"),a=this.urls.annotation.set;if(d.is(":hidden")){if(!jQuery.trim(c.html())){$.ajax({url:this.urls.annotation.get,error:function(){alert(_l("Annotations failed"))},success:function(e){if(e===""){e="<em>"+_l("Describe or add notes to dataset")+"</em>"}c.html(e);d.find(".tooltip").tooltip();async_save_text(c.attr("id"),c.attr("id"),a,"new_annotation",18,true,4);d.slideDown("fast")}})}else{d.slideDown("fast")}}else{d.slideUp("fast")}return false},toString:function(){var a=(this.model)?(this.model+""):("(no model)");return"HDAView("+a+")"}});HDAEditView.templates={tagArea:Handlebars.templates["template-hda-tagArea"],annotationArea:Handlebars.templates["template-hda-annotationArea"]};function create_scatterplot_action_fn(a,b){action=function(){var d=$(window.parent.document).find("iframe#galaxy_main"),c=a+"/scatterplot?"+$.param(b);d.attr("src",c);$("div.popmenu-wrapper").remove();return false};return action}function create_trackster_action_fn(a,c,b){return function(){var d={};if(b){d.dbkey=b}$.ajax({url:a+"/list_tracks?f-"+$.param(d),dataType:"html",error:function(){alert(_l("Could not add this dataset to browser")+".")},success:function(e){var f=window.parent;f.show_modal(_l("View Data in a New or Saved Visualization"),"",{Cancel:function(){f.hide_modal()},"View in saved visualization":function(){f.show_modal(_l("Add Data to Saved Visualization"),e,{Cancel:function(){f.hide_modal()},"Add to visualization":function(){$(f.document).find("input[name=id]:checked").each(function(){var g=$(this).val();c.id=g;f.location=a+"/trackster?"+$.param(c)})}})},"View in new visualization":function(){f.location=a+"/trackster?"+$.param(c)}})}});return false}}; \ No newline at end of file +var HDAEditView=HDABaseView.extend(LoggableMixin).extend({initialize:function(a){HDABaseView.prototype.initialize.call(this,a);this.defaultPrimaryActionButtonRenderers=[this._render_showParamsButton,this._render_rerunButton]},_render_warnings:function(){return $(jQuery.trim(HDABaseView.templates.messages(_.extend(this.model.toJSON(),{urls:this.urls}))))},_render_titleButtons:function(){var a=$('<div class="historyItemButtons"></div>');a.append(this._render_displayButton());a.append(this._render_editButton());a.append(this._render_deleteButton());return a},_render_editButton:function(){if((this.model.get("state")===HistoryDatasetAssociation.STATES.UPLOAD)||(this.model.get("state")===HistoryDatasetAssociation.STATES.ERROR)||(this.model.get("state")===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){this.editButton=null;return null}var c=this.model.get("purged"),a=this.model.get("deleted"),b={title:_l("Edit Attributes"),href:this.urls.edit,target:"galaxy_main",icon_class:"edit"};if(a||c){b.enabled=false;if(c){b.title=_l("Cannot edit attributes of datasets removed from disk")}else{if(a){b.title=_l("Undelete dataset to edit attributes")}}}this.editButton=new IconButtonView({model:new IconButton(b)});return this.editButton.render().$el},_render_deleteButton:function(){if((this.model.get("state")===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(!this.model.get("accessible"))){this.deleteButton=null;return null}var a={title:_l("Delete"),href:this.urls["delete"],id:"historyItemDeleter-"+this.model.get("id"),icon_class:"delete"};if(this.model.get("deleted")||this.model.get("purged")){a={title:_l("Dataset is already deleted"),icon_class:"delete",enabled:false}}this.deleteButton=new IconButtonView({model:new IconButton(a)});return this.deleteButton.render().$el},_render_hdaSummary:function(){var a=_.extend(this.model.toJSON(),{urls:this.urls});if(this.model.get("metadata_dbkey")==="?"&&!this.model.isDeletedOrPurged()){_.extend(a,{dbkey_unknown_and_editable:true})}return HDABaseView.templates.hdaSummary(a)},_render_errButton:function(){if(this.model.get("state")!==HistoryDatasetAssociation.STATES.ERROR){this.errButton=null;return null}this.errButton=new IconButtonView({model:new IconButton({title:_l("View or report this error"),href:this.urls.report_error,target:"galaxy_main",icon_class:"bug"})});return this.errButton.render().$el},_render_rerunButton:function(){this.rerunButton=new IconButtonView({model:new IconButton({title:_l("Run this job again"),href:this.urls.rerun,target:"galaxy_main",icon_class:"arrow-circle"})});return this.rerunButton.render().$el},_render_visualizationsButton:function(){var c=this.model.get("dbkey"),a=this.model.get("visualizations"),f=this.urls.visualization,d={},g={dataset_id:this.model.get("id"),hda_ldda:"hda"};if(!(this.model.hasData())||!(a&&a.length)||!(f)){this.visualizationsButton=null;return null}this.visualizationsButton=new IconButtonView({model:new IconButton({title:_l("Visualize"),href:f,icon_class:"chart_curve"})});var b=this.visualizationsButton.render().$el;b.addClass("visualize-icon");if(c){g.dbkey=c}function e(h){switch(h){case"trackster":return create_trackster_action_fn(f,g,c);case"scatterplot":return create_scatterplot_action_fn(f,g);default:return function(){window.parent.location=f+"/"+h+"?"+$.param(g)}}}if(a.length===1){b.attr("title",a[0]);b.click(e(a[0]))}else{_.each(a,function(i){var h=i.charAt(0).toUpperCase()+i.slice(1);d[_l(h)]=e(i)});make_popupmenu(b,d)}return b},_render_secondaryActionButtons:function(b){var c=$("<div/>"),a=this;c.attr("style","float: right;").attr("id","secondary-actions-"+this.model.get("id"));_.each(b,function(d){c.append(d.call(a))});return c},_render_tagButton:function(){if(!(this.model.hasData())||(!this.urls.tags.get)){this.tagButton=null;return null}this.tagButton=new IconButtonView({model:new IconButton({title:_l("Edit dataset tags"),target:"galaxy_main",href:this.urls.tags.get,icon_class:"tags"})});return this.tagButton.render().$el},_render_annotateButton:function(){if(!(this.model.hasData())||(!this.urls.annotation.get)){this.annotateButton=null;return null}this.annotateButton=new IconButtonView({model:new IconButton({title:_l("Edit dataset annotation"),target:"galaxy_main",icon_class:"annotate"})});return this.annotateButton.render().$el},_render_tagArea:function(){if(!this.urls.tags.set){return null}return $(HDAEditView.templates.tagArea(_.extend(this.model.toJSON(),{urls:this.urls})))},_render_annotationArea:function(){if(!this.urls.annotation.get){return null}return $(HDAEditView.templates.annotationArea(_.extend(this.model.toJSON(),{urls:this.urls})))},_render_body_error:function(a){HDABaseView.prototype._render_body_error.call(this,a);var b=a.find("#primary-actions-"+this.model.get("id"));b.prepend(this._render_errButton())},_render_body_ok:function(a){a.append(this._render_hdaSummary());if(this.model.isDeletedOrPurged()){a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton,this._render_rerunButton]));return}a.append(this._render_primaryActionButtons([this._render_downloadButton,this._render_showParamsButton,this._render_rerunButton,this._render_visualizationsButton]));a.append(this._render_secondaryActionButtons([this._render_tagButton,this._render_annotateButton]));a.append('<div class="clear"/>');a.append(this._render_tagArea());a.append(this._render_annotationArea());a.append(this._render_displayApps());a.append(this._render_peek())},events:{"click .historyItemTitle":"toggleBodyVisibility","click a.icon-button.tags":"loadAndDisplayTags","click a.icon-button.annotate":"loadAndDisplayAnnotation"},loadAndDisplayTags:function(b){this.log(this+".loadAndDisplayTags",b);var c=this.$el.find(".tag-area"),a=c.find(".tag-elt");if(c.is(":hidden")){if(!jQuery.trim(a.html())){$.ajax({url:this.urls.tags.get,error:function(){alert(_l("Tagging failed"))},success:function(d){a.html(d);a.find(".tooltip").tooltip();c.slideDown("fast")}})}else{c.slideDown("fast")}}else{c.slideUp("fast")}return false},loadAndDisplayAnnotation:function(b){this.log(this+".loadAndDisplayAnnotation",b);var d=this.$el.find(".annotation-area"),c=d.find(".annotation-elt"),a=this.urls.annotation.set;if(d.is(":hidden")){if(!jQuery.trim(c.html())){$.ajax({url:this.urls.annotation.get,error:function(){alert(_l("Annotations failed"))},success:function(e){if(e===""){e="<em>"+_l("Describe or add notes to dataset")+"</em>"}c.html(e);d.find(".tooltip").tooltip();async_save_text(c.attr("id"),c.attr("id"),a,"new_annotation",18,true,4);d.slideDown("fast")}})}else{d.slideDown("fast")}}else{d.slideUp("fast")}return false},toString:function(){var a=(this.model)?(this.model+""):("(no model)");return"HDAView("+a+")"}});HDAEditView.templates={tagArea:Handlebars.templates["template-hda-tagArea"],annotationArea:Handlebars.templates["template-hda-annotationArea"]};function create_scatterplot_action_fn(a,b){action=function(){var d=$(window.parent.document).find("iframe#galaxy_main"),c=a+"/scatterplot?"+$.param(b);d.attr("src",c);$("div.popmenu-wrapper").remove();return false};return action}function create_trackster_action_fn(a,c,b){return function(){var d={};if(b){d.dbkey=b}$.ajax({url:a+"/list_tracks?f-"+$.param(d),dataType:"html",error:function(){alert(_l("Could not add this dataset to browser")+".")},success:function(e){var f=window.parent;f.show_modal(_l("View Data in a New or Saved Visualization"),"",{Cancel:function(){f.hide_modal()},"View in saved visualization":function(){f.show_modal(_l("Add Data to Saved Visualization"),e,{Cancel:function(){f.hide_modal()},"Add to visualization":function(){$(f.document).find("input[name=id]:checked").each(function(){var g=$(this).val();c.id=g;f.location=a+"/trackster?"+$.param(c)})}})},"View in new visualization":function(){f.location=a+"/trackster?"+$.param(c)}})}});return false}}; \ No newline at end of file diff -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e -r 4e50648f6e5d015d253cb3c9e68dd731729b06f7 static/scripts/packed/mvc/dataset/hda-model.js --- a/static/scripts/packed/mvc/dataset/hda-model.js +++ b/static/scripts/packed/mvc/dataset/hda-model.js @@ -1,1 +1,1 @@ -var HistoryDatasetAssociation=BaseModel.extend(LoggableMixin).extend({defaults:{history_id:null,model_class:"HistoryDatasetAssociation",hid:0,id:null,name:"",state:"",data_type:null,file_size:0,meta_files:[],misc_blurb:"",misc_info:"",deleted:false,purged:false,visible:false,accessible:false},url:function(){return"api/histories/"+this.get("history_id")+"/contents/"+this.get("id")},initialize:function(){this.log(this+".initialize",this.attributes);this.log("\tparent history_id: "+this.get("history_id"));if(!this.get("accessible")){this.set("state",HistoryDatasetAssociation.STATES.NOT_VIEWABLE)}this.on("change:state",function(b,a){this.log(this+" has changed state:",b,a);if(this.inReadyState()){this.trigger("state:ready",this.get("id"),a,this.previous("state"),b)}})},isDeletedOrPurged:function(){return(this.get("deleted")||this.get("purged"))},isVisible:function(b,c){var a=true;if((!b)&&(this.get("deleted")||this.get("purged"))){a=false}if((!c)&&(!this.get("visible"))){a=false}return a},inReadyState:function(){var a=this.get("state");return((a===HistoryDatasetAssociation.STATES.NEW)||(a===HistoryDatasetAssociation.STATES.OK)||(a===HistoryDatasetAssociation.STATES.EMPTY)||(a===HistoryDatasetAssociation.STATES.FAILED_METADATA)||(a===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(a===HistoryDatasetAssociation.STATES.DISCARDED)||(a===HistoryDatasetAssociation.STATES.ERROR))},hasData:function(){return(this.get("file_size")>0)},toString:function(){var a=this.get("id")||"";if(this.get("name")){a+=':"'+this.get("name")+'"'}return"HistoryDatasetAssociation("+a+")"}});HistoryDatasetAssociation.STATES={UPLOAD:"upload",QUEUED:"queued",RUNNING:"running",SETTING_METADATA:"setting_metadata",NEW:"new",OK:"ok",EMPTY:"empty",FAILED_METADATA:"failed_metadata",NOT_VIEWABLE:"noPermission",DISCARDED:"discarded",ERROR:"error"};var HDACollection=Backbone.Collection.extend(LoggableMixin).extend({model:HistoryDatasetAssociation,initialize:function(){},ids:function(){return this.map(function(a){return a.id})},getVisible:function(a,b){return this.filter(function(c){return c.isVisible(a,b)})},getStateLists:function(){var a={};_.each(_.values(HistoryDatasetAssociation.STATES),function(b){a[b]=[]});this.each(function(b){a[b.get("state")].push(b.get("id"))});return a},running:function(){var a=[];this.each(function(b){if(!b.inReadyState()){a.push(b.get("id"))}});return a},update:function(a){this.log(this+"update:",a);if(!(a&&a.length)){return}var b=this;_.each(a,function(e,c){var d=b.get(e);d.fetch()})},toString:function(){return("HDACollection("+this.ids().join(",")+")")}}); \ No newline at end of file +var HistoryDatasetAssociation=BaseModel.extend(LoggableMixin).extend({defaults:{history_id:null,model_class:"HistoryDatasetAssociation",hid:0,id:null,name:"",state:"",data_type:null,file_size:0,meta_files:[],misc_blurb:"",misc_info:"",deleted:false,purged:false,visible:false,accessible:false},urlRoot:"api/histories/",url:function(){return"api/histories/"+this.get("history_id")+"/contents/"+this.get("id")},initialize:function(){this.log(this+".initialize",this.attributes);this.log("\tparent history_id: "+this.get("history_id"));if(!this.get("accessible")){this.set("state",HistoryDatasetAssociation.STATES.NOT_VIEWABLE)}this.on("change:state",function(b,a){this.log(this+" has changed state:",b,a);if(this.inReadyState()){this.trigger("state:ready",this.get("id"),a,this.previous("state"),b)}})},isDeletedOrPurged:function(){return(this.get("deleted")||this.get("purged"))},isVisible:function(b,c){var a=true;if((!b)&&(this.get("deleted")||this.get("purged"))){a=false}if((!c)&&(!this.get("visible"))){a=false}return a},inReadyState:function(){var a=this.get("state");return((a===HistoryDatasetAssociation.STATES.NEW)||(a===HistoryDatasetAssociation.STATES.OK)||(a===HistoryDatasetAssociation.STATES.EMPTY)||(a===HistoryDatasetAssociation.STATES.FAILED_METADATA)||(a===HistoryDatasetAssociation.STATES.NOT_VIEWABLE)||(a===HistoryDatasetAssociation.STATES.DISCARDED)||(a===HistoryDatasetAssociation.STATES.ERROR))},hasData:function(){return(this.get("file_size")>0)},toString:function(){var a=this.get("id")||"";if(this.get("name")){a+=':"'+this.get("name")+'"'}return"HistoryDatasetAssociation("+a+")"}});HistoryDatasetAssociation.STATES={UPLOAD:"upload",QUEUED:"queued",RUNNING:"running",SETTING_METADATA:"setting_metadata",NEW:"new",EMPTY:"empty",OK:"ok",FAILED_METADATA:"failed_metadata",NOT_VIEWABLE:"noPermission",DISCARDED:"discarded",ERROR:"error"};var HDACollection=Backbone.Collection.extend(LoggableMixin).extend({model:HistoryDatasetAssociation,initialize:function(){},ids:function(){return this.map(function(a){return a.id})},getVisible:function(a,b){return this.filter(function(c){return c.isVisible(a,b)})},getStateLists:function(){var a={};_.each(_.values(HistoryDatasetAssociation.STATES),function(b){a[b]=[]});this.each(function(b){a[b.get("state")].push(b.get("id"))});return a},running:function(){var a=[];this.each(function(b){if(!b.inReadyState()){a.push(b.get("id"))}});return a},update:function(a){this.log(this+"update:",a);if(!(a&&a.length)){return}var b=this;_.each(a,function(e,c){var d=b.get(e);d.fetch()})},toString:function(){return("HDACollection("+this.ids().join(",")+")")}}); \ No newline at end of file diff -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e -r 4e50648f6e5d015d253cb3c9e68dd731729b06f7 static/scripts/packed/mvc/history/history-model.js --- a/static/scripts/packed/mvc/history/history-model.js +++ b/static/scripts/packed/mvc/history/history-model.js @@ -1,1 +1,1 @@ -var History=BaseModel.extend(LoggableMixin).extend({defaults:{id:"",name:"",state:"",diskSize:0,deleted:false,annotation:null,message:null},url:function(){return"api/histories/"+this.get("id")},initialize:function(a,b){this.log(this+".initialize:",a,b);this.hdas=new HDACollection();if(b&&b.length){this.hdas.reset(b);this.checkForUpdates()}},loadFromApi:function(a,c){var b=this;b.attributes.id=a;jQuery.when(jQuery.ajax("api/users/current"),b.fetch()).then(function(e,d){b.attributes.user=e[0];b.trigger("loaded:user",e[0]);b.trigger("loaded",d[0])}).then(function(){jQuery.ajax(b.url()+"/contents?"+jQuery.param({ids:b.hdaIdsFromStateIds().join(",")})).success(function(d){b.hdas.reset(d);b.checkForUpdates();b.trigger("loaded:hdas",d);if(c){callback(b)}})})},hdaIdsFromStateIds:function(){return _.reduce(_.values(this.get("state_ids")),function(b,a){return b.concat(a)})},checkForUpdates:function(a){if(this.hdas.running().length){this.stateUpdater()}else{this.trigger("ready")}return this},stateUpdater:function(){var c=this,a=this.get("state"),b=this.get("state_ids");jQuery.ajax("api/histories/"+this.get("id")).success(function(d){c.set(d);c.log("current history state:",c.get("state"),"(was)",a,"new size:",c.get("nice_size"));var e=[];_.each(_.keys(d.state_ids),function(g){var f=_.difference(d.state_ids[g],b[g]);e=e.concat(f)});if(e.length){c.hdas.update(e)}if((c.get("state")===HistoryDatasetAssociation.STATES.RUNNING)||(c.get("state")===HistoryDatasetAssociation.STATES.QUEUED)){setTimeout(function(){c.stateUpdater()},4000)}else{c.trigger("ready")}}).error(function(f,d,e){if(console&&console.warn){console.warn("Error getting history updates from the server:",f,d,e)}alert(_l("Error getting history updates from the server.")+"\n"+e)})},toString:function(){var a=(this.get("name"))?(","+this.get("name")):("");return"History("+this.get("id")+a+")"}});var HistoryCollection=Backbone.Collection.extend(LoggableMixin).extend({model:History,urlRoot:"api/histories",}); \ No newline at end of file +var History=BaseModel.extend(LoggableMixin).extend({defaults:{id:"",name:"",state:"",diskSize:0,deleted:false,annotation:null,message:null},urlRoot:"api/histories/",url:function(){return"api/histories/"+this.get("id")},initialize:function(a,b){this.log(this+".initialize:",a,b);this.hdas=new HDACollection();if(b&&b.length){this.hdas.reset(b);this.checkForUpdates()}},loadFromApi:function(a,c){var b=this;b.attributes.id=a;jQuery.when(jQuery.ajax("api/users/current"),b.fetch()).then(function(e,d){b.attributes.user=e[0];b.trigger("loaded:user",e[0]);b.trigger("loaded",d[0])}).then(function(){jQuery.ajax(b.url()+"/contents?"+jQuery.param({ids:b.hdaIdsFromStateIds().join(",")})).success(function(d){b.hdas.reset(d);b.checkForUpdates();b.trigger("loaded:hdas",d);if(c){callback(b)}})})},hdaIdsFromStateIds:function(){return _.reduce(_.values(this.get("state_ids")),function(b,a){return b.concat(a)})},checkForUpdates:function(a){if(this.hdas.running().length){this.stateUpdater()}else{this.trigger("ready")}return this},stateUpdater:function(){var c=this,a=this.get("state"),b=this.get("state_ids");jQuery.ajax("api/histories/"+this.get("id")).success(function(d){c.set(d);c.log("current history state:",c.get("state"),"(was)",a,"new size:",c.get("nice_size"));var e=[];_.each(_.keys(d.state_ids),function(g){var f=_.difference(d.state_ids[g],b[g]);e=e.concat(f)});if(e.length){c.hdas.update(e)}if((c.get("state")===HistoryDatasetAssociation.STATES.RUNNING)||(c.get("state")===HistoryDatasetAssociation.STATES.QUEUED)){setTimeout(function(){c.stateUpdater()},4000)}else{c.trigger("ready")}}).error(function(f,d,e){if(console&&console.warn){console.warn("Error getting history updates from the server:",f,d,e)}alert(_l("Error getting history updates from the server.")+"\n"+e)})},toString:function(){var a=(this.get("name"))?(","+this.get("name")):("");return"History("+this.get("id")+a+")"}});var HistoryCollection=Backbone.Collection.extend(LoggableMixin).extend({model:History,urlRoot:"api/histories"}); \ No newline at end of file diff -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e -r 4e50648f6e5d015d253cb3c9e68dd731729b06f7 static/scripts/packed/mvc/history/history-panel.js --- a/static/scripts/packed/mvc/history/history-panel.js +++ b/static/scripts/packed/mvc/history/history-panel.js @@ -1,1 +1,1 @@ -var HistoryPanel=BaseView.extend(LoggableMixin).extend({el:"body.historyPage",HDAView:HDAEditView,initialize:function(a){this.log(this+".initialize:",a);if(!a.urlTemplates){throw (this+" needs urlTemplates on initialize")}if(!a.urlTemplates.history){throw (this+" needs urlTemplates.history on initialize")}if(!a.urlTemplates.hda){throw (this+" needs urlTemplates.hda on initialize")}this.urlTemplates=a.urlTemplates.history;this.hdaUrlTemplates=a.urlTemplates.hda;this.storage=new PersistantStorage("HistoryView."+this.model.get("id"),{expandedHdas:{},show_deleted:false,show_hidden:false});this.log("this.storage:",this.storage.get());this.log("show_deleted:",a.show_deleted,"show_hidden",a.show_hidden);if((a.show_deleted===true)||(a.show_deleted===false)){this.storage.set("show_deleted",a.show_deleted)}if((a.show_hidden===true)||(a.show_hidden===false)){this.storage.set("show_hidden",a.show_hidden)}this.show_deleted=this.storage.get("show_deleted");this.show_hidden=this.storage.get("show_hidden");this.log("this.show_deleted:",this.show_deleted,"show_hidden",this.show_hidden);this.log("(now) this.storage:",this.storage.get());this.model.bind("change:nice_size",this.updateHistoryDiskSize,this);this.model.hdas.bind("add",this.add,this);this.model.hdas.bind("reset",this.addAll,this);this.model.hdas.bind("all",this.all,this);this.hdaViews={};this.urls={}},add:function(a){},addAll:function(){this.render()},all:function(a){},renderUrls:function(a){var b=this;b.urls={};_.each(this.urlTemplates,function(d,c){b.urls[c]=_.template(d,a)});return b.urls},render:function(){var b=this,d=b.toString()+".set-up",c=$("<div/>"),a=this.model.toJSON(),e=(this.$el.children().size()===0);a.urls=this.renderUrls(a);c.append(HistoryPanel.templates.historyPanel(a));c.find(".tooltip").tooltip({placement:"bottom"});this.setUpActionButton(c.find("#history-action-popup"));if(!this.model.hdas.length||!this.renderItems(c.find("#"+this.model.get("id")+"-datasets"))){c.find("#emptyHistoryMessage").show()}$(b).queue(d,function(f){b.$el.fadeOut("fast",function(){f()})});$(b).queue(d,function(f){b.$el.html("");b.$el.append(c.children());b.$el.fadeIn("fast",function(){f()})});$(b).queue(d,function(f){this.log(b+" rendered:",b.$el);b.setUpBehaviours();if(e){b.trigger("rendered:initial")}else{b.trigger("rendered")}f()});$(b).dequeue(d);return this},setUpActionButton:function(e){var c=this,d=(this.storage.get("show_deleted"))?("Hide deleted"):("Show deleted"),a=(this.storage.get("show_hidden"))?("Hide hidden"):("Show hidden"),b={};b[_l("refresh")]=function(){window.location.reload()};b[_l("collapse all")]=function(){c.hideAllHdaBodies()};b[_l(d)]=function(){c.toggleShowDeleted()};b[_l(a)]=function(){c.toggleShowHidden()};make_popupmenu(e,b)},renderItems:function(b){this.hdaViews={};var a=this,c=this.model.hdas.getVisible(this.storage.get("show_deleted"),this.storage.get("show_hidden"));_.each(c,function(f){var e=f.get("id"),d=a.storage.get("expandedHdas").get(e);a.hdaViews[e]=new a.HDAView({model:f,expanded:d,urlTemplates:a.hdaUrlTemplates});a.setUpHdaListeners(a.hdaViews[e]);b.prepend(a.hdaViews[e].render().$el)});return c.length},setUpHdaListeners:function(b){var a=this;b.bind("body-visible",function(c){a.storage.get("expandedHdas").set(c,true)});b.bind("body-hidden",function(c){a.storage.get("expandedHdas").deleteKey(c)})},setUpBehaviours:function(){if(!(this.model.get("user")&&this.model.get("user").email)){return}var a=this.$("#history-annotation-area");this.$("#history-annotate").click(function(){if(a.is(":hidden")){a.slideDown("fast")}else{a.slideUp("fast")}return false});async_save_text("history-name-container","history-name",this.urls.rename,"new_name",18);async_save_text("history-annotation-container","history-annotation",this.urls.annotate,"new_annotation",18,true,4)},updateHistoryDiskSize:function(){this.$el.find("#history-size").text(this.model.get("nice_size"))},events:{"click #history-tag":"loadAndDisplayTags"},showQuotaMessage:function(a){var b=this.$el.find("#quota-message-container");if(b.is(":hidden")){b.slideDown("fast")}},hideQuotaMessage:function(a){var b=this.$el.find("#quota-message-container");if(!b.is(":hidden")){b.slideUp("fast")}},toggleShowDeleted:function(a,c,b){this.storage.set("show_deleted",!this.storage.get("show_deleted"));this.render()},toggleShowHidden:function(){this.storage.set("show_hidden",!this.storage.get("show_hidden"));this.render()},hideAllHdaBodies:function(){_.each(this.hdaViews,function(a){a.toggleBodyVisibility(null,false)});this.storage.set("expandedHdas",{})},loadAndDisplayTags:function(c){this.log(this+".loadAndDisplayTags",c);var d=this.$el.find("#history-tag-area"),b=d.find(".tag-elt");this.log("\t tagArea",d," tagElt",b);if(d.is(":hidden")){if(!jQuery.trim(b.html())){var a=this;$.ajax({url:a.urls.tag,error:function(){alert(_l("Tagging failed"))},success:function(e){b.html(e);b.find(".tooltip").tooltip();d.slideDown("fast")}})}else{d.slideDown("fast")}}else{d.slideUp("fast")}return false},toString:function(){var a=this.model.get("name")||"";return"HistoryView("+a+")"}});HistoryPanel.templates={historyPanel:Handlebars.templates["template-history-historyPanel"]}; \ No newline at end of file +var HistoryPanel=BaseView.extend(LoggableMixin).extend({el:"body.historyPage",HDAView:HDAEditView,events:{"click #history-tag":"loadAndDisplayTags"},initialize:function(a){this.log(this+".initialize:",a);if(!a.urlTemplates){throw (this+" needs urlTemplates on initialize")}if(!a.urlTemplates.history){throw (this+" needs urlTemplates.history on initialize")}if(!a.urlTemplates.hda){throw (this+" needs urlTemplates.hda on initialize")}this.urlTemplates=a.urlTemplates.history;this.hdaUrlTemplates=a.urlTemplates.hda;this._setUpWebStorage(a.initiallyExpanded,a.show_deleted,a.show_hidden);this.model.bind("change:nice_size",this.updateHistoryDiskSize,this);this.model.hdas.bind("add",this.add,this);this.model.hdas.bind("reset",this.addAll,this);this.hdaViews={};this.urls={}},_setUpWebStorage:function(b,a,c){this.storage=new PersistantStorage("HistoryView."+this.model.get("id"),{expandedHdas:{},show_deleted:false,show_hidden:false});this.log("this.storage:",this.storage.get());if(b){this.storage.set("exandedHdas",b)}if((a===true)||(a===false)){this.storage.set("show_deleted",a)}if((c===true)||(c===false)){this.storage.set("show_hidden",c)}this.show_deleted=this.storage.get("show_deleted");this.show_hidden=this.storage.get("show_hidden");this.log("(init'd) this.storage:",this.storage.get())},add:function(a){},addAll:function(){this.render()},render:function(){var b=this,d=b.toString()+".set-up",c=$("<div/>"),a=this.model.toJSON(),e=(this.$el.children().size()===0);a.urls=this._renderUrls(a);c.append(HistoryPanel.templates.historyPanel(a));c.find(".tooltip").tooltip({placement:"bottom"});this._setUpActionButton(c.find("#history-action-popup"));if(!this.model.hdas.length||!this.renderItems(c.find("#"+this.model.get("id")+"-datasets"))){c.find("#emptyHistoryMessage").show()}$(b).queue(d,function(f){b.$el.fadeOut("fast",function(){f()})});$(b).queue(d,function(f){b.$el.html("");b.$el.append(c.children());b.$el.fadeIn("fast",function(){f()})});$(b).queue(d,function(f){this.log(b+" rendered:",b.$el);b._setUpBehaviours();if(e){b.trigger("rendered:initial")}else{b.trigger("rendered")}f()});$(b).dequeue(d);return this},_renderUrls:function(a){var b=this;b.urls={};_.each(this.urlTemplates,function(d,c){b.urls[c]=_.template(d,a)});return b.urls},_setUpActionButton:function(e){var c=this,d=(this.storage.get("show_deleted"))?("Hide deleted"):("Show deleted"),a=(this.storage.get("show_hidden"))?("Hide hidden"):("Show hidden"),b={};b[_l("refresh")]=function(){window.location.reload()};b[_l("collapse all")]=function(){c.hideAllHdaBodies()};b[_l(d)]=function(){c.toggleShowDeleted()};b[_l(a)]=function(){c.toggleShowHidden()};make_popupmenu(e,b)},renderItems:function(b){this.hdaViews={};var a=this,c=this.model.hdas.getVisible(this.storage.get("show_deleted"),this.storage.get("show_hidden"));_.each(c,function(f){var e=f.get("id"),d=a.storage.get("expandedHdas").get(e);a.hdaViews[e]=new a.HDAView({model:f,expanded:d,urlTemplates:a.hdaUrlTemplates});a._setUpHdaListeners(a.hdaViews[e]);b.prepend(a.hdaViews[e].render().$el)});return c.length},_setUpHdaListeners:function(b){var a=this;b.bind("body-expanded",function(c){a.storage.get("expandedHdas").set(c,true)});b.bind("body-collapsed",function(c){a.storage.get("expandedHdas").deleteKey(c)})},_setUpBehaviours:function(){if(!(this.model.get("user")&&this.model.get("user").email)){return}var a=this.$("#history-annotation-area");this.$("#history-annotate").click(function(){if(a.is(":hidden")){a.slideDown("fast")}else{a.slideUp("fast")}return false});async_save_text("history-name-container","history-name",this.urls.rename,"new_name",18);async_save_text("history-annotation-container","history-annotation",this.urls.annotate,"new_annotation",18,true,4)},updateHistoryDiskSize:function(){this.$el.find("#history-size").text(this.model.get("nice_size"))},showQuotaMessage:function(){var a=this.$el.find("#quota-message-container");if(a.is(":hidden")){a.slideDown("fast")}},hideQuotaMessage:function(){var a=this.$el.find("#quota-message-container");if(!a.is(":hidden")){a.slideUp("fast")}},toggleShowDeleted:function(){this.storage.set("show_deleted",!this.storage.get("show_deleted"));this.render()},toggleShowHidden:function(){this.storage.set("show_hidden",!this.storage.get("show_hidden"));this.render()},hideAllHdaBodies:function(){_.each(this.hdaViews,function(a){a.toggleBodyVisibility(null,false)});this.storage.set("expandedHdas",{})},loadAndDisplayTags:function(c){this.log(this+".loadAndDisplayTags",c);var d=this.$el.find("#history-tag-area"),b=d.find(".tag-elt");this.log("\t tagArea",d," tagElt",b);if(d.is(":hidden")){if(!jQuery.trim(b.html())){var a=this;$.ajax({url:a.urls.tag,error:function(){alert(_l("Tagging failed"))},success:function(e){b.html(e);b.find(".tooltip").tooltip();d.slideDown("fast")}})}else{d.slideDown("fast")}}else{d.slideUp("fast")}return false},toString:function(){var a=this.model.get("name")||"";return"HistoryPanel("+a+")"}});HistoryPanel.templates={historyPanel:Handlebars.templates["template-history-historyPanel"]}; \ No newline at end of file diff -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e -r 4e50648f6e5d015d253cb3c9e68dd731729b06f7 static/scripts/packed/mvc/user/user-model.js --- a/static/scripts/packed/mvc/user/user-model.js +++ b/static/scripts/packed/mvc/user/user-model.js @@ -1,1 +1,1 @@ -var User=BaseModel.extend(LoggableMixin).extend({urlRoot:"api/users",defaults:{id:null,username:"("+_l("anonymous user")+")",email:"",total_disk_usage:0,nice_total_disk_usage:"0 bytes"},initialize:function(a){this.log("User.initialize:",a);this.on("loaded",function(b,c){this.log(this+" has loaded:",b,c)});this.on("change",function(b,c){this.log(this+" has changed:",b,c.changes)})},loadFromApi:function(d,b){d=d||User.CURRENT_ID_STR;b=b||{};var a=this,c=b.success;b.success=function(f,e){a.trigger("loaded",f,e);if(c){c(f,e)}};if(d===User.CURRENT_ID_STR){b.url=this.urlRoot+"/"+User.CURRENT_ID_STR}return BaseModel.prototype.fetch.call(this,b)},toString:function(){var a=[this.get("username")];if(this.get("id")){a.unshift(this.get("id"));a.push(this.get("email"))}return"User("+a.join(":")+")"}});User.CURRENT_ID_STR="current";User.getCurrentUserFromApi=function(b){var a=new User();a.loadFromApi(User.CURRENT_ID_STR,b);return a};var UserCollection=Backbone.Collection.extend(LoggableMixin).extend({model:User,urlRoot:"api/users"}); \ No newline at end of file +var User=BaseModel.extend(LoggableMixin).extend({urlRoot:"api/users",defaults:{id:null,username:"("+_l("anonymous user")+")",email:"",total_disk_usage:0,nice_total_disk_usage:"0 bytes",quota_percent:null},initialize:function(a){this.log("User.initialize:",a);this.on("loaded",function(b,c){this.log(this+" has loaded:",b,c)});this.on("change",function(b,c){this.log(this+" has changed:",b,c.changes)})},isAnonymous:function(){return(!this.get("email"))},loadFromApi:function(d,b){d=d||User.CURRENT_ID_STR;b=b||{};var a=this,c=b.success;b.success=function(f,e){a.trigger("loaded",f,e);if(c){c(f,e)}};if(d===User.CURRENT_ID_STR){b.url=this.urlRoot+"/"+User.CURRENT_ID_STR}return BaseModel.prototype.fetch.call(this,b)},toString:function(){var a=[this.get("username")];if(this.get("id")){a.unshift(this.get("id"));a.push(this.get("email"))}return"User("+a.join(":")+")"}});User.CURRENT_ID_STR="current";User.getCurrentUserFromApi=function(b){var a=new User();a.loadFromApi(User.CURRENT_ID_STR,b);return a};var UserCollection=Backbone.Collection.extend(LoggableMixin).extend({model:User,urlRoot:"api/users"}); \ No newline at end of file diff -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e -r 4e50648f6e5d015d253cb3c9e68dd731729b06f7 static/scripts/packed/templates/compiled/template-history-historyPanel.js --- a/static/scripts/packed/templates/compiled/template-history-historyPanel.js +++ b/static/scripts/packed/templates/compiled/template-history-historyPanel.js @@ -1,1 +1,1 @@ -(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel"]=b(function(k,A,y,q,I){y=y||k.helpers;var z="",n,m,v=this,e="function",c=y.blockHelperMissing,d=this.escapeExpression;function t(N,M){var K="",L,J;K+='\n <div id="history-name" class="tooltip editable-text"\n title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(2,s,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(2,s,M)})}if(L||L===0){K+=L}K+='">';J=y.name;if(J){L=J.call(N,{hash:{}})}else{L=N.name;L=typeof L===e?L():L}K+=d(L)+"</div>\n ";return K}function s(K,J){return"Click to rename history"}function r(N,M){var K="",L,J;K+='\n <div id="history-name" class="tooltip"\n title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(5,p,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(5,p,M)})}if(L||L===0){K+=L}K+='">';J=y.name;if(J){L=J.call(N,{hash:{}})}else{L=N.name;L=typeof L===e?L():L}K+=d(L)+"</div>\n ";return K}function p(K,J){return"You must be logged in to edit your history name"}function o(K,J){return"Click to see more actions"}function j(N,M){var K="",L,J;K+='\n <div id="history-secondary-links" style="float: right;">\n <a id="history-tag" title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(10,H,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(10,H,M)})}if(L||L===0){K+=L}K+='"\n class="icon-button tags tooltip" target="galaxy_main" href="javascript:void(0)"></a>\n <a id="history-annotate" title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(12,G,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(12,G,M)})}if(L||L===0){K+=L}K+='"\n class="icon-button annotate tooltip" target="galaxy_main" href="javascript:void(0)"></a>\n </div>\n ';return K}function H(K,J){return"Edit history tags"}function G(K,J){return"Edit history annotation"}function F(N,M){var K="",L,J;K+="\n ";J=y.warningmessagesmall;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(15,E,M)})}else{L=N.warningmessagesmall;L=typeof L===e?L():L}if(!y.warningmessagesmall){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(15,E,M)})}if(L||L===0){K+=L}K+="\n ";return K}function E(M,L){var K,J;J=y.local;if(J){K=J.call(M,{hash:{},inverse:v.noop,fn:v.program(16,D,L)})}else{K=M.local;K=typeof K===e?K():K}if(!y.local){K=c.call(M,K,{hash:{},inverse:v.noop,fn:v.program(16,D,L)})}if(K||K===0){return K}else{return""}}function D(K,J){return"You are currently viewing a deleted history!"}function C(N,M){var K="",L,J;K+='\n <div id="history-tag-annotation">\n\n <div id="history-tag-area" style="display: none">\n <strong>';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(19,B,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(19,B,M)})}if(L||L===0){K+=L}K+=':</strong>\n <div class="tag-elt"></div>\n </div>\n\n <div id="history-annotation-area" style="display: none">\n <strong>';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(21,l,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(21,l,M)})}if(L||L===0){K+=L}K+=':</strong>\n <div id="history-annotation-container">\n <div id="history-annotation" class="tooltip editable-text"\n title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(23,i,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(23,i,M)})}if(L||L===0){K+=L}K+='">\n ';L=N.annotation;L=y["if"].call(N,L,{hash:{},inverse:v.program(27,g,M),fn:v.program(25,h,M)});if(L||L===0){K+=L}K+="\n </div>\n </div>\n </div>\n </div>\n ";return K}function B(K,J){return"Tags"}function l(K,J){return"Annotation"}function i(K,J){return"Click to edit annotation"}function h(N,M){var K="",L,J;K+="\n ";J=y.annotation;if(J){L=J.call(N,{hash:{}})}else{L=N.annotation;L=typeof L===e?L():L}K+=d(L)+"\n ";return K}function g(N,M){var K="",L,J;K+="\n <em>";J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(28,f,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(28,f,M)})}if(L||L===0){K+=L}K+="</em>\n ";return K}function f(K,J){return"Describe or add notes to history"}function x(N,M){var K="",L,J;K+='\n <div id="message-container">\n <div class="';J=y.status;if(J){L=J.call(N,{hash:{}})}else{L=N.status;L=typeof L===e?L():L}K+=d(L)+'message">\n ';J=y.message;if(J){L=J.call(N,{hash:{}})}else{L=N.message;L=typeof L===e?L():L}K+=d(L)+"\n </div><br />\n </div>\n ";return K}function w(K,J){return"You are over your disk quota.\n Tool execution is on hold until your disk usage drops below your allocated quota."}function u(K,J){return"Your history is empty. Click 'Get Data' on the left pane to start"}z+='\n<div id="history-controls">\n <div id="history-title-area" class="historyLinks">\n\n <div id="history-name-container" style="float: left;">\n ';z+="\n ";n=A.user;n=n==null||n===false?n:n.email;n=y["if"].call(A,n,{hash:{},inverse:v.program(4,r,I),fn:v.program(1,t,I)});if(n||n===0){z+=n}z+='\n </div>\n\n <a id="history-action-popup" class="tooltip" title="';m=y.local;if(m){n=m.call(A,{hash:{},inverse:v.noop,fn:v.program(7,o,I)})}else{n=A.local;n=typeof n===e?n():n}if(!y.local){n=c.call(A,n,{hash:{},inverse:v.noop,fn:v.program(7,o,I)})}if(n||n===0){z+=n}z+='"\n href="javascript:void(0);" style="float: right;">\n <span class="ficon cog large"></span>\n </a>\n <div style="clear: both;"></div>\n </div>\n\n <div id="history-subtitle-area">\n <div id="history-size" style="float:left;">';m=y.nice_size;if(m){n=m.call(A,{hash:{}})}else{n=A.nice_size;n=typeof n===e?n():n}z+=d(n)+"</div>\n ";n=A.user;n=n==null||n===false?n:n.email;n=y["if"].call(A,n,{hash:{},inverse:v.noop,fn:v.program(9,j,I)});if(n||n===0){z+=n}z+='\n <div style="clear: both;"></div>\n </div>\n\n ';n=A.deleted;n=y["if"].call(A,n,{hash:{},inverse:v.noop,fn:v.program(14,F,I)});if(n||n===0){z+=n}z+="\n\n ";z+="\n ";z+="\n ";n=A.user;n=n==null||n===false?n:n.email;n=y["if"].call(A,n,{hash:{},inverse:v.noop,fn:v.program(18,C,I)});if(n||n===0){z+=n}z+="\n\n ";n=A.message;n=y["if"].call(A,n,{hash:{},inverse:v.noop,fn:v.program(30,x,I)});if(n||n===0){z+=n}z+='\n\n <div id="quota-message-container" style="display: none">\n <div id="quota-message" class="errormessage">\n ';m=y.local;if(m){n=m.call(A,{hash:{},inverse:v.noop,fn:v.program(32,w,I)})}else{n=A.local;n=typeof n===e?n():n}if(!y.local){n=c.call(A,n,{hash:{},inverse:v.noop,fn:v.program(32,w,I)})}if(n||n===0){z+=n}z+='\n </div>\n </div>\n</div>\n\n<div id="';m=y.id;if(m){n=m.call(A,{hash:{}})}else{n=A.id;n=typeof n===e?n():n}z+=d(n)+'-datasets" class="history-datasets-list"></div>\n\n<div class="infomessagesmall" id="emptyHistoryMessage" style="display: none;">\n ';m=y.local;if(m){n=m.call(A,{hash:{},inverse:v.noop,fn:v.program(34,u,I)})}else{n=A.local;n=typeof n===e?n():n}if(!y.local){n=c.call(A,n,{hash:{},inverse:v.noop,fn:v.program(34,u,I)})}if(n||n===0){z+=n}z+="\n</div>";return z})})(); \ No newline at end of file +(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a["template-history-historyPanel"]=b(function(k,A,y,q,I){y=y||k.helpers;var z="",n,m,v=this,e="function",c=y.blockHelperMissing,d=this.escapeExpression;function t(N,M){var K="",L,J;K+='\n <div id="history-name" class="tooltip editable-text"\n title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(2,s,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(2,s,M)})}if(L||L===0){K+=L}K+='">';J=y.name;if(J){L=J.call(N,{hash:{}})}else{L=N.name;L=typeof L===e?L():L}K+=d(L)+"</div>\n ";return K}function s(K,J){return"Click to rename history"}function r(N,M){var K="",L,J;K+='\n <div id="history-name" class="tooltip"\n title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(5,p,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(5,p,M)})}if(L||L===0){K+=L}K+='">';J=y.name;if(J){L=J.call(N,{hash:{}})}else{L=N.name;L=typeof L===e?L():L}K+=d(L)+"</div>\n ";return K}function p(K,J){return"You must be logged in to edit your history name"}function o(K,J){return"Click to see more actions"}function j(N,M){var K="",L,J;K+='\n <div id="history-secondary-links" style="float: right;">\n <a id="history-tag" title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(10,H,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(10,H,M)})}if(L||L===0){K+=L}K+='"\n class="icon-button tags tooltip" target="galaxy_main" href="javascript:void(0)"></a>\n <a id="history-annotate" title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(12,G,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(12,G,M)})}if(L||L===0){K+=L}K+='"\n class="icon-button annotate tooltip" target="galaxy_main" href="javascript:void(0)"></a>\n </div>\n ';return K}function H(K,J){return"Edit history tags"}function G(K,J){return"Edit history annotation"}function F(N,M){var K="",L,J;K+="\n ";J=y.warningmessagesmall;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(15,E,M)})}else{L=N.warningmessagesmall;L=typeof L===e?L():L}if(!y.warningmessagesmall){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(15,E,M)})}if(L||L===0){K+=L}K+="\n ";return K}function E(M,L){var K,J;J=y.local;if(J){K=J.call(M,{hash:{},inverse:v.noop,fn:v.program(16,D,L)})}else{K=M.local;K=typeof K===e?K():K}if(!y.local){K=c.call(M,K,{hash:{},inverse:v.noop,fn:v.program(16,D,L)})}if(K||K===0){return K}else{return""}}function D(K,J){return"You are currently viewing a deleted history!"}function C(N,M){var K="",L,J;K+='\n <div id="history-tag-annotation">\n\n <div id="history-tag-area" style="display: none">\n <strong>';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(19,B,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(19,B,M)})}if(L||L===0){K+=L}K+=':</strong>\n <div class="tag-elt"></div>\n </div>\n\n <div id="history-annotation-area" style="display: none">\n <strong>';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(21,l,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(21,l,M)})}if(L||L===0){K+=L}K+=':</strong>\n <div id="history-annotation-container">\n <div id="history-annotation" class="tooltip editable-text"\n title="';J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(23,i,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(23,i,M)})}if(L||L===0){K+=L}K+='">\n ';L=N.annotation;L=y["if"].call(N,L,{hash:{},inverse:v.program(27,g,M),fn:v.program(25,h,M)});if(L||L===0){K+=L}K+="\n </div>\n </div>\n </div>\n </div>\n ";return K}function B(K,J){return"Tags"}function l(K,J){return"Annotation"}function i(K,J){return"Click to edit annotation"}function h(N,M){var K="",L,J;K+="\n ";J=y.annotation;if(J){L=J.call(N,{hash:{}})}else{L=N.annotation;L=typeof L===e?L():L}K+=d(L)+"\n ";return K}function g(N,M){var K="",L,J;K+="\n <em>";J=y.local;if(J){L=J.call(N,{hash:{},inverse:v.noop,fn:v.program(28,f,M)})}else{L=N.local;L=typeof L===e?L():L}if(!y.local){L=c.call(N,L,{hash:{},inverse:v.noop,fn:v.program(28,f,M)})}if(L||L===0){K+=L}K+="</em>\n ";return K}function f(K,J){return"Describe or add notes to history"}function x(N,M){var K="",L,J;K+='\n <div id="message-container">\n <div class="';J=y.status;if(J){L=J.call(N,{hash:{}})}else{L=N.status;L=typeof L===e?L():L}K+=d(L)+'message">\n ';J=y.message;if(J){L=J.call(N,{hash:{}})}else{L=N.message;L=typeof L===e?L():L}K+=d(L)+"\n </div><br />\n </div>\n ";return K}function w(K,J){return"You are over your disk quota.\n Tool execution is on hold until your disk usage drops below your allocated quota."}function u(K,J){return"Your history is empty. Click 'Get Data' on the left pane to start"}z+='<div id="history-controls">\n <div id="history-title-area" class="historyLinks">\n\n ';z+='\n <div id="history-name-container" style="float: left;">\n ';z+="\n ";n=A.user;n=n==null||n===false?n:n.email;n=y["if"].call(A,n,{hash:{},inverse:v.program(4,r,I),fn:v.program(1,t,I)});if(n||n===0){z+=n}z+='\n </div>\n\n <a id="history-action-popup" class="tooltip" title="';m=y.local;if(m){n=m.call(A,{hash:{},inverse:v.noop,fn:v.program(7,o,I)})}else{n=A.local;n=typeof n===e?n():n}if(!y.local){n=c.call(A,n,{hash:{},inverse:v.noop,fn:v.program(7,o,I)})}if(n||n===0){z+=n}z+='"\n href="javascript:void(0);" style="float: right;">\n <span class="ficon cogs large"></span>\n </a>\n <div style="clear: both;"></div>\n </div>\n\n <div id="history-subtitle-area">\n <div id="history-size" style="float:left;">';m=y.nice_size;if(m){n=m.call(A,{hash:{}})}else{n=A.nice_size;n=typeof n===e?n():n}z+=d(n)+"</div>\n ";n=A.user;n=n==null||n===false?n:n.email;n=y["if"].call(A,n,{hash:{},inverse:v.noop,fn:v.program(9,j,I)});if(n||n===0){z+=n}z+='\n <div style="clear: both;"></div>\n </div>\n\n ';n=A.deleted;n=y["if"].call(A,n,{hash:{},inverse:v.noop,fn:v.program(14,F,I)});if(n||n===0){z+=n}z+="\n\n ";z+="\n ";z+="\n ";n=A.user;n=n==null||n===false?n:n.email;n=y["if"].call(A,n,{hash:{},inverse:v.noop,fn:v.program(18,C,I)});if(n||n===0){z+=n}z+="\n\n ";n=A.message;n=y["if"].call(A,n,{hash:{},inverse:v.noop,fn:v.program(30,x,I)});if(n||n===0){z+=n}z+='\n\n <div id="quota-message-container" style="display: none">\n <div id="quota-message" class="errormessage">\n ';m=y.local;if(m){n=m.call(A,{hash:{},inverse:v.noop,fn:v.program(32,w,I)})}else{n=A.local;n=typeof n===e?n():n}if(!y.local){n=c.call(A,n,{hash:{},inverse:v.noop,fn:v.program(32,w,I)})}if(n||n===0){z+=n}z+='\n </div>\n </div>\n</div>\n\n<div id="';m=y.id;if(m){n=m.call(A,{hash:{}})}else{n=A.id;n=typeof n===e?n():n}z+=d(n)+'-datasets" class="history-datasets-list"></div>\n\n<div class="infomessagesmall" id="emptyHistoryMessage" style="display: none;">\n ';m=y.local;if(m){n=m.call(A,{hash:{},inverse:v.noop,fn:v.program(34,u,I)})}else{n=A.local;n=typeof n===e?n():n}if(!y.local){n=c.call(A,n,{hash:{},inverse:v.noop,fn:v.program(34,u,I)})}if(n||n===0){z+=n}z+="\n</div>";return z})})(); \ No newline at end of file diff -r 2d1402caf21a072edfdcaca0b12f1d38b4421b6e -r 4e50648f6e5d015d253cb3c9e68dd731729b06f7 static/scripts/packed/viz/circster.js --- a/static/scripts/packed/viz/circster.js +++ b/static/scripts/packed/viz/circster.js @@ -1,1 +1,1 @@ -define(["libs/underscore","libs/d3","viz/visualization"],function(g,l,i){var m=Backbone.Model.extend({is_visible:function(q,n){var o=q.getBoundingClientRect(),p=$("svg")[0].getBoundingClientRect();if(o.right<0||o.left>p.right||o.bottom<0||o.top>p.bottom){return false}return true}});var h={drawTicks:function(r,q,v,p,n){var u=r.append("g").selectAll("g").data(q).enter().append("g").selectAll("g").data(v).enter().append("g").attr("class","tick").attr("transform",function(w){return"rotate("+(w.angle*180/Math.PI-90)+")translate("+w.radius+",0)"});var t=[],s=[],o=function(w){return w.angle>Math.PI?"end":null};if(n){t=[0,0,0,-4];s=[4,0,"",".35em"];o=null}else{t=[1,0,4,0];s=[0,4,".35em",""]}u.append("line").attr("x1",t[0]).attr("y1",t[1]).attr("x2",t[2]).attr("y1",t[3]).style("stroke","#000");u.append("text").attr("x",s[0]).attr("y",s[1]).attr("dx",s[2]).attr("dy",s[3]).attr("text-anchor",o).attr("transform",p).text(function(w){return w.label})},formatNum:function(o,n){var q=null;if(o<1){q=o.toPrecision(n)}else{var p=Math.round(o.toPrecision(n));if(o<1000){q=p}else{if(o<1000000){q=Math.round((p/1000).toPrecision(3)).toFixed(0)+"K"}else{if(o<1000000000){q=Math.round((p/1000000).toPrecision(3)).toFixed(0)+"M"}}}}return q}};var c=Backbone.Model.extend({});var a=Backbone.View.extend({className:"circster",initialize:function(n){this.total_gap=n.total_gap;this.genome=n.genome;this.dataset_arc_height=n.dataset_arc_height;this.track_gap=10;this.label_arc_height=50;this.scale=1;this.circular_views=null;this.chords_views=null;this.model.get("tracks").on("add",this.add_track,this);this.model.get("tracks").on("remove",this.remove_track,this);this.get_circular_tracks()},get_circular_tracks:function(){return this.model.get("tracks").filter(function(n){return n.get("track_type")!=="DiagonalHeatmapTrack"})},get_chord_tracks:function(){return this.model.get("tracks").filter(function(n){return n.get("track_type")==="DiagonalHeatmapTrack"})},get_tracks_bounds:function(){var o=this.get_circular_tracks();dataset_arc_height=this.dataset_arc_height,min_dimension=Math.min(this.$el.width(),this.$el.height()),radius_start=min_dimension/2-o.length*(this.dataset_arc_height+this.track_gap)-(this.label_arc_height+this.track_gap),tracks_start_radii=l.range(radius_start,min_dimension/2,this.dataset_arc_height+this.track_gap);var n=this;return g.map(tracks_start_radii,function(p){return[p,p+n.dataset_arc_height]})},render:function(){var w=this,q=this.dataset_arc_height,n=w.$el.width(),v=w.$el.height(),s=this.get_circular_tracks(),p=this.get_chord_tracks(),r=this.get_tracks_bounds(),o=l.select(w.$el[0]).append("svg").attr("width",n).attr("height",v).attr("pointer-events","all").append("svg:g").call(l.behavior.zoom().on("zoom",function(){var x=l.event.scale;o.attr("transform","translate("+l.event.translate+") scale("+x+")");if(w.scale!==x){if(w.zoom_drag_timeout){clearTimeout(w.zoom_drag_timeout)}w.zoom_drag_timeout=setTimeout(function(){},400)}})).attr("transform","translate("+n/2+","+v/2+")").append("svg:g").attr("class","tracks");this.circular_views=s.map(function(y,z){var A=(y.get("track_type")==="LineTrack"?d:e),x=new A({el:o.append("g")[0],track:y,radius_bounds:r[z],genome:w.genome,total_gap:w.total_gap});x.render();return x});this.chords_views=p.map(function(y){var x=new j({el:o.append("g")[0],track:y,radius_bounds:r[0],genome:w.genome,total_gap:w.total_gap});x.render();return x});var u=this.circular_views[this.circular_views.length-1].radius_bounds[1],t=[u,u+this.label_arc_height];this.label_track_view=new b({el:o.append("g")[0],track:new c(),radius_bounds:t,genome:w.genome,total_gap:w.total_gap});this.label_track_view.render()},add_track:function(t){if(t.get("track_type")==="DiagonalHeatmapTrack"){var p=this.circular_views[0].radius_bounds,s=new j({el:l.select("g.tracks").append("g")[0],track:t,radius_bounds:p,genome:this.genome,total_gap:this.total_gap});s.render();this.chords_views.push(s)}else{var r=this.get_tracks_bounds();g.each(this.circular_views,function(v,w){v.update_radius_bounds(r[w])});g.each(this.chords_views,function(v){v.update_radius_bounds(r[0])});var q=this.circular_views.length,u=(t.get("track_type")==="LineTrack"?d:e),n=new u({el:l.select("g.tracks").append("g")[0],track:t,radius_bounds:r[q],genome:this.genome,total_gap:this.total_gap});n.render();this.circular_views.push(n);var o=r[r.length-1];o[1]=o[0];this.label_track_view.update_radius_bounds(o)}},remove_track:function(o,q,p){var n=this.circular_views[p.index];this.circular_views.splice(p.index,1);n.$el.remove();var r=this.get_tracks_bounds();g.each(this.circular_views,function(s,t){s.update_radius_bounds(r[t])})}});var k=Backbone.View.extend({tagName:"g",initialize:function(n){this.bg_stroke="ccc";this.loading_bg_fill="000";this.bg_fill="ccc";this.total_gap=n.total_gap;this.track=n.track;this.radius_bounds=n.radius_bounds;this.genome=n.genome;this.chroms_layout=this._chroms_layout();this.data_bounds=[];this.scale=1;this.parent_elt=l.select(this.$el[0])},get_fill_color:function(){var n=this.track.get("config").get_value("block_color");if(!n){n=this.track.get("config").get_value("color")}return n},render:function(){var r=this.parent_elt;if(!r){console.log("no parent elt")}var q=this.chroms_layout,t=l.svg.arc().innerRadius(this.radius_bounds[0]).outerRadius(this.radius_bounds[1]),n=r.selectAll("g").data(q).enter().append("svg:g"),p=n.append("path").attr("d",t).attr("class","chrom-background").style("stroke",this.bg_stroke).style("fill",this.loading_bg_fill);p.append("title").text(function(v){return v.data.chrom});var o=this,s=o.track.get("data_manager"),u=(s?s.data_is_ready():true);$.when(u).then(function(){$.when(o._render_data(r)).then(function(){p.style("fill",o.bg_fill);o.render_labels()})})},render_labels:function(){},update_radius_bounds:function(o){this.radius_bounds=o;var n=l.svg.arc().innerRadius(this.radius_bounds[0]).outerRadius(this.radius_bounds[1]);this.parent_elt.selectAll("g>path.chrom-background").transition().duration(1000).attr("d",n);this._transition_chrom_data();this._transition_labels()},update_scale:function(q){var p=this.scale;this.scale=q;if(q<=p){return}var o=this,n=new m();this.parent_elt.selectAll("path.chrom-data").filter(function(s,r){return n.is_visible(this)}).each(function(x,t){var w=l.select(this),s=w.attr("chrom"),v=o.genome.get_chrom_region(s),u=o.track.get("data_manager"),r;if(!u.can_get_more_detailed_data(v)){return}r=o.track.get("data_manager").get_more_detailed_data(v,"Coverage",0,q);$.when(r).then(function(A){w.remove();o._update_data_bounds();var z=g.find(o.chroms_layout,function(B){return B.data.chrom===s});var y=o.get_fill_color();o._render_chrom_data(o.parent_elt,z,A).style("stroke",y).style("fill",y)})});return o},_transition_chrom_data:function(){var o=this.track,q=this.chroms_layout,n=this.parent_elt.selectAll("g>path.chrom-data"),r=n[0].length;if(r>0){var p=this;$.when(o.get("data_manager").get_genome_wide_data(this.genome)).then(function(t){var s=g.reject(g.map(t,function(u,v){var w=null,x=p._get_path_function(q[v],u);if(x){w=x(u.data)}return w}),function(u){return u===null});n.each(function(v,u){l.select(this).transition().duration(1000).attr("d",s[u])})})}},_transition_labels:function(){},_update_data_bounds:function(){var n=this.data_bounds;this.data_bounds=this.get_data_bounds(this.track.get("data_manager").get_genome_wide_data(this.genome));if(this.data_bounds[0]<n[0]||this.data_bounds[1]>n[1]){this._transition_chrom_data()}},_render_data:function(q){var p=this,o=this.chroms_layout,n=this.track,r=$.Deferred();$.when(n.get("data_manager").get_genome_wide_data(this.genome)).then(function(t){p.data_bounds=p.get_data_bounds(t);layout_and_data=g.zip(o,t),chroms_data_layout=g.map(layout_and_data,function(u){var v=u[0],w=u[1];return p._render_chrom_data(q,v,w)});var s=p.get_fill_color();p.parent_elt.selectAll("path.chrom-data").style("stroke",s).style("fill",s);r.resolve(q)});return r},_render_chrom_data:function(n,o,p){},_get_path_function:function(o,n){},_chroms_layout:function(){var o=this.genome.get_chroms_info(),q=l.layout.pie().value(function(s){return s.len}).sort(null),r=q(o),n=this.total_gap/o.length,p=g.map(r,function(u,t){var s=u.endAngle-n;u.endAngle=(s>u.startAngle?s:u.startAngle);return u});return p}});var b=k.extend({initialize:function(n){k.prototype.initialize.call(this,n);this.innerRadius=this.radius_bounds[0];this.radius_bounds[0]=this.radius_bounds[1];this.bg_stroke="fff";this.bg_fill="fff";this.min_arc_len=0.08},_render_data:function(p){var o=this,n=p.selectAll("g");n.selectAll("path").attr("id",function(t){return"label-"+t.data.chrom});n.append("svg:text").filter(function(t){return t.endAngle-t.startAngle>o.min_arc_len}).attr("text-anchor","middle").append("svg:textPath").attr("xlink:href",function(t){return"#label-"+t.data.chrom}).attr("startOffset","25%").attr("font-weight","bold").text(function(t){return t.data.chrom});var q=function(v){var t=(v.endAngle-v.startAngle)/v.value,u=l.range(0,v.value,25000000).map(function(w,x){return{radius:o.innerRadius,angle:w*t+v.startAngle,label:x===0?0:(x%3?null:o.formatNum(w))}});if(u.length<4){u[u.length-1].label=o.formatNum(Math.round((u[u.length-1].angle-v.startAngle)/t))}return u};var s=function(t){return t.angle>Math.PI?"rotate(180)translate(-16)":null};var r=g.filter(this.chroms_layout,function(t){return t.endAngle-t.startAngle>o.min_arc_len});this.drawTicks(this.parent_elt,r,q,s)}});g.extend(b.prototype,h);var f=k.extend({_quantile:function(o,n){o.sort(l.ascending);return l.quantile(o,n)},_render_chrom_data:function(n,q,o){var r=this._get_path_function(q,o);if(!r){return null}var p=n.datum(o.data),s=p.append("path").attr("class","chrom-data").attr("chrom",q.data.chrom).attr("d",r);return s},_get_path_function:function(q,p){if(typeof p==="string"||!p.data||p.data.length===0){return null}var n=l.scale.linear().domain(this.data_bounds).range(this.radius_bounds).clamp(true);var r=l.scale.linear().domain([0,p.data.length]).range([q.startAngle,q.endAngle]);var o=l.svg.line.radial().interpolate("linear").radius(function(s){return n(s[1])}).angle(function(t,s){return r(s)});return l.svg.area.radial().interpolate(o.interpolate()).innerRadius(n(0)).outerRadius(o.radius()).angle(o.angle())},render_labels:function(){var n=this,q=function(){return"rotate(90)"};var p=g.filter(this.chroms_layout,function(r){return r.endAngle-r.startAngle>0.08}),o=g.filter(p,function(s,r){return r%3===0});this.drawTicks(this.parent_elt,o,this._data_bounds_ticks_fn(),q,true)},_transition_labels:function(){if(this.data_bounds.length===0){return}var o=this,q=g.filter(this.chroms_layout,function(r){return r.endAngle-r.startAngle>0.08}),p=g.filter(q,function(s,r){return r%3===0}),n=g.flatten(g.map(p,function(r){return o._data_bounds_ticks_fn()(r)}));this.parent_elt.selectAll("g.tick").data(n).transition().attr("transform",function(r){return"rotate("+(r.angle*180/Math.PI-90)+")translate("+r.radius+",0)"})},_data_bounds_ticks_fn:function(){var n=this;visibleChroms=0;return function(o){return[{radius:n.radius_bounds[0],angle:o.startAngle,label:n.formatNum(n.data_bounds[0])},{radius:n.radius_bounds[1],angle:o.startAngle,label:n.formatNum(n.data_bounds[1])}]}},get_data_bounds:function(n){}});g.extend(f.prototype,h);var e=f.extend({get_data_bounds:function(o){var n=g.map(o,function(p){if(typeof p==="string"||!p.max){return 0}return p.max});return[0,(n&&typeof n!=="string"?this._quantile(values,0.98):0)]}});var d=f.extend({get_data_bounds:function(o){var n=g.flatten(g.map(o,function(p){if(p){return g.map(p.data,function(q){return q[1]})}else{return 0}}));return[g.min(n),this._quantile(n,0.98)]}});var j=k.extend({render:function(){var n=this;$.when(n.track.get("data_manager").data_is_ready()).then(function(){$.when(n.track.get("data_manager").get_genome_wide_data(n.genome)).then(function(q){var p=[],o=n.genome.get_chroms_info();g.each(q,function(u,t){var r=o[t].chrom;var s=g.map(u.data,function(w){var v=n._get_region_angle(r,w[1]),x=n._get_region_angle(w[3],w[4]);return{source:{startAngle:v,endAngle:v+0.01},target:{startAngle:x,endAngle:x+0.01}}});p=p.concat(s)});n.parent_elt.append("g").attr("class","chord").selectAll("path").data(p).enter().append("path").style("fill",n.get_fill_color()).attr("d",l.svg.chord().radius(n.radius_bounds[0])).style("opacity",1)})})},update_radius_bounds:function(n){this.radius_bounds=n;this.parent_elt.selectAll("path").transition().attr("d",l.svg.chord().radius(this.radius_bounds[0]))},_get_region_angle:function(p,n){var o=g.find(this.chroms_layout,function(q){return q.data.chrom===p});return o.endAngle-((o.endAngle-o.startAngle)*(o.data.len-n)/o.data.len)}});return{CircsterView:a}}); \ No newline at end of file +define(["libs/underscore","libs/d3","viz/visualization"],function(g,l,i){var m=Backbone.Model.extend({is_visible:function(q,n){var o=q.getBoundingClientRect(),p=$("svg")[0].getBoundingClientRect();if(o.right<0||o.left>p.right||o.bottom<0||o.top>p.bottom){return false}return true}});var h={drawTicks:function(r,q,v,p,n){var u=r.append("g").selectAll("g").data(q).enter().append("g").selectAll("g").data(v).enter().append("g").attr("class","tick").attr("transform",function(w){return"rotate("+(w.angle*180/Math.PI-90)+")translate("+w.radius+",0)"});var t=[],s=[],o=function(w){return w.angle>Math.PI?"end":null};if(n){t=[0,0,0,-4];s=[4,0,"",".35em"];o=null}else{t=[1,0,4,0];s=[0,4,".35em",""]}u.append("line").attr("x1",t[0]).attr("y1",t[1]).attr("x2",t[2]).attr("y1",t[3]).style("stroke","#000");u.append("text").attr("x",s[0]).attr("y",s[1]).attr("dx",s[2]).attr("dy",s[3]).attr("text-anchor",o).attr("transform",p).text(function(w){return w.label})},formatNum:function(o,n){if(n===undefined){n=2}var q=null;if(o<1){q=o.toPrecision(n)}else{var p=Math.round(o.toPrecision(n));if(o<1000){q=p}else{if(o<1000000){q=Math.round((p/1000).toPrecision(3)).toFixed(0)+"K"}else{if(o<1000000000){q=Math.round((p/1000000).toPrecision(3)).toFixed(0)+"M"}}}}return q}};var c=Backbone.Model.extend({});var a=Backbone.View.extend({className:"circster",initialize:function(n){this.total_gap=n.total_gap;this.genome=n.genome;this.dataset_arc_height=n.dataset_arc_height;this.track_gap=10;this.label_arc_height=50;this.scale=1;this.circular_views=null;this.chords_views=null;this.model.get("tracks").on("add",this.add_track,this);this.model.get("tracks").on("remove",this.remove_track,this);this.get_circular_tracks()},get_circular_tracks:function(){return this.model.get("tracks").filter(function(n){return n.get("track_type")!=="DiagonalHeatmapTrack"})},get_chord_tracks:function(){return this.model.get("tracks").filter(function(n){return n.get("track_type")==="DiagonalHeatmapTrack"})},get_tracks_bounds:function(){var o=this.get_circular_tracks();dataset_arc_height=this.dataset_arc_height,min_dimension=Math.min(this.$el.width(),this.$el.height()),radius_start=min_dimension/2-o.length*(this.dataset_arc_height+this.track_gap)-(this.label_arc_height+this.track_gap),tracks_start_radii=l.range(radius_start,min_dimension/2,this.dataset_arc_height+this.track_gap);var n=this;return g.map(tracks_start_radii,function(p){return[p,p+n.dataset_arc_height]})},render:function(){var w=this,q=this.dataset_arc_height,n=w.$el.width(),v=w.$el.height(),s=this.get_circular_tracks(),p=this.get_chord_tracks(),r=this.get_tracks_bounds(),o=l.select(w.$el[0]).append("svg").attr("width",n).attr("height",v).attr("pointer-events","all").append("svg:g").call(l.behavior.zoom().on("zoom",function(){var x=l.event.scale;o.attr("transform","translate("+l.event.translate+") scale("+x+")");if(w.scale!==x){if(w.zoom_drag_timeout){clearTimeout(w.zoom_drag_timeout)}w.zoom_drag_timeout=setTimeout(function(){},400)}})).attr("transform","translate("+n/2+","+v/2+")").append("svg:g").attr("class","tracks");this.circular_views=s.map(function(y,z){var A=(y.get("track_type")==="LineTrack"?d:e),x=new A({el:o.append("g")[0],track:y,radius_bounds:r[z],genome:w.genome,total_gap:w.total_gap});x.render();return x});this.chords_views=p.map(function(y){var x=new j({el:o.append("g")[0],track:y,radius_bounds:r[0],genome:w.genome,total_gap:w.total_gap});x.render();return x});var u=this.circular_views[this.circular_views.length-1].radius_bounds[1],t=[u,u+this.label_arc_height];this.label_track_view=new b({el:o.append("g")[0],track:new c(),radius_bounds:t,genome:w.genome,total_gap:w.total_gap});this.label_track_view.render()},add_track:function(t){if(t.get("track_type")==="DiagonalHeatmapTrack"){var p=this.circular_views[0].radius_bounds,s=new j({el:l.select("g.tracks").append("g")[0],track:t,radius_bounds:p,genome:this.genome,total_gap:this.total_gap});s.render();this.chords_views.push(s)}else{var r=this.get_tracks_bounds();g.each(this.circular_views,function(v,w){v.update_radius_bounds(r[w])});g.each(this.chords_views,function(v){v.update_radius_bounds(r[0])});var q=this.circular_views.length,u=(t.get("track_type")==="LineTrack"?d:e),n=new u({el:l.select("g.tracks").append("g")[0],track:t,radius_bounds:r[q],genome:this.genome,total_gap:this.total_gap});n.render();this.circular_views.push(n);var o=r[r.length-1];o[1]=o[0];this.label_track_view.update_radius_bounds(o)}},remove_track:function(o,q,p){var n=this.circular_views[p.index];this.circular_views.splice(p.index,1);n.$el.remove();var r=this.get_tracks_bounds();g.each(this.circular_views,function(s,t){s.update_radius_bounds(r[t])})}});var k=Backbone.View.extend({tagName:"g",initialize:function(n){this.bg_stroke="ccc";this.loading_bg_fill="000";this.bg_fill="ccc";this.total_gap=n.total_gap;this.track=n.track;this.radius_bounds=n.radius_bounds;this.genome=n.genome;this.chroms_layout=this._chroms_layout();this.data_bounds=[];this.scale=1;this.parent_elt=l.select(this.$el[0])},get_fill_color:function(){var n=this.track.get("config").get_value("block_color");if(!n){n=this.track.get("config").get_value("color")}return n},render:function(){var r=this.parent_elt;if(!r){console.log("no parent elt")}var q=this.chroms_layout,t=l.svg.arc().innerRadius(this.radius_bounds[0]).outerRadius(this.radius_bounds[1]),n=r.selectAll("g").data(q).enter().append("svg:g"),p=n.append("path").attr("d",t).attr("class","chrom-background").style("stroke",this.bg_stroke).style("fill",this.loading_bg_fill);p.append("title").text(function(v){return v.data.chrom});var o=this,s=o.track.get("data_manager"),u=(s?s.data_is_ready():true);$.when(u).then(function(){$.when(o._render_data(r)).then(function(){p.style("fill",o.bg_fill);o.render_labels()})})},render_labels:function(){},update_radius_bounds:function(o){this.radius_bounds=o;var n=l.svg.arc().innerRadius(this.radius_bounds[0]).outerRadius(this.radius_bounds[1]);this.parent_elt.selectAll("g>path.chrom-background").transition().duration(1000).attr("d",n);this._transition_chrom_data();this._transition_labels()},update_scale:function(q){var p=this.scale;this.scale=q;if(q<=p){return}var o=this,n=new m();this.parent_elt.selectAll("path.chrom-data").filter(function(s,r){return n.is_visible(this)}).each(function(x,t){var w=l.select(this),s=w.attr("chrom"),v=o.genome.get_chrom_region(s),u=o.track.get("data_manager"),r;if(!u.can_get_more_detailed_data(v)){return}r=o.track.get("data_manager").get_more_detailed_data(v,"Coverage",0,q);$.when(r).then(function(A){w.remove();o._update_data_bounds();var z=g.find(o.chroms_layout,function(B){return B.data.chrom===s});var y=o.get_fill_color();o._render_chrom_data(o.parent_elt,z,A).style("stroke",y).style("fill",y)})});return o},_transition_chrom_data:function(){var o=this.track,q=this.chroms_layout,n=this.parent_elt.selectAll("g>path.chrom-data"),r=n[0].length;if(r>0){var p=this;$.when(o.get("data_manager").get_genome_wide_data(this.genome)).then(function(t){var s=g.reject(g.map(t,function(u,v){var w=null,x=p._get_path_function(q[v],u);if(x){w=x(u.data)}return w}),function(u){return u===null});n.each(function(v,u){l.select(this).transition().duration(1000).attr("d",s[u])})})}},_transition_labels:function(){},_update_data_bounds:function(){var n=this.data_bounds;this.data_bounds=this.get_data_bounds(this.track.get("data_manager").get_genome_wide_data(this.genome));if(this.data_bounds[0]<n[0]||this.data_bounds[1]>n[1]){this._transition_chrom_data()}},_render_data:function(q){var p=this,o=this.chroms_layout,n=this.track,r=$.Deferred();$.when(n.get("data_manager").get_genome_wide_data(this.genome)).then(function(t){p.data_bounds=p.get_data_bounds(t);layout_and_data=g.zip(o,t),chroms_data_layout=g.map(layout_and_data,function(u){var v=u[0],w=u[1];return p._render_chrom_data(q,v,w)});var s=p.get_fill_color();p.parent_elt.selectAll("path.chrom-data").style("stroke",s).style("fill",s);r.resolve(q)});return r},_render_chrom_data:function(n,o,p){},_get_path_function:function(o,n){},_chroms_layout:function(){var o=this.genome.get_chroms_info(),q=l.layout.pie().value(function(s){return s.len}).sort(null),r=q(o),n=this.total_gap/o.length,p=g.map(r,function(u,t){var s=u.endAngle-n;u.endAngle=(s>u.startAngle?s:u.startAngle);return u});return p}});var b=k.extend({initialize:function(n){k.prototype.initialize.call(this,n);this.innerRadius=this.radius_bounds[0];this.radius_bounds[0]=this.radius_bounds[1];this.bg_stroke="fff";this.bg_fill="fff";this.min_arc_len=0.08},_render_data:function(p){var o=this,n=p.selectAll("g");n.selectAll("path").attr("id",function(t){return"label-"+t.data.chrom});n.append("svg:text").filter(function(t){return t.endAngle-t.startAngle>o.min_arc_len}).attr("text-anchor","middle").append("svg:textPath").attr("xlink:href",function(t){return"#label-"+t.data.chrom}).attr("startOffset","25%").attr("font-weight","bold").text(function(t){return t.data.chrom});var q=function(v){var t=(v.endAngle-v.startAngle)/v.value,u=l.range(0,v.value,25000000).map(function(w,x){return{radius:o.innerRadius,angle:w*t+v.startAngle,label:x===0?0:(x%3?null:o.formatNum(w))}});if(u.length<4){u[u.length-1].label=o.formatNum(Math.round((u[u.length-1].angle-v.startAngle)/t))}return u};var s=function(t){return t.angle>Math.PI?"rotate(180)translate(-16)":null};var r=g.filter(this.chroms_layout,function(t){return t.endAngle-t.startAngle>o.min_arc_len});this.drawTicks(this.parent_elt,r,q,s)}});g.extend(b.prototype,h);var f=k.extend({_quantile:function(o,n){o.sort(l.ascending);return l.quantile(o,n)},_render_chrom_data:function(n,q,o){var r=this._get_path_function(q,o);if(!r){return null}var p=n.datum(o.data),s=p.append("path").attr("class","chrom-data").attr("chrom",q.data.chrom).attr("d",r);return s},_get_path_function:function(q,p){if(typeof p==="string"||!p.data||p.data.length===0){return null}var n=l.scale.linear().domain(this.data_bounds).range(this.radius_bounds).clamp(true);var r=l.scale.linear().domain([0,p.data.length]).range([q.startAngle,q.endAngle]);var o=l.svg.line.radial().interpolate("linear").radius(function(s){return n(s[1])}).angle(function(t,s){return r(s)});return l.svg.area.radial().interpolate(o.interpolate()).innerRadius(n(0)).outerRadius(o.radius()).angle(o.angle())},render_labels:function(){var n=this,q=function(){return"rotate(90)"};var p=g.filter(this.chroms_layout,function(r){return r.endAngle-r.startAngle>0.08}),o=g.filter(p,function(s,r){return r%3===0});this.drawTicks(this.parent_elt,o,this._data_bounds_ticks_fn(),q,true)},_transition_labels:function(){if(this.data_bounds.length===0){return}var o=this,q=g.filter(this.chroms_layout,function(r){return r.endAngle-r.startAngle>0.08}),p=g.filter(q,function(s,r){return r%3===0}),n=g.flatten(g.map(p,function(r){return o._data_bounds_ticks_fn()(r)}));this.parent_elt.selectAll("g.tick").data(n).transition().attr("transform",function(r){return"rotate("+(r.angle*180/Math.PI-90)+")translate("+r.radius+",0)"})},_data_bounds_ticks_fn:function(){var n=this;visibleChroms=0;return function(o){return[{radius:n.radius_bounds[0],angle:o.startAngle,label:n.formatNum(n.data_bounds[0])},{radius:n.radius_bounds[1],angle:o.startAngle,label:n.formatNum(n.data_bounds[1])}]}},get_data_bounds:function(n){}});g.extend(f.prototype,h);var e=f.extend({get_data_bounds:function(o){var n=g.map(o,function(p){if(typeof p==="string"||!p.max){return 0}return p.max});return[0,(n&&typeof n!=="string"?this._quantile(n,0.98):0)]}});var d=f.extend({get_data_bounds:function(o){var n=g.flatten(g.map(o,function(p){if(p){return g.map(p.data,function(q){return q[1]})}else{return 0}}));return[g.min(n),this._quantile(n,0.98)]}});var j=k.extend({render:function(){var n=this;$.when(n.track.get("data_manager").data_is_ready()).then(function(){$.when(n.track.get("data_manager").get_genome_wide_data(n.genome)).then(function(q){var p=[],o=n.genome.get_chroms_info();g.each(q,function(u,t){var r=o[t].chrom;var s=g.map(u.data,function(w){var v=n._get_region_angle(r,w[1]),x=n._get_region_angle(w[3],w[4]);return{source:{startAngle:v,endAngle:v+0.01},target:{startAngle:x,endAngle:x+0.01}}});p=p.concat(s)});n.parent_elt.append("g").attr("class","chord").selectAll("path").data(p).enter().append("path").style("fill",n.get_fill_color()).attr("d",l.svg.chord().radius(n.radius_bounds[0])).style("opacity",1)})})},update_radius_bounds:function(n){this.radius_bounds=n;this.parent_elt.selectAll("path").transition().attr("d",l.svg.chord().radius(this.radius_bounds[0]))},_get_region_angle:function(p,n){var o=g.find(this.chroms_layout,function(q){return q.data.chrom===p});return o.endAngle-((o.endAngle-o.startAngle)*(o.data.len-n)/o.data.len)}});return{CircsterView:a}}); \ No newline at end of file Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.
participants (1)
-
Bitbucket