Merge json changes (and some cleanup) back with central.

This commit is contained in:
Dannon Baker
2014-09-09 16:31:31 -04:00
61 changed files with 1824 additions and 2407 deletions
+1
View File
@@ -0,0 +1 @@
run_tests.sh
+47 -366
View File
@@ -42,6 +42,7 @@ var LoggableMixin = /** @lends LoggableMixin# */{
if( this.logger ){
var log = this.logger.log;
if( typeof this.logger.log === 'object' ){
//TODO:! there has to be a way to get the lineno/file into this
log = Function.prototype.bind.call( this.logger.log, this.logger );
}
return log.apply( this.logger, arguments );
@@ -148,6 +149,23 @@ var SessionStorageModel = Backbone.Model.extend({
}());
//==============================================================================
/** Function that allows mixing of hashs into bbone MVC while showing the mixins first
* (before the more local class overrides/hash).
* Basically, a simple reversal of param order on _.defaults() - to show mixins in top of definition.
* @example:
* var NewModel = Something.extend( mixin( MyMixinA, MyMixinB, { ... myVars : ... }) );
*
* NOTE: this does not combine any hashes (like events, etc.) and you're expected to handle that
*/
function mixin( mixinHash1, /* mixinHash2, etc: ... variadic */ propsHash ){
var args = Array.prototype.slice.call( arguments, 0 ),
lastArg = args.pop();
args.unshift( lastArg );
return _.defaults.apply( _, args );
}
//==============================================================================
/** A mixin for models that allow T/F/Matching to their attributes - useful when
* searching or filtering collections of models.
@@ -328,205 +346,6 @@ var HiddenUntilActivatedViewMixin = /** @lends hiddenUntilActivatedMixin# */{
};
//==============================================================================
/** Function that allows mixing of hashs into bbone MVC while showing the mixins first
* (before the more local class overrides/hash).
* Basically, a simple reversal of param order on _.defaults() - to show mixins in top of definition.
* @example:
* var NewModel = Something.extend( mixin( MyMixinA, MyMixinB, { ... myVars : ... }) );
*
* NOTE: this does not combine any hashes (like events, etc.) and you're expected to handle that
*/
function mixin( mixinHash1, /* mixinHash2, etc: ... variadic */ propsHash ){
var args = Array.prototype.slice.call( arguments, 0 ),
lastArg = args.pop();
args.unshift( lastArg );
return _.defaults.apply( _, args );
}
//==============================================================================
/** Return an underscore template fn from an array of strings.
* @param {String[]} template the template strings to compile into the underscore template fn
* @param {String} jsonNamespace an optional namespace for the json data passed in (defaults to 'model')
* @returns {Function} the (wrapped) underscore template fn
* The function accepts:
*
* The template strings can access:
* the json/model hash using model ("<%- model.myAttr %>) using the jsonNamespace above
* _l: the localizer function
* view (if passed): ostensibly, the view using the template (handy for view instance vars)
* Because they're namespaced, undefined attributes will not throw an error.
*
* @example:
* templateBler : BASE_MVC.wrapTemplate([
* '<div class="myclass <%- mynamespace.modelClass %>">',
* '<span><% print( _l( mynamespace.message ) ); %>:<%= view.status %></span>'
* '</div>'
* ], 'mynamespace' )
*
* Meant to be called in a View's definition in order to compile only once.
*
*/
function wrapTemplate( template, jsonNamespace ){
jsonNamespace = jsonNamespace || 'model';
var templateFn = _.template( template.join( '' ) );
return function( json, view ){
var templateVars = { view : view || {}, _l : _l };
templateVars[ jsonNamespace ] = json || {};
return templateFn( templateVars );
};
}
//==============================================================================
/** A view which, when first rendered, shows only summary data/attributes, but
* can be expanded to show further details (and optionally fetch those
* details from the server).
*/
var ExpandableView = Backbone.View.extend( LoggableMixin ).extend({
//TODO: Although the reasoning behind them is different, this shares a lot with HiddenUntilActivated above: combine them
//PRECONDITION: model must have method hasDetails
//PRECONDITION: subclasses must have templates.el and templates.details
initialize : function( attributes ){
/** are the details of this view expanded/shown or not? */
this.expanded = attributes.expanded || false;
//this.log( '\t expanded:', this.expanded );
this.fxSpeed = attributes.fxSpeed || this.fxSpeed;
},
// ........................................................................ render main
/** jq fx speed */
fxSpeed : 'fast',
/** Render this content, set up ui.
* @param {Number or String} speed the speed of the render
*/
render : function( speed ){
var $newRender = this._buildNewRender();
this._setUpBehaviors( $newRender );
this._queueNewRender( $newRender, speed );
return this;
},
/** Build a temp div containing the new children for the view's $el.
* If the view is already expanded, build the details as well.
*/
_buildNewRender : function(){
// create a new render using a skeleton template, render title buttons, render body, and set up events, etc.
var $newRender = $( this.templates.el( this.model.toJSON(), this ) );
if( this.expanded ){
this.$details( $newRender ).replaceWith( this._renderDetails().show() );
}
return $newRender;
},
/** Fade out the old el, swap in the new contents, then fade in.
* @param {Number or String} speed jq speed to use for rendering effects
* @fires rendered when rendered
*/
_queueNewRender : function( $newRender, speed ) {
speed = ( speed === undefined )?( this.fxSpeed ):( speed );
var view = this;
$( view ).queue( 'fx', [
function( next ){ this.$el.fadeOut( speed, next ); },
function( next ){
view._swapNewRender( $newRender );
next();
},
function( next ){ this.$el.fadeIn( speed, next ); },
function( next ){
this.trigger( 'rendered', view );
next();
}
]);
},
/** empty out the current el, move the $newRender's children in */
_swapNewRender : function( $newRender ){
return this.$el.empty().attr( 'class', this.className ).append( $newRender.children() );
},
/** set up js behaviors, event handlers for elements within the given container
* @param {jQuery} $container jq object that contains the elements to process (defaults to this.$el)
*/
_setUpBehaviors : function( $where ){
$where = $where || this.$el;
// set up canned behavior on children (bootstrap, popupmenus, editable_text, etc.)
//make_popup_menus( $where );
$where.find( '[title]' ).tooltip({ placement : 'bottom' });
},
// ......................................................................... details
/** shortcut to details DOM (as jQ) */
$details : function( $where ){
$where = $where || this.$el;
return $where.find( '.details' );
},
/** build the DOM for the details and set up behaviors on it */
_renderDetails : function(){
var $newDetails = $( this.templates.details( this.model.toJSON(), this ) );
this._setUpBehaviors( $newDetails );
return $newDetails;
},
// ......................................................................... expansion/details
/** Show or hide the details
* @param {Boolean} expand if true, expand; if false, collapse
*/
toggleExpanded : function( expand ){
expand = ( expand === undefined )?( !this.expanded ):( expand );
if( expand ){
this.expand();
} else {
this.collapse();
}
return this;
},
/** Render and show the full, detailed body of this view including extra data and controls.
* note: if the model does not have detailed data, fetch that data before showing the body
* @fires expanded when a body has been expanded
*/
expand : function(){
var view = this;
return view._fetchModelDetails()
.always(function(){
var $newDetails = view._renderDetails();
view.$details().replaceWith( $newDetails );
// needs to be set after the above or the slide will not show
view.expanded = true;
$newDetails.slideDown( view.fxSpeed, function(){
view.trigger( 'expanded', view );
});
});
},
/** Check for model details and, if none, fetch them.
* @returns {jQuery.promise} the model.fetch.xhr if details are being fetched, an empty promise if not
*/
_fetchModelDetails : function(){
if( !this.model.hasDetails() ){
return this.model.fetch();
}
return jQuery.when();
},
/** Hide the body/details of an HDA.
* @fires collapsed when a body has been collapsed
*/
collapse : function(){
var view = this;
view.expanded = false;
this.$details().slideUp( view.fxSpeed, function(){
view.trigger( 'collapsed', view );
});
}
});
//==============================================================================
/** Mixin for views that can be dragged and dropped
* Allows for the drag behavior to be turned on/off, setting/removing jQuery event
@@ -711,186 +530,48 @@ var SelectableViewMixin = {
//==============================================================================
/** A view that is displayed in some larger list/grid/collection.
* Inherits from Expandable, Selectable, Draggable.
* The DOM contains warnings, a title bar, and a series of primary action controls.
* Primary actions are meant to be easily accessible item functions (such as delete)
* that are rendered in the title bar.
/** Return an underscore template fn from an array of strings.
* @param {String[]} template the template strings to compile into the underscore template fn
* @param {String} jsonNamespace an optional namespace for the json data passed in (defaults to 'model')
* @returns {Function} the (wrapped) underscore template fn
* The function accepts:
*
* Details are rendered when the user clicks the title bar or presses enter/space when
* the title bar is in focus.
* The template strings can access:
* the json/model hash using model ("<%- model.myAttr %>) using the jsonNamespace above
* _l: the localizer function
* view (if passed): ostensibly, the view using the template (handy for view instance vars)
* Because they're namespaced, undefined attributes will not throw an error.
*
* @example:
* templateBler : BASE_MVC.wrapTemplate([
* '<div class="myclass <%- mynamespace.modelClass %>">',
* '<span><% print( _l( mynamespace.message ) ); %>:<%= view.status %></span>'
* '</div>'
* ], 'mynamespace' )
*
* Meant to be called in a View's definition in order to compile only once.
*
* Designed as a base class for history panel contents - but usable elsewhere (I hope).
*/
var ListItemView = ExpandableView.extend( mixin( SelectableViewMixin, DraggableViewMixin, {
//TODO: that's a little contradictory
tagName : 'div',
className : 'list-item',
/** Set up the base class and all mixins */
initialize : function( attributes ){
ExpandableView.prototype.initialize.call( this, attributes );
SelectableViewMixin.initialize.call( this, attributes );
DraggableViewMixin.initialize.call( this, attributes );
},
// ........................................................................ rendering
/** In this override, call methods to build warnings, titlebar and primary actions */
_buildNewRender : function(){
var $newRender = ExpandableView.prototype._buildNewRender.call( this );
$newRender.find( '.warnings' ).replaceWith( this._renderWarnings() );
$newRender.find( '.title-bar' ).replaceWith( this._renderTitleBar() );
$newRender.find( '.primary-actions' ).append( this._renderPrimaryActions() );
$newRender.find( '.subtitle' ).replaceWith( this._renderSubtitle() );
return $newRender;
},
/** In this override, render the selector controls and set up dragging before the swap */
_swapNewRender : function( $newRender ){
ExpandableView.prototype._swapNewRender.call( this, $newRender );
if( this.selectable ){ this.showSelector( 0 ); }
if( this.draggable ){ this.draggableOn(); }
return this.$el;
},
/** Render any warnings the item may need to show (e.g. "I'm deleted") */
_renderWarnings : function(){
var view = this,
$warnings = $( '<div class="warnings"></div>' ),
json = view.model.toJSON();
//TODO:! unordered (map)
_.each( view.templates.warnings, function( templateFn ){
$warnings.append( $( templateFn( json, view ) ) );
});
return $warnings;
},
/** Render the title bar (the main/exposed SUMMARY dom element) */
_renderTitleBar : function(){
return $( this.templates.titleBar( this.model.toJSON(), this ) );
},
/** Return an array of jQ objects containing common/easily-accessible item controls */
_renderPrimaryActions : function(){
// override this
return [];
},
/** Render the title bar (the main/exposed SUMMARY dom element) */
_renderSubtitle : function(){
return $( this.templates.subtitle( this.model.toJSON(), this ) );
},
// ......................................................................... events
/** event map */
events : {
// expand the body when the title is clicked or when in focus and space or enter is pressed
'click .title-bar' : '_clickTitleBar',
'keydown .title-bar' : '_keyDownTitleBar',
// dragging - don't work, originalEvent === null
//'dragstart .dataset-title-bar' : 'dragStartHandler',
//'dragend .dataset-title-bar' : 'dragEndHandler'
'click .selector' : 'toggleSelect'
},
/** expand when the title bar is clicked */
_clickTitleBar : function( event ){
event.stopPropagation();
this.toggleExpanded();
},
/** expand when the title bar is in focus and enter or space is pressed */
_keyDownTitleBar : function( event ){
// bail (with propagation) if keydown and not space or enter
var KEYCODE_SPACE = 32, KEYCODE_RETURN = 13;
if( event && ( event.type === 'keydown' )
&&( event.keyCode === KEYCODE_SPACE || event.keyCode === KEYCODE_RETURN ) ){
this.toggleExpanded();
event.stopPropagation();
return false;
}
return true;
},
// ......................................................................... misc
/** String representation */
toString : function(){
var modelString = ( this.model )?( this.model + '' ):( '(no model)' );
return 'ListItemView(' + modelString + ')';
}
}));
// ............................................................................ TEMPLATES
/** underscore templates */
ListItemView.prototype.templates = (function(){
//TODO: move to require text! plugin
var elTemplato = wrapTemplate([
'<div class="list-element">',
// errors, messages, etc.
'<div class="warnings"></div>',
// multi-select checkbox
'<div class="selector">',
'<span class="fa fa-2x fa-square-o"></span>',
'</div>',
// space for title bar buttons - gen. floated to the right
'<div class="primary-actions"></div>',
'<div class="title-bar"></div>',
// expandable area for more details
'<div class="details"></div>',
'</div>'
]);
var warnings = {};
var titleBarTemplate = wrapTemplate([
// adding a tabindex here allows focusing the title bar and the use of keydown to expand the dataset display
'<div class="title-bar clear" tabindex="0">',
//TODO: prob. belongs in dataset-list-item
'<span class="state-icon"></span>',
'<div class="title">',
'<span class="name"><%- element.name %></span>',
'</div>',
'<div class="subtitle"></div>',
'</div>'
], 'element' );
var subtitleTemplate = wrapTemplate([
// override this
'<div class="subtitle"></div>'
]);
var detailsTemplate = wrapTemplate([
// override this
'<div class="details"></div>'
]);
return {
el : elTemplato,
warnings : warnings,
titleBar : titleBarTemplate,
subtitle : subtitleTemplate,
details : detailsTemplate
function wrapTemplate( template, jsonNamespace ){
jsonNamespace = jsonNamespace || 'model';
var templateFn = _.template( template.join( '' ) );
return function( json, view ){
var templateVars = { view : view || {}, _l : _l };
templateVars[ jsonNamespace ] = json || {};
return templateFn( templateVars );
};
}());
}
//==============================================================================
return {
LoggableMixin : LoggableMixin,
SessionStorageModel : SessionStorageModel,
mixin : mixin,
SearchableModelMixin : SearchableModelMixin,
HiddenUntilActivatedViewMixin : HiddenUntilActivatedViewMixin,
mixin : mixin,
wrapTemplate : wrapTemplate,
ExpandableView : ExpandableView,
DraggableViewMixin : DraggableViewMixin,
SelectableViewMixin : SelectableViewMixin,
ListItemView : ListItemView
wrapTemplate : wrapTemplate
};
});
@@ -1,11 +1,12 @@
define([
"mvc/list/list-item",
"mvc/dataset/dataset-li",
"mvc/base-mvc",
"utils/localization"
], function( DATASET_LI, BASE_MVC, _l ){
], function( LIST_ITEM, DATASET_LI, BASE_MVC, _l ){
/* global Backbone, LoggableMixin */
//==============================================================================
var ListItemView = BASE_MVC.ListItemView;
var ListItemView = LIST_ITEM.ListItemView;
/** @class Read only view for DatasetCollection.
*/
var DCListItemView = ListItemView.extend(
@@ -97,8 +98,7 @@ var DCEListItemView = ListItemView.extend(
//TODO: this might be expendable - compacted with HDAListItemView
/** logger used to record this.log messages, commonly set to console */
// comment this out to suppress log output
logger : console,
//logger : console,
/** add the DCE class to the list item */
className : ListItemView.prototype.className + " dataset-collection-element",
@@ -270,6 +270,11 @@ var DatasetCollection = Backbone.Model
return this.save( { deleted: false }, options );
},
/** Is this collection deleted or purged? */
isDeletedOrPurged : function(){
return ( this.get( 'deleted' ) || this.get( 'purged' ) );
},
// ........................................................................ searchable
/** searchable attributes for collections */
searchAttributes : [
+51 -205
View File
@@ -1,9 +1,10 @@
define([
"mvc/list/list-panel",
"mvc/collection/collection-model",
"mvc/collection/collection-li",
"mvc/base-mvc",
"utils/localization"
], function( DC_MODEL, DC_LI, BASE_MVC, _l ){
], function( LIST_PANEL, DC_MODEL, DC_LI, BASE_MVC, _l ){
/* =============================================================================
TODO:
@@ -11,36 +12,29 @@ TODO:
// =============================================================================
/** @class non-editable, read-only View/Controller for a dataset collection.
*/
var CollectionPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
var _super = LIST_PANEL.ModelListPanel;
var CollectionPanel = _super.extend(
/** @lends CollectionPanel.prototype */{
//MODEL is either a DatasetCollection (or subclass) or a DatasetCollectionElement (list of pairs)
/** logger used to record this.log messages, commonly set to console */
//logger : console,
tagName : 'div',
className : 'dataset-collection-panel',
/** (in ms) that jquery effects will use */
fxSpeed : 'fast',
className : _super.prototype.className + ' dataset-collection-panel',
/** sub view class used for datasets */
DatasetDCEViewClass : DC_LI.DatasetDCEListItemView,
/** sub view class used for nested collections */
NestedDCDCEViewClass : DC_LI.NestedDCDCEListItemView,
/** key of attribute in model to assign to this.collection */
modelCollectionKey : 'elements',
// ......................................................................... SET UP
/** Set up the view, set up storage, bind listeners to HistoryContents events
* @param {Object} attributes optional settings for the panel
*/
initialize : function( attributes ){
attributes = attributes || {};
// set the logger if requested
if( attributes.logger ){
this.logger = attributes.logger;
}
this.log( this + '.initialize:', attributes );
_super.prototype.initialize.call( this, attributes );
this.linkTarget = attributes.linkTarget || '_blank';
this.hasUser = attributes.hasUser;
@@ -50,185 +44,49 @@ var CollectionPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
//window.collectionPanel = this;
},
/** create any event listeners for the panel
* @fires: rendered:initial on the first render
* @fires: empty-history when switching to a history with no HDAs or creating a new history
*/
_setUpListeners : function(){
// debugging
//if( this.logger ){
this.on( 'all', function( event ){
this.log( this + '', arguments );
}, this );
//}
return this;
},
// ------------------------------------------------------------------------ history/hda event listening
/** listening for history and HDA events */
_setUpModelEventHandlers : function(){
return this;
},
// ------------------------------------------------------------------------ panel rendering
/** Render panel
* @fires: rendered when the panel is attached and fully visible
* @see Backbone.View#render
*/
render : function( speed, callback ){
this.log( 'render:', speed, callback );
// send a speed of 0 to have no fade in/out performed
speed = ( speed === undefined )?( this.fxSpeed ):( speed );
//this.debug( this + '.render, fxSpeed:', speed );
var panel = this,
$newRender;
// handle the possibility of no model (can occur if fetching the model returns an error)
if( !this.model ){
return this;
}
$newRender = this.renderModel();
// fade out existing, swap with the new, fade in, set up behaviours
$( panel ).queue( 'fx', [
function( next ){
if( speed && panel.$el.is( ':visible' ) ){
panel.$el.fadeOut( speed, next );
} else {
next();
}
},
function( next ){
// swap over from temp div newRender
panel.$el.empty();
if( $newRender ){
panel.$el.append( $newRender.children() );
}
next();
},
function( next ){
if( speed && !panel.$el.is( ':visible' ) ){
panel.$el.fadeIn( speed, next );
} else {
next();
}
},
function( next ){
//TODO: ideally, these would be set up before the fade in (can't because of async save text)
if( callback ){ callback.call( this ); }
panel.trigger( 'rendered', this );
next();
}
]);
return this;
},
/** render with collection data
* @returns {jQuery} dom fragment as temporary container to be swapped out later
*/
renderModel : function( ){
// tmp div for final swap in render
//TODO: ugh - reuse issue - refactor out
var type = this.model.get( 'collection_type' ) || this.model.object.get( 'collection_type' ),
json = _.extend( this.model.toJSON(), {
parentName : this.parentName,
type : type
}),
$newRender = $( '<div/>' ).append( this.templates.panel( json ) );
this._setUpBehaviours( $newRender );
this.renderContents( $newRender );
return $newRender;
},
/** Set up js/widget behaviours */
_setUpBehaviours : function( $where ){
//TODO: these should be either sub-MVs, or handled by events
$where = $where || this.$el;
$where.find( '[title]' ).tooltip({ placement: 'bottom' });
return this;
},
// ------------------------------------------------------------------------ sub-$element shortcuts
/** the scroll container for this panel - can be $el, $el.parent(), or grandparent depending on context */
$container : function(){
return ( this.findContainerFn )?( this.findContainerFn.call( this ) ):( this.$el.parent() );
},
/** where list content views are attached */
$datasetsList : function( $where ){
return ( $where || this.$el ).find( '.datasets-list' );
},
// ------------------------------------------------------------------------ sub-views
/** Set up/render a view for each DCE to be shown, init with model and listeners.
* DCE views are cached to the map this.contentViews (using the model.id as key).
* @param {jQuery} $whereTo what dom element to prepend the DCE views to
* @returns the number of visible DCE views
*/
renderContents : function( $whereTo ){
//this.debug( 'renderContents, elements:', this.model.elements );
$whereTo = $whereTo || this.$el;
this.warn( this + '.renderContents:, model:', this.model );
var panel = this,
contentViews = {},
//NOTE: no filtering here
visibleContents = this.model.getVisibleContents();
//this.debug( 'renderContents, visibleContents:', visibleContents, $whereTo );
this.$datasetsList( $whereTo ).empty();
if( visibleContents && visibleContents.length ){
visibleContents.each( function( content ){
var contentId = content.id,
contentView = panel._createContentView( content );
contentViews[ contentId ] = contentView;
panel._attachContentView( contentView.render(), $whereTo );
});
}
this.contentViews = contentViews;
return this.contentViews;
/** In this override, use model.getVisibleContents */
_filterCollection : function(){
//TODO: should *not* be model.getVisibleContents
return this.model.getVisibleContents();
},
/** */
_createContentView : function( content ){
//this.debug( 'content json:', JSON.stringify( content, null, ' ' ) );
var contentView = null,
ContentClass = this._getContentClass( content );
//this.debug( 'content:', content );
//this.debug( 'ContentClass:', ContentClass );
contentView = new ContentClass({
model : content,
linkTarget : this.linkTarget,
//draggable : true,
hasUser : this.hasUser,
logger : this.logger
});
//this.debug( 'contentView:', contentView );
this._setUpContentListeners( contentView );
return contentView;
},
/** */
_getContentClass : function( content ){
//this.debug( this + '._getContentClass:', content );
/** override to return proper view class based on element_type */
_getItemViewClass : function( model ){
//this.debug( this + '._getItemViewClass:', model );
//TODO: subclasses use DCEViewClass - but are currently unused - decide
switch( content.get( 'element_type' ) ){
switch( model.get( 'element_type' ) ){
case 'hda':
return this.DatasetDCEViewClass;
case 'dataset_collection':
return this.NestedDCDCEViewClass;
}
throw new TypeError( 'Unknown element type:', content.get( 'element_type' ) );
throw new TypeError( 'Unknown element type:', model.get( 'element_type' ) );
},
/** Set up listeners for content view events. In this override, handle collection expansion. */
_setUpContentListeners : function( contentView ){
/** override to add link target and anon */
_getItemViewOptions : function( model ){
var options = _super.prototype._getItemViewOptions.call( this, model );
return _.extend( options, {
linkTarget : this.linkTarget,
hasUser : this.hasUser
});
},
/** when a sub-view is clicked in the collection panel that is itself a collection,
* hide this panel's elements and show the sub-collection in its own panel.
*/
_setUpItemViewListeners : function( view ){
var panel = this;
if( contentView.model.get( 'element_type' ) === 'dataset_collection' ){
contentView.on( 'expanded', function( collectionView ){
_super.prototype._setUpItemViewListeners.call( panel, view );
//TODO:?? doesn't seem to belong here
if( view.model.get( 'element_type' ) === 'dataset_collection' ){
view.on( 'expanded', function( collectionView ){
panel.info( 'expanded', collectionView );
panel._addCollectionPanel( collectionView );
});
}
return panel;
},
/** When a sub-collection is clicked, hide the current panel and render the sub-collection in its own panel */
@@ -246,7 +104,7 @@ var CollectionPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
});
currPanel.panelStack.push( panel );
currPanel.$( '.controls' ).add( '.datasets-list' ).hide();
currPanel.$( '.controls' ).add( '.list-items' ).hide();
currPanel.$el.append( panel.$el );
panel.on( 'close', function(){
currPanel.render();
@@ -266,14 +124,6 @@ var CollectionPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
}
},
/** attach an contentView to the panel */
_attachContentView : function( contentView, $whereTo ){
$whereTo = $whereTo || this.$el;
var $datasetsList = this.$datasetsList( $whereTo );
$datasetsList.append( contentView.$el );
return this;
},
// ------------------------------------------------------------------------ panel events
/** event map */
events : {
@@ -293,16 +143,16 @@ var CollectionPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
}
});
//----------------------------------------------------------------------------- TEMPLATES
/** underscore templates */
CollectionPanel.templates = CollectionPanel.prototype.templates = (function(){
// use closure to run underscore template fn only once at module load
var _panelTemplate = _.template([
//------------------------------------------------------------------------------ TEMPLATES
CollectionPanel.prototype.templates = (function(){
var controlsTemplate = BASE_MVC.wrapTemplate([
'<div class="controls">',
'<div class="navigation">',
'<a class="back" href="javascript:void(0)">',
'<span class="fa fa-icon fa-angle-left"></span>',
_l( 'Back to ' ), '<%- collection.parentName %>',
_l( 'Back to ' ), '<%- view.parentName %>',
'</a>',
'</div>',
@@ -310,29 +160,25 @@ CollectionPanel.templates = CollectionPanel.prototype.templates = (function(){
'<div class="name"><%- collection.name || collection.element_identifier %></div>',
'<div class="subtitle">',
//TODO: remove logic from template
'<% if( collection.type === "list" ){ %>',
'<% if( collection.collection_type === "list" ){ %>',
_l( 'a list of datasets' ),
'<% } else if( collection.type === "paired" ){ %>',
'<% } else if( collection.collection_type === "paired" ){ %>',
_l( 'a pair of datasets' ),
'<% } else if( collection.type === "list:paired" ){ %>',
'<% } else if( collection.collection_type === "list:paired" ){ %>',
_l( 'a list of paired datasets' ),
'<% } %>',
'</div>',
'</div>',
'</div>',
// where the datasets/hdas are added
'<div class="datasets-list"></div>'
].join( '' ));
'</div>'
], 'collection' );
// we override here in order to pass the localizer (_L) into the template scope - since we use it as a fn within
return {
panel : function( json ){
return _panelTemplate({ _l: _l, collection: json });
}
};
return _.extend( _.clone( _super.prototype.templates ), {
controls : controlsTemplate
});
}());
// =============================================================================
/** @class non-editable, read-only View/Controller for a dataset collection. */
var ListCollectionPanel = CollectionPanel.extend(
+3 -2
View File
@@ -1,8 +1,9 @@
define([
"mvc/list/list-item",
"mvc/dataset/states",
"mvc/base-mvc",
"utils/localization"
], function( STATES, BASE_MVC, _l ){
], function( LIST_ITEM, STATES, BASE_MVC, _l ){
/* global Backbone */
/*==============================================================================
TODO:
@@ -11,7 +12,7 @@ TODO:
simplify button rendering
==============================================================================*/
var _super = BASE_MVC.ListItemView;
var _super = LIST_ITEM.ListItemView;
/** @class Read only list view for either LDDAs, HDAs, or HDADCEs.
* Roughly, any DatasetInstance (and not a raw Dataset).
*/
+1 -1
View File
@@ -1,5 +1,5 @@
define([
"mvc/dataset/list-panel",
"mvc/list/list-panel",
"mvc/dataset/dataset-li",
"mvc/base-mvc",
"utils/localization"
@@ -94,6 +94,9 @@ var DatasetAssociation = Backbone.Model.extend( BASE_MVC.LoggableMixin ).extend(
this.trigger( 'state:ready', currModel, newState, this.previous( 'state' ) );
}
});
this.on( 'change:urls', function(){
console.warn( 'change:urls', arguments );
});
// the download url (currenlty) relies on having a correct file extension
this.on( 'change:id change:file_ext', function( currModel ){
this._generateUrls();
@@ -104,6 +107,8 @@ var DatasetAssociation = Backbone.Model.extend( BASE_MVC.LoggableMixin ).extend(
/** override to add urls */
toJSON : function(){
var json = Backbone.Model.prototype.toJSON.call( this );
//console.warn( 'returning json?' );
//return json;
return _.extend( json, {
urls : this.urls
});
+2 -2
View File
@@ -17,12 +17,12 @@ var HDAListItemView = _super.extend(
/** logger used to record this.log messages, commonly set to console */
//logger : console,
className : _super.prototype.className + " history-content",
initialize : function( attributes, options ){
_super.prototype.initialize.call( this, attributes, options );
},
className : _super.prototype.className + " history-content",
// ......................................................................... misc
/** String representation */
toString : function(){
@@ -53,6 +53,7 @@ var HistoryContents = Backbone.Collection.extend( BASE_MVC.LoggableMixin ).exten
*/
initialize : function( models, options ){
options = options || {};
//TODO: could probably use the contents.history_id instead
this.historyId = options.historyId;
//this._setUpListeners();
@@ -226,7 +227,7 @@ var HistoryContents = Backbone.Collection.extend( BASE_MVC.LoggableMixin ).exten
if( !existing ){ return model; }
// merge the models _BEFORE_ calling the superclass version
var merged = existing.toJSON();
var merged = _.clone( existing.attributes );
_.extend( merged, model );
return merged;
});
@@ -303,6 +304,13 @@ var HistoryContents = Backbone.Collection.extend( BASE_MVC.LoggableMixin ).exten
return xhr;
},
/** In this override, copy the historyId to the clone */
clone : function(){
var clone = Backbone.Collection.prototype.clone.call( this );
clone.historyId = this.historyId;
return clone;
},
/** debugging */
print : function(){
var contents = this;
+14 -14
View File
@@ -232,7 +232,7 @@ History.UPDATE_DELAY = 4000;
/** Get data for a history then its hdas using a sequential ajax call, return a deferred to receive both */
History.getHistoryData = function getHistoryData( historyId, options ){
options = options || {};
var hdaDetailIds = options.hdaDetailIds || [];
var detailIdsFn = options.detailIdsFn || [];
var hdcaDetailIds = options.hdcaDetailIds || [];
//console.debug( 'getHistoryData:', historyId, options );
@@ -250,20 +250,20 @@ History.getHistoryData = function getHistoryData( historyId, options ){
// get the number of hdas accrd. to the history
return historyData && historyData.empty;
}
function getHdas( historyData ){
function getContents( historyData ){
// get the hda data
// if no hdas accrd. to history: return empty immed.
if( isEmpty( historyData ) ){ return []; }
// if there are hdas accrd. to history: get those as well
if( _.isFunction( hdaDetailIds ) ){
hdaDetailIds = hdaDetailIds( historyData );
if( _.isFunction( detailIdsFn ) ){
detailIdsFn = detailIdsFn( historyData );
}
if( _.isFunction( hdcaDetailIds ) ){
hdcaDetailIds = hdcaDetailIds( historyData );
}
var data = {};
if( hdaDetailIds.length ) {
data.dataset_details = hdaDetailIds.join( ',' );
if( detailIdsFn.length ) {
data.dataset_details = detailIdsFn.join( ',' );
}
if( hdcaDetailIds.length ) {
// for symmetry, not actually used by backend of consumed
@@ -274,10 +274,10 @@ History.getHistoryData = function getHistoryData( historyId, options ){
}
// getting these concurrently is 400% slower (sqlite, local, vanilla) - so:
// chain the api calls - getting history first then hdas
// chain the api calls - getting history first then contents
var historyFn = options.historyFn || getHistory,
hdaFn = options.hdaFn || getHdas;
contentsFn = options.contentsFn || getContents;
// chain ajax calls: get history first, then hdas
var historyXHR = historyFn( historyId );
@@ -291,15 +291,15 @@ History.getHistoryData = function getHistoryData( historyId, options ){
df.reject( xhr, 'loading the history' );
});
var hdaXHR = historyXHR.then( hdaFn );
hdaXHR.then( function( hdaJSON ){
df.notify({ status: 'dataset data retrieved', historyJSON: historyJSON, hdaJSON: hdaJSON });
var contentsXHR = historyXHR.then( contentsFn );
contentsXHR.then( function( contentsJSON ){
df.notify({ status: 'contents data retrieved', historyJSON: historyJSON, contentsJSON: contentsJSON });
// we've got both: resolve the outer scope deferred
df.resolve( historyJSON, hdaJSON );
df.resolve( historyJSON, contentsJSON );
});
hdaXHR.fail( function( xhr, status, message ){
contentsXHR.fail( function( xhr, status, message ){
// call reject on the outer deferred to allow its fail callback to run
df.reject( xhr, 'loading the datasets', { history: historyJSON } );
df.reject( xhr, 'loading the contents', { history: historyJSON } );
});
return df;
@@ -1,118 +1,97 @@
define([
"mvc/history/history-panel",
"mvc/history/hda-li",
"mvc/history/hdca-li",
"mvc/base-mvc",
"utils/localization"
], function( HPANEL, HDA_LI, _l ){
], function( HPANEL, HDA_LI, HDCA_LI, BASE_MVC, _l ){
/* =============================================================================
TODO:
============================================================================= */
var _super = HPANEL.ReadOnlyHistoryPanel;
var _super = HPANEL.HistoryPanel;
// used in history/display.mako and history/embed.mako
/** @class View/Controller for a tabular view of the history model.
* @name AnnotatedHistoryPanel
*
* As ReadOnlyHistoryPanel, but with:
* history annotation always shown
* datasets displayed in a table:
* datasets in left cells, dataset annotations in the right
*
* @augments Backbone.View
* @borrows LoggableMixin#logger as #logger
* @borrows LoggableMixin#log as #log
* @constructs
*/
var AnnotatedHistoryPanel = _super.extend(
/** @lends AnnotatedHistoryPanel.prototype */{
/** logger used to record this.log messages, commonly set to console */
// comment this out to suppress log output
//logger : console,
className : 'annotated-history-panel',
//TODO:?? possibly into own annotated class
/** class to use for constructing the HDA views */
//HDAViewClass : HDA_LI.HDAListItemView,
className : _super.prototype.className + ' annotated-history-panel',
// ------------------------------------------------------------------------ panel rendering
/** render with history data
* In this override:
* replace the datasets list with a table,
* add the history annotation,
* and move the search controls
* @returns {jQuery} dom fragment as temporary container to be swapped out later
/** In this override, add the history annotation
*/
renderModel : function( ){
// why do we need this here? why isn't className being applied?
this.$el.addClass( this.className );
var $newRender = _super.prototype.renderModel.call( this ),
// move datasets from div to table
$datasetsList = this.$datasetsList( $newRender ),
$datasetsTable = $( '<table/>' ).addClass( 'datasets-list datasets-table' );
$datasetsTable.append( $datasetsList.children() );
$datasetsList.replaceWith( $datasetsTable );
//TODO: it's possible to do this with css only, right? display: table-cell, etc.?
// add history annotation under subtitle
$newRender.find( '.history-subtitle' ).after( this.renderHistoryAnnotation() );
// hide search button, move search bar beneath controls (instead of above title), show, and set up
$newRender.find( '.history-search-btn' ).hide();
$newRender.find( '.history-controls' ).after( $newRender.find( '.history-search-controls' ).show() );
_buildNewRender : function(){
//TODO: shouldn't this display regardless (on all non-current panels)?
var $newRender = _super.prototype._buildNewRender.call( this );
this.renderHistoryAnnotation( $newRender );
return $newRender;
},
/** render the history's annotation as its own field */
renderHistoryAnnotation : function(){
renderHistoryAnnotation : function( $newRender ){
var annotation = this.model.get( 'annotation' );
if( !annotation ){ return null; }
return $([
'<div class="history-annotation">', annotation, '</div>'
].join( '' ));
if( !annotation ){ return; }
$newRender.find( '.controls .annotation-display' ).text( annotation );
},
/** Set up/render a view for each HDA to be shown, init with model and listeners.
* In this override, add table header cells to indicate the dataset, annotation columns
/** In this override, convert the list-items tag to a table
* and add table header cells to indicate the dataset, annotation columns
*/
renderHdas : function( $whereTo ){
renderItems : function( $whereTo ){
$whereTo = $whereTo || this.$el;
var hdaViews = _super.prototype.renderHdas.call( this, $whereTo );
this.$datasetsList( $whereTo ).prepend( $( '<tr/>' ).addClass( 'headers' ).append([
$( '<th/>' ).text( _l( 'Dataset' ) ),
$( '<th/>' ).text( _l( 'Annotation' ) )
]));
return hdaViews;
// convert to table
$whereTo.find( '.list-items' )
.replaceWith( $( '<table/>' ).addClass( 'list-items' ) );
// render rows/contents and prepend headers
var views = _super.prototype.renderItems.call( this, $whereTo );
this.$list( $whereTo )
.prepend( $( '<tr/>' ).addClass( 'headers' ).append([
$( '<th/>' ).text( _l( 'Dataset' ) ),
$( '<th/>' ).text( _l( 'Annotation' ) )
]));
return views;
},
// ------------------------------------------------------------------------ hda sub-views
/** attach an hdaView to the panel
* In this override, wrap the hdaView in a table row and cell, adding a 2nd cell for the hda annotation
// ------------------------------------------------------------------------ sub-views
/** In this override, wrap the content view in a table row
* with the content in the left td and annotation/extra-info in the right
*/
attachContentView : function( hdaView, $whereTo ){
$whereTo = $whereTo || this.$el;
// build a row around the dataset with the std hdaView in the first cell and the annotation in the next
var stateClass = _.find( hdaView.el.classList, function( c ){ return ( /^state\-/ ).test( c ); }),
annotation = hdaView.model.get( 'annotation' ) || '',
$tr = $( '<tr/>' ).addClass( 'dataset-row' ).append([
$( '<td/>' ).addClass( 'dataset-container' ).append( hdaView.$el )
// visually match the cell bg to the dataset at runtime (prevents the empty space)
// (getting bg via jq on hidden elem doesn't work on chrome/webkit - so use states)
//.css( 'background-color', hdaView.$el.css( 'background-color' ) ),
.addClass( stateClass? stateClass.replace( '-', '-color-' ): '' ),
$( '<td/>' ).addClass( 'additional-info' ).text( annotation )
]);
this.$datasetsList( $whereTo ).append( $tr );
_attachItems : function( $whereTo ){
this.$list( $whereTo ).append( this.views.map( function( view ){
//TODO:?? possibly make this more flexible: instead of annotation use this._additionalInfo()
// build a row around the dataset with the std itemView in the first cell and the annotation in the next
var stateClass = _.find( view.el.classList, function( c ){ return ( /^state\-/ ).test( c ); }),
annotation = view.model.get( 'annotation' ) || '',
$tr = $( '<tr/>' ).append([
$( '<td/>' ).addClass( 'contents-container' ).append( view.$el )
// visually match the cell bg to the dataset at runtime (prevents the empty space)
// (getting bg via jq on hidden elem doesn't work on chrome/webkit - so use states)
//.css( 'background-color', view.$el.css( 'background-color' ) ),
.addClass( stateClass? stateClass.replace( '-', '-color-' ): '' ),
$( '<td/>' ).addClass( 'additional-info' ).text( annotation )
]);
return $tr;
}));
return this;
},
// ------------------------------------------------------------------------ panel events
/** event map */
events : _.extend( _.clone( _super.prototype.events ), {
// clicking on any part of the row will expand the items
'click tr' : function( ev ){
//if( !ev.target.hasAttribute( 'href' ) ){
$( ev.currentTarget ).find( '.dataset-title-bar' ).click();
//}
$( ev.currentTarget ).find( '.title-bar' ).click();
},
// prevent propagation on icon btns so they won't bubble up to tr and toggleBodyVisibility
'click .icon-btn' : function( ev ){
@@ -127,6 +106,7 @@ var AnnotatedHistoryPanel = _super.extend(
}
});
//==============================================================================
return {
AnnotatedHistoryPanel : AnnotatedHistoryPanel
@@ -11,8 +11,6 @@ define([
var HistoryPanelPrefs = BASE_MVC.SessionStorageModel.extend(
/** @lends HistoryPanelPrefs.prototype */{
defaults : {
/** is the panel currently showing the search/filter controls? */
searching : false,
/** should the tags editor be shown or hidden initially? */
tagsEditorShown : false,
/** should the annotation editor be shown or hidden initially? */
@@ -32,31 +30,26 @@ HistoryPanelPrefs.storageKey = function storageKey(){
TODO:
============================================================================= */
var _super = HPANEL_EDIT.HistoryPanel;
var _super = HPANEL_EDIT.HistoryPanelEdit;
// used in root/index.mako
/** @class View/Controller for the user's current history model as used in the history
* panel (current right hand panel) of the analysis page.
* @name HistoryPanel
*
* @augments Backbone.View
* @borrows LoggableMixin#logger as #logger
* @borrows LoggableMixin#log as #log
* @constructs
* The only history panel that will poll for updates.
*/
var CurrentHistoryPanel = _super.extend(
/** @lends CurrentHistoryPanel.prototype */{
className : _super.prototype.className + ' current-history-panel',
/** logger used to record this.log messages, commonly set to console */
// comment this out to suppress log output
//logger : console,
emptyMsg : _l( "This history is empty. Click 'Get Data' on the left tool menu to start" ),
noneFoundMsg : _l( "No matching datasets found" ),
// ......................................................................... SET UP
/** Set up the view, set up storage, bind listeners to HistoryContents events
* @param {Object} attributes
*/
/** Set up the view, set up storage, bind listeners to HistoryContents events */
initialize : function( attributes ){
attributes = attributes || {};
@@ -72,19 +65,19 @@ var CurrentHistoryPanel = _super.extend(
this.panelStack = [];
},
// ------------------------------------------------------------------------ loading history/hda models
/** (re-)loads the user's current history & hdas w/ details */
// ------------------------------------------------------------------------ loading history/item models
/** (re-)loads the user's current history & contents w/ details */
loadCurrentHistory : function( attributes ){
this.debug( this + '.loadCurrentHistory' );
// implemented as a 'fresh start' or for when there is no model (intial panel render)
var panel = this;
return this.loadHistoryWithHDADetails( 'current', attributes )
.then(function( historyData, hdaData ){
return this.loadHistoryWithDetails( 'current', attributes )
.then(function( historyData, contentsData ){
panel.trigger( 'current-history', panel );
});
},
/** loads a history & hdas w/ details and makes them the current history */
/** loads a history & contents w/ details and makes them the current history */
switchToHistory : function( historyId, attributes ){
//this.info( 'switchToHistory:', historyId, attributes );
var panel = this,
@@ -94,8 +87,8 @@ var CurrentHistoryPanel = _super.extend(
// method : 'PUT'
//});
};
return this.loadHistoryWithHDADetails( historyId, attributes, historyFn )
.then(function( historyData, hdaData ){
return this.loadHistoryWithDetails( historyId, attributes, historyFn )
.then(function( historyData, contentsData ){
panel.trigger( 'switched-history', panel );
});
},
@@ -115,7 +108,7 @@ var CurrentHistoryPanel = _super.extend(
// id undefined bc there is no historyId yet - the server will provide
// (no need for details - nothing expanded in new history)
return this.loadHistory( undefined, attributes, historyFn )
.then(function( historyData, hdaData ){
.then(function( historyData, contentsData ){
panel.trigger( 'new-history', panel );
});
},
@@ -130,98 +123,60 @@ var CurrentHistoryPanel = _super.extend(
return this;
},
// ------------------------------------------------------------------------ history/hda event listening
/** listening for history and HDA events */
_setUpModelEventHandlers : function(){
_super.prototype._setUpModelEventHandlers.call( this );
// ---- history
// update the quota meter when current history changes size
if( Galaxy && Galaxy.quotaMeter ){
this.listenTo( this.model, 'change:nice_size', function(){
//this.info( '!! model size changed:', this.model.get( 'nice_size' ) )
//TODO: global
Galaxy.quotaMeter.update();
});
}
// ------------------------------------------------------------------------ history/content event listening
/** listening for collection events */
_setUpCollectionListeners : function(){
_super.prototype._setUpCollectionListeners.call( this );
// if an a hidden hda is created (gen. by a workflow), moves thru the updater to the ready state,
// if a hidden item is created (gen. by a workflow), moves thru the updater to the ready state,
// then: remove it from the collection if the panel is set to NOT show hidden datasets
this.model.contents.on( 'state:ready', function( hda, newState, oldState ){
if( ( !hda.get( 'visible' ) )
this.collection.on( 'state:ready', function( model, newState, oldState ){
if( ( !model.get( 'visible' ) )
&& ( !this.storage.get( 'show_hidden' ) ) ){
this.removeHdaView( this.hdaViews[ hda.id ] );
this.removeItemView( this.viewFromModel( model ) );
}
}, this );
},
// ------------------------------------------------------------------------ panel rendering
/** Render urls, historyPanel body, and hdas (if any are shown)
* @fires: rendered when the panel is attached and fully visible
* @see Backbone.View#render
*/
render : function( speed, callback ){
this.log( 'render:', speed, callback );
// send a speed of 0 to have no fade in/out performed
speed = ( speed === undefined )?( this.fxSpeed ):( speed );
var panel = this,
$newRender;
// handle the possibility of no model (can occur if fetching the model returns an error)
if( this.model ){
$newRender = this.renderModel();
} else {
$newRender = this.renderWithoutModel();
/** listening for history events */
_setUpModelListeners : function(){
_super.prototype._setUpModelListeners.call( this );
// ---- history
// update the quota meter when current history changes size
//TODO: global - have Galaxy listen to this instead
if( Galaxy && Galaxy.quotaMeter ){
this.listenTo( this.model, 'change:nice_size', function(){
//this.info( '!! model size changed:', this.model.get( 'nice_size' ) )
Galaxy.quotaMeter.update();
});
}
// fade out existing, swap with the new, fade in, set up behaviours
$( panel ).queue( 'fx', [
function( next ){
if( speed && panel.$el.is( ':visible' ) ){
panel.$el.fadeOut( speed, next );
} else {
next();
}
},
function( next ){
// swap over from temp div newRender
panel.$el.empty();
if( $newRender ){
panel.$el.append( $newRender.children() );
panel.renderBasedOnPrefs();
}
next();
},
function( next ){
if( speed && !panel.$el.is( ':visible' ) ){
panel.$el.fadeIn( speed, next );
} else {
next();
}
},
function( next ){
//TODO: ideally, these would be set up before the fade in (can't because of async save text)
if( callback ){ callback.call( this ); }
panel.trigger( 'rendered', this );
next();
}
]);
return this;
},
/** perform additional rendering based on preferences */
renderBasedOnPrefs : function(){
if( this.preferences.get( 'searching' ) ){
this.toggleSearchControls( 0, true );
}
// ------------------------------------------------------------------------ panel rendering
/** In this override, handle null models and move the search input to the top */
_buildNewRender : function(){
if( !this.model ){ return $(); }
var $newRender = _super.prototype._buildNewRender.call( this );
//TODO: hacky
$newRender.find( '.search' ).prependTo( $newRender.find( '.controls' ) );
this._renderQuotaMessage( $newRender );
return $newRender;
},
/** render the message displayed when a user is over quota and can't run jobs */
_renderQuotaMessage : function( $whereTo ){
$whereTo = $whereTo || this.$el;
return $( this.templates.quotaMsg( {}, this ) ).prependTo( $whereTo.find( '.messages' ) );
},
/** In this override, add links to open data uploader or get data in the tools section */
_renderEmptyMsg : function( $whereTo ){
_renderEmptyMessage : function( $whereTo ){
var panel = this,
$emptyMsg = panel.$emptyMessage( $whereTo ),
$toolMenu = $( '.toolMenuContainer' );
if( ( _.isEmpty( panel.hdaViews ) && !panel.searchFor )
if( ( _.isEmpty( panel.views ) && !panel.searchFor )
&& ( Galaxy && Galaxy.upload && $toolMenu.size() ) ){
$emptyMsg.empty();
@@ -246,25 +201,12 @@ var CurrentHistoryPanel = _super.extend(
// $( this ).fadeTo( 200, 1.0 );
//});
});
$emptyMsg.show();
} else {
_super.prototype._renderEmptyMsg.call( this, $whereTo );
return $emptyMsg.show();
}
return this;
return _super.prototype._renderEmptyMessage.call( this, $whereTo );
},
/** In this override, save the search control visibility state to preferences */
toggleSearchControls : function( eventOrSpeed, show ){
var visible = _super.prototype.toggleSearchControls.call( this, eventOrSpeed, show );
this.preferences.set( 'searching', visible );
},
/** render the tag sub-view controller
* In this override, get and set current panel preferences when editor is used
*/
/** In this override, get and set current panel preferences when editor is used */
_renderTags : function( $where ){
var panel = this;
// render tags and show/hide based on preferences
@@ -278,9 +220,7 @@ var CurrentHistoryPanel = _super.extend(
panel.preferences.set( 'tagsEditorShown', tagsEditor.hidden );
});
},
/** render the annotation sub-view controller
* In this override, get and set current panel preferences when editor is used
*/
/** In this override, get and set current panel preferences when editor is used */
_renderAnnotation : function( $where ){
var panel = this;
// render annotation and show/hide based on preferences
@@ -296,54 +236,62 @@ var CurrentHistoryPanel = _super.extend(
},
// ------------------------------------------------------------------------ sub-views
/** Set up HistoryPanel listeners for HDAView events. In this override, handle collection expansion.
*/
_setUpHdaListeners : function( hdaView ){
_super.prototype._setUpHdaListeners.call( this, hdaView );
/** Override to reverse order of views - newest contents on top */
_attachItems : function( $whereTo ){
this.$list( $whereTo ).append( this.views.reverse().map( function( view ){
return view.$el;
}));
return this;
},
var historyView = this;
if( hdaView instanceof historyView.HDCAViewClass ){
hdaView.off( 'expanded' );
hdaView.on( 'expanded', function( collectionView ){
this.info( 'expanded', collectionView );
historyView._addCollectionPanel( collectionView );
/** In this override, handle collection expansion. */
_setUpItemViewListeners : function( view ){
var panel = this;
_super.prototype._setUpItemViewListeners.call( panel, view );
if( view instanceof panel.HDCAViewClass ){
view.off( 'expanded' );
view.on( 'expanded', function( collectionView ){
panel.info( 'expanded', collectionView );
panel._addCollectionPanel( collectionView );
});
hdaView.off( 'collapsed' );
view.off( 'collapsed' );
}
},
/** In this override, handle collection expansion. */
_addCollectionPanel : function( collectionView ){
var historyView = this,
var panel = this,
collectionModel = collectionView.model;
this.debug( 'history panel (stack), collectionModel:', collectionModel );
var panel = new ( this._getCollectionPanelClass( collectionModel ) )({
var overlaid = new ( this._getCollectionPanelClass( collectionModel ) )({
model : collectionModel,
HDAViewClass : this.HDAViewClass,
parentName : this.model.get( 'name' ),
linkTarget : this.linkTarget
});
historyView.panelStack.push( panel );
panel.panelStack.push( overlaid );
historyView.$( '.history-controls' ).add( '.datasets-list' ).hide();
historyView.$el.append( panel.$el );
panel.on( 'close', function(){
historyView.render();
panel.$( '.controls' ).add( panel.$list() ).hide();
panel.$el.append( overlaid.$el );
overlaid.on( 'close', function(){
panel.render();
collectionView.collapse();
historyView.panelStack.pop();
panel.panelStack.pop();
});
//TODO: to hdca-model, hasDetails
if( !panel.model.hasDetails() ){
var xhr = panel.model.fetch();
if( !overlaid.model.hasDetails() ){
var xhr = overlaid.model.fetch();
xhr.done( function(){
//this.debug( 'collection data fetched' );
//this.debug( JSON.stringify( panel.model.toJSON(), null, ' ' ) );
//this.debug( JSON.stringify( overlaid.model.toJSON(), null, ' ' ) );
//TODO: (re-)render collection contents
panel.render();
overlaid.render();
});
} else {
panel.render();
overlaid.render();
}
},
@@ -359,18 +307,43 @@ var CurrentHistoryPanel = _super.extend(
throw new TypeError( 'Uknown collection_type: ' + model.get( 'collection_type' ) );
},
/** In this override, check for any overlaid panels first
* @param {HistoryDatasetAssociation} hda
*/
addContentView : function( hda ){
/** In this override, check for any overlaid panels first */
addItemView : function( model, collection, options ){
this.log( this + '.addItemView:', model );
if( !this._filterItem( model ) ){ return undefined; }
var panel = this;
// don't show/add if there are panels overlaid on this one
if( this.panelStack.length ){
return this;
return panel;
}
return _super.prototype.addContentView.call( this, hda );
// current history item order is reversed - use unshift and prepend
var view = panel._createItemView( model );
this.views.unshift( view );
panel.scrollToTop();
$({}).queue([
function fadeOutEmptyMsg( next ){
var $emptyMsg = panel.$emptyMessage();
if( $emptyMsg.is( ':visible' ) ){
$emptyMsg.fadeOut( panel.fxSpeed, next );
} else {
next();
}
},
function createAndPrepend( next ){
//view.render().$el.hide();
panel.scrollToTop();
panel.$list().prepend( view.render( 0 ).$el.hide() );
view.$el.slideDown( panel.fxSpeed );
}
]);
return view;
},
// ........................................................................ external objects/MVC
//TODO: remove quota meter from panel and remove this
//TODO: remove quota meter from panel and remove this
/** add listeners to an external quota meter (mvc/user/user-quotameter.js) */
connectToQuotaMeter : function( quotaMeter ){
if( !quotaMeter ){
@@ -431,6 +404,22 @@ var CurrentHistoryPanel = _super.extend(
});
//------------------------------------------------------------------------------ TEMPLATES
CurrentHistoryPanel.prototype.templates = (function(){
var quotaMsgTemplate = BASE_MVC.wrapTemplate([
'<div class="quota-message errormessage">',
_l( 'You are over your disk quota' ), '. ',
_l( 'Tool execution is on hold until your disk usage drops below your allocated quota' ), '.',
'</div>'
], 'history' );
return _.extend( _.clone( _super.prototype.templates ), {
quotaMsg : quotaMsgTemplate
});
}());
//==============================================================================
return {
CurrentHistoryPanel : CurrentHistoryPanel
+96 -257
View File
@@ -23,24 +23,18 @@ define([
TODO:
============================================================================= */
var _super = HPANEL.ReadOnlyHistoryPanel;
var _super = HPANEL.HistoryPanel;
// base class for current-history-panel and used as-is in history/view.mako
/** @class Editable View/Controller for the history model.
* @name HistoryPanel
*
* Allows:
* (everything ReadOnlyHistoryPanel allows)
* (everything HistoryPanel allows)
* changing the name
* displaying and editing tags and annotations
* multi-selection and operations on mulitple hdas
*
* @augments Backbone.View
* @borrows LoggableMixin#logger as #logger
* @borrows LoggableMixin#log as #log
* @constructs
* multi-selection and operations on mulitple content items
*/
var HistoryPanel = _super.extend(
/** @lends HistoryPanel.prototype */{
var HistoryPanelEdit = _super.extend(
/** @lends HistoryPanelEdit.prototype */{
/** logger used to record this.log messages, commonly set to console */
//logger : console,
@@ -56,13 +50,9 @@ var HistoryPanel = _super.extend(
*/
initialize : function( attributes ){
attributes = attributes || {};
_super.prototype.initialize.call( this, attributes );
// ---- set up instance vars
/** selected hda ids */
this.selectedHdaIds = [];
/** last selected hda */
this.lastSelectedViewId = null;
/** editor for tags - sub-view */
this.tagsEditor = null;
/** editor for annotations - sub-view */
@@ -73,52 +63,44 @@ var HistoryPanel = _super.extend(
// states/modes the panel can be in
/** is the panel currently showing the dataset selection controls? */
this.selecting = attributes.selecting || false;
this.annotationEditorShown = attributes.annotationEditorShown || false;
this.tagsEditorShown = attributes.tagsEditorShown || false;
_super.prototype.initialize.call( this, attributes );
this.multiselectActions = attributes.multiselectActions || this._getActions();
},
// ------------------------------------------------------------------------ panel rendering
/** listening for history and HDA events */
_setUpModelEventHandlers : function(){
_super.prototype._setUpModelEventHandlers.call( this );
/** listening for collection events */
_setUpCollectionListeners : function(){
_super.prototype._setUpCollectionListeners.call( this );
this.model.on( 'change:nice_size', this.updateHistoryDiskSize, this );
this.model.contents.on( 'change:deleted', this._handleHdaDeletionChange, this );
this.model.contents.on( 'change:visible', this._handleHdaVisibleChange, this );
this.model.contents.on( 'change:purged', function( hda ){
// hafta get the new nice-size w/o the purged hda
this.collection.on( 'change:deleted', this._handleHdaDeletionChange, this );
this.collection.on( 'change:visible', this._handleHdaVisibleChange, this );
this.collection.on( 'change:purged', function( model ){
// hafta get the new nice-size w/o the purged model
this.model.fetch();
}, this );
return this;
},
/** listening for history and HDA events */
_setUpModelListeners : function(){
_super.prototype._setUpModelListeners.call( this );
this.model.on( 'change:nice_size', this.updateHistoryDiskSize, this );
return this;
},
// ------------------------------------------------------------------------ panel rendering
/** render with history data
* In this override, add tags, annotations, and multi select
* @returns {jQuery} dom fragment as temporary container to be swapped out later
*/
renderModel : function( ){
//TODO: can't call ReadOnlyHistoryPanel?
var $newRender = $( '<div/>' );
/** In this override, add tag and annotation editors and a btn to toggle the selectors */
_buildNewRender : function(){
// create a new render using a skeleton template, render title buttons, render body, and set up events, etc.
var $newRender = _super.prototype._buildNewRender.call( this );
if( !this.model ){ return $newRender; }
$newRender.append( HistoryPanel.templates.historyPanel( this.model.toJSON() ) );
this.$emptyMessage( $newRender ).text( this.emptyMsg );
if( Galaxy && Galaxy.currUser && Galaxy.currUser.id && Galaxy.currUser.id === this.model.get( 'user_id' ) ){
this._renderTags( $newRender );
this._renderAnnotation( $newRender );
}
// search and select available to both anon/logged-in users
$newRender.find( '.history-secondary-actions' ).prepend( this._renderSelectButton() );
$newRender.find( '.history-dataset-actions' ).toggle( this.selecting );
$newRender.find( '.history-secondary-actions' ).prepend( this._renderSearchButton() );
this._setUpBehaviours( $newRender );
// render hda views (if any and any shown (show_deleted/hidden)
this.renderHdas( $newRender );
return $newRender;
},
@@ -127,9 +109,9 @@ var HistoryPanel = _super.extend(
var panel = this;
this.tagsEditor = new TAGS.TagsEditor({
model : this.model,
el : $where.find( '.history-controls .tags-display' ),
el : $where.find( '.controls .tags-display' ),
onshowFirstTime : function(){ this.render(); },
// show hide hda view tag editors when this is shown/hidden
// show hide sub-view tag editors when this is shown/hidden
onshow : function(){
panel.toggleHDATagEditors( true, panel.fxSpeed );
},
@@ -140,7 +122,7 @@ var HistoryPanel = _super.extend(
title : _l( 'Edit history tags' ),
classes : 'history-tag-btn',
faIcon : 'fa-tags'
}).appendTo( $where.find( '.history-secondary-actions' ) )
}).appendTo( $where.find( '.controls .actions' ) )
});
},
/** render the annotation sub-view controller */
@@ -148,9 +130,9 @@ var HistoryPanel = _super.extend(
var panel = this;
this.annotationEditor = new ANNOTATIONS.AnnotationEditor({
model : this.model,
el : $where.find( '.history-controls .annotation-display' ),
el : $where.find( '.controls .annotation-display' ),
onshowFirstTime : function(){ this.render(); },
// show hide hda view annotation editors when this is shown/hidden
// show hide sub-view view annotation editors when this is shown/hidden
onshow : function(){
panel.toggleHDAAnnotationEditors( true, panel.fxSpeed );
},
@@ -161,33 +143,22 @@ var HistoryPanel = _super.extend(
title : _l( 'Edit history annotation' ),
classes : 'history-annotate-btn',
faIcon : 'fa-comment'
}).appendTo( $where.find( '.history-secondary-actions' ) )
}).appendTo( $where.find( '.controls .actions' ) )
});
},
/** button for starting select mode */
_renderSelectButton : function( $where ){
return faIconButton({
title : _l( 'Operations on multiple datasets' ),
classes : 'history-select-btn',
faIcon : 'fa-check-square-o'
});
},
/** Set up HistoryPanel js/widget behaviours
/** Set up HistoryPanelEdit js/widget behaviours
* In this override, add the multi select popup menu and make the name editable
*/
_setUpBehaviours : function( $where ){
_setUpBehaviors : function( $where ){
$where = $where || this.$el;
_super.prototype._setUpBehaviours.call( this, $where );
// anon users shouldn't have access to any of the following
if( !this.model ){
return;
}
_super.prototype._setUpBehaviors.call( this, $where );
if( !this.model ){ return; }
// set up the pupup for actions available when multi selecting
this.actionsPopup = this._setUpDatasetActionsPopup( $where );
if( this.multiselectActions.length ){
this.actionsPopup = new PopupMenu( $where.find( '.list-action-popup-btn' ), this.multiselectActions );
}
// anon users shouldn't have access to any of the following
if( ( !Galaxy.currUser || Galaxy.currUser.isAnonymous() )
@@ -195,20 +166,22 @@ var HistoryPanel = _super.extend(
return;
}
var panel = this;
$where.find( '.history-name' )
.attr( 'title', _l( 'Click to rename history' ) ).tooltip({ placement: 'bottom' })
var panel = this,
nameSelector = '.controls .name';
$where.find( nameSelector )
.attr( 'title', _l( 'Click to rename history' ) )
.tooltip({ placement: 'bottom' })
.make_text_editable({
on_finish: function( newName ){
var previousName = panel.model.get( 'name' );
if( newName && newName !== previousName ){
panel.$el.find( '.history-name' ).text( newName );
panel.$el.find( nameSelector ).text( newName );
panel.model.save({ name: newName })
.fail( function(){
panel.$el.find( '.history-name' ).text( panel.model.previous( 'name' ) );
panel.$el.find( nameSelector ).text( panel.model.previous( 'name' ) );
});
} else {
panel.$el.find( '.history-name' ).text( previousName );
panel.$el.find( nameSelector ).text( previousName );
}
}
});
@@ -217,61 +190,62 @@ var HistoryPanel = _super.extend(
/** return a new popup menu for choosing a multi selection action
* ajax calls made for multiple datasets are queued
*/
_setUpDatasetActionsPopup : function( $where ){
_getActions : function(){
var panel = this,
actions = [
{ html: _l( 'Hide datasets' ), func: function(){
var action = HDA_MODEL.HistoryDatasetAssociation.prototype.hide;
panel.getSelectedHdaCollection().ajaxQueue( action );
panel.getSelectedModels().ajaxQueue( action );
}
},
{ html: _l( 'Unhide datasets' ), func: function(){
var action = HDA_MODEL.HistoryDatasetAssociation.prototype.unhide;
panel.getSelectedHdaCollection().ajaxQueue( action );
panel.getSelectedModels().ajaxQueue( action );
}
},
{ html: _l( 'Delete datasets' ), func: function(){
var action = HDA_MODEL.HistoryDatasetAssociation.prototype['delete'];
panel.getSelectedHdaCollection().ajaxQueue( action );
panel.getSelectedModels().ajaxQueue( action );
}
},
{ html: _l( 'Undelete datasets' ), func: function(){
var action = HDA_MODEL.HistoryDatasetAssociation.prototype.undelete;
panel.getSelectedHdaCollection().ajaxQueue( action );
panel.getSelectedModels().ajaxQueue( action );
}
} ];
}
];
if( panel.purgeAllowed ){
actions.push({
html: _l( 'Permanently delete datasets' ), func: function(){
if( confirm( _l( 'This will permanently remove the data in your datasets. Are you sure?' ) ) ){
var action = HDA_MODEL.HistoryDatasetAssociation.prototype.purge;
panel.getSelectedHdaCollection().ajaxQueue( action );
panel.getSelectedModels().ajaxQueue( action );
}
}
});
}
actions.push( {
html: _l( 'Build Dataset List (Experimental)' ), func: function() {
panel.getSelectedHdaCollection().promoteToHistoryDatasetCollection( panel.model, "list" );
html: _l( 'Build Dataset List' ), func: function() {
panel.getSelectedModels().promoteToHistoryDatasetCollection( panel.model, "list" );
}
});
actions.push( {
// TODO: Only show quick pair if two things selected.
html: _l( 'Build Dataset Pair (Experimental)' ), func: function() {
panel.getSelectedHdaCollection().promoteToHistoryDatasetCollection( panel.model, "paired" );
html: _l( 'Build Dataset Pair' ), func: function() {
panel.getSelectedModels().promoteToHistoryDatasetCollection( panel.model, "paired" );
}
});
actions.push( {
// TODO: Only show quick pair if two things selected.
html: _l( 'Build List of Dataset Pairs (Experimental)' ),
html: _l( 'Build List of Dataset Pairs' ),
func: _.bind( panel._showPairedCollectionModal, panel )
});
return new PopupMenu( $where.find( '.history-dataset-action-popup-btn' ), actions );
return actions;
},
_showPairedCollectionModal : function(){
var panel = this,
datasets = panel.getSelectedHdaCollection().toJSON().filter( function( content ){
datasets = panel.getSelectedModels().toJSON().filter( function( content ){
return content.history_content_type === 'dataset'
&& content.state === STATES.OK;
});
@@ -291,113 +265,53 @@ var HistoryPanel = _super.extend(
}
},
// ------------------------------------------------------------------------ hda sub-views
/** If this hda is deleted and we're not showing deleted hdas, remove the view
* @param {HistoryDataAssociation} the hda to check
*/
_handleHdaDeletionChange : function( hda ){
if( hda.get( 'deleted' ) && !this.storage.get( 'show_deleted' ) ){
this.removeHdaView( this.hdaViews[ hda.id ] );
} // otherwise, the hdaView rendering should handle it
},
/** If this hda is hidden and we're not showing hidden hdas, remove the view
* @param {HistoryDataAssociation} the hda to check
*/
_handleHdaVisibleChange : function( hda ){
if( hda.hidden() && !this.storage.get( 'show_hidden' ) ){
this.removeHdaView( this.hdaViews[ hda.id ] );
} // otherwise, the hdaView rendering should handle it
},
_getContentOptions : function( content ){
var options = _super.prototype._getContentOptions.call( this, content );
// ------------------------------------------------------------------------ sub-views
/** In this override, add purgeAllowed and whether tags/annotation editors should be shown */
_getItemViewOptions : function( model ){
var options = _super.prototype._getItemViewOptions.call( this, model );
_.extend( options, {
selectable : this.selecting,
purgeAllowed : this.purgeAllowed,
//TODO: not working
tagsEditorShown : ( this.tagsEditor && !this.tagsEditor.hidden ),
annotationEditorShown : ( this.annotationEditor && !this.annotationEditor.hidden )
});
return options;
},
/** Set up HistoryPanel listeners for HDAView events. Currently binds:
* HDAView#body-visible, HDAView#body-hidden to store expanded states
* @param {HDAView} hdaView HDAView (base or edit) to listen to
/** If this item is deleted and we're not showing deleted items, remove the view
* @param {Model} the item model to check
*/
_setUpHdaListeners : function( hdaView ){
var historyView = this;
_super.prototype._setUpHdaListeners.call( this, hdaView );
// maintain a list of hdas that are selected
hdaView.on( 'selected', function( hdaView, event ){
if( !event ){ return; }
//this.debug( 'selected', event );
var selectedIds = [];
//this.debug( historyView.lastSelectedViewId, historyView.hdaViews[ historyView.lastSelectedViewId ] );
// shift will select a range, but not set lastSelectedViewId
if( ( event.shiftKey )
&& ( historyView.lastSelectedViewId && _.has( historyView.hdaViews, historyView.lastSelectedViewId ) ) ){
var lastSelectedView = historyView.hdaViews[ historyView.lastSelectedViewId ];
selectedIds = historyView.selectDatasetRange( hdaView, lastSelectedView )
.map( function( view ){ return view.model.id; });
// only
} else {
var id = hdaView.model.id;
historyView.lastSelectedViewId = id;
//this.debug( 'lastSelectedViewId:', historyView.lastSelectedViewId );
selectedIds = [ id ];
}
//this.debug( 'selectedIds:', selectedIds );
historyView.selectedHdaIds = _.union( historyView.selectedHdaIds, selectedIds );
//TODO: might want to use getSelectedHdaViews instead managing these lists with ops
//this.debug( 'selected', historyView.selectedHdaIds );
});
hdaView.on( 'de-selected', function( hdaView, event ){
//this.debug( 'de-selected', event );
var id = hdaView.model.id;
historyView.selectedHdaIds = _.without( historyView.selectedHdaIds, id );
//this.debug( 'de-selected', historyView.selectedHdaIds );
});
_handleHdaDeletionChange : function( itemModel ){
if( itemModel.get( 'deleted' ) && !this.storage.get( 'show_deleted' ) ){
this.removeItemView( itemModel );
}
},
/** toggle the visibility of each hdaView's tagsEditor applying all the args sent to this function */
/** If this item is hidden and we're not showing hidden items, remove the view
* @param {Model} the item model to check
*/
_handleHdaVisibleChange : function( itemModel ){
if( itemModel.hidden() && !this.storage.get( 'show_hidden' ) ){
this.removeItemView( itemModel );
}
},
/** toggle the visibility of each content's tagsEditor applying all the args sent to this function */
toggleHDATagEditors : function( showOrHide ){
var args = arguments;
_.each( this.hdaViews, function( hdaView ){
if( hdaView.tagsEditor ){
hdaView.tagsEditor.toggle.apply( hdaView.tagsEditor, args );
var args = Array.prototype.slice.call( arguments, 1 );
_.each( this.views, function( view ){
if( view.tagsEditor ){
view.tagsEditor.toggle.apply( view.tagsEditor, args );
}
});
},
/** toggle the visibility of each hdaView's annotationEditor applying all the args sent to this function */
/** toggle the visibility of each content's annotationEditor applying all the args sent to this function */
toggleHDAAnnotationEditors : function( showOrHide ){
var args = arguments;
_.each( this.hdaViews, function( hdaView ){
if( hdaView.annotationEditor ){
hdaView.annotationEditor.toggle.apply( hdaView.annotationEditor, args );
}
});
},
/** Remove a view from the panel and if the panel is now empty, re-render
* @param {Int} the id of the hdaView to remove
*/
removeHdaView : function( hdaView ){
if( !hdaView ){ return; }
var panel = this;
hdaView.$el.fadeOut( panel.fxSpeed, function(){
hdaView.off();
hdaView.remove();
delete panel.hdaViews[ hdaView.model.id ];
if( _.isEmpty( panel.hdaViews ) ){
panel.trigger( 'empty-history', panel );
panel._renderEmptyMsg();
var args = Array.prototype.slice.call( arguments, 1 );
_.each( this.views, function( view ){
if( view.annotationEditor ){
view.annotationEditor.toggle.apply( view.annotationEditor, args );
}
});
},
@@ -405,9 +319,7 @@ var HistoryPanel = _super.extend(
// ------------------------------------------------------------------------ panel events
/** event map */
events : _.extend( _.clone( _super.prototype.events ), {
'click .history-select-btn' : 'toggleSelectors',
'click .history-select-all-datasets-btn' : 'selectAllDatasets',
'click .history-deselect-all-datasets-btn' : 'deselectAllDatasets'
'click .show-selectors-btn' : 'toggleSelectors'
}),
/** Update the history size display (curr. upper right of panel).
@@ -416,88 +328,15 @@ var HistoryPanel = _super.extend(
this.$el.find( '.history-size' ).text( this.model.get( 'nice_size' ) );
},
// ........................................................................ multi-select of hdas
//TODO: to toggle showOrHide pattern
/** show selectors on all visible hdas and associated controls */
showSelectors : function( speed ){
speed = ( speed !== undefined )?( speed ):( this.fxSpeed );
this.selecting = true;
this.$( '.history-dataset-actions' ).slideDown( speed );
_.each( this.hdaViews, function( view ){
view.showSelector();
});
this.selectedHdaIds = [];
this.lastSelectedViewId = null;
},
/** hide selectors on all visible hdas and associated controls */
hideSelectors : function( speed ){
speed = ( speed !== undefined )?( speed ):( this.fxSpeed );
this.selecting = false;
this.$( '.history-dataset-actions' ).slideUp( speed );
_.each( this.hdaViews, function( view ){
view.hideSelector();
});
this.selectedHdaIds = [];
this.lastSelectedViewId = null;
},
/** show or hide selectors on all visible hdas and associated controls */
toggleSelectors : function(){
if( !this.selecting ){
this.showSelectors();
} else {
this.hideSelectors();
}
},
/** select all visible hdas */
selectAllDatasets : function( event ){
_.each( this.hdaViews, function( view ){
view.select( event );
});
},
/** deselect all visible hdas */
deselectAllDatasets : function( event ){
this.lastSelectedViewId = null;
_.each( this.hdaViews, function( view ){
view.deselect( event );
});
},
/** select a range of datasets between A and B */
selectDatasetRange : function( viewA, viewB ){
var range = this.hdaViewRange( viewA, viewB );
_.each( range, function( view ){
view.select();
});
return range;
},
/** return an array of all currently selected hdas */
getSelectedHdaViews : function(){
return _.filter( this.hdaViews, function( v ){
return v.selected;
});
},
/** return an HdaCollection of the models of all currenly selected hdas */
getSelectedHdaCollection : function(){
return new HISTORY_CONTENTS.HistoryContents( _.map( this.getSelectedHdaViews(), function( hdaView ){
return hdaView.model;
}), { historyId: this.model.id });
},
// ........................................................................ misc
/** Return a string rep of the history */
toString : function(){
return 'HistoryPanel(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
return 'HistoryPanelEdit(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
}
});
//==============================================================================
return {
HistoryPanel : HistoryPanel
HistoryPanelEdit : HistoryPanelEdit
};
});
File diff suppressed because it is too large Load Diff
+332
View File
@@ -0,0 +1,332 @@
define([
'mvc/base-mvc',
'utils/localization'
], function( BASE_MVC, _l ){
//==============================================================================
/** A view which, when first rendered, shows only summary data/attributes, but
* can be expanded to show further details (and optionally fetch those
* details from the server).
*/
var ExpandableView = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend({
//TODO: Although the reasoning behind them is different, this shares a lot with HiddenUntilActivated above: combine them
//PRECONDITION: model must have method hasDetails
//PRECONDITION: subclasses must have templates.el and templates.details
initialize : function( attributes ){
/** are the details of this view expanded/shown or not? */
this.expanded = attributes.expanded || false;
//this.log( '\t expanded:', this.expanded );
this.fxSpeed = attributes.fxSpeed || this.fxSpeed;
},
// ........................................................................ render main
/** jq fx speed */
fxSpeed : 'fast',
/** Render this content, set up ui.
* @param {Number or String} speed the speed of the render
*/
render : function( speed ){
var $newRender = this._buildNewRender();
this._setUpBehaviors( $newRender );
this._queueNewRender( $newRender, speed );
return this;
},
/** Build a temp div containing the new children for the view's $el.
* If the view is already expanded, build the details as well.
*/
_buildNewRender : function(){
// create a new render using a skeleton template, render title buttons, render body, and set up events, etc.
var $newRender = $( this.templates.el( this.model.toJSON(), this ) );
if( this.expanded ){
this.$details( $newRender ).replaceWith( this._renderDetails().show() );
}
return $newRender;
},
/** Fade out the old el, swap in the new contents, then fade in.
* @param {Number or String} speed jq speed to use for rendering effects
* @fires rendered when rendered
*/
_queueNewRender : function( $newRender, speed ) {
speed = ( speed === undefined )?( this.fxSpeed ):( speed );
var view = this;
$( view ).queue( 'fx', [
function( next ){ this.$el.fadeOut( speed, next ); },
function( next ){
view._swapNewRender( $newRender );
next();
},
function( next ){ this.$el.fadeIn( speed, next ); },
function( next ){
this.trigger( 'rendered', view );
next();
}
]);
},
/** empty out the current el, move the $newRender's children in */
_swapNewRender : function( $newRender ){
return this.$el.empty().attr( 'class', this.className ).append( $newRender.children() );
},
/** set up js behaviors, event handlers for elements within the given container
* @param {jQuery} $container jq object that contains the elements to process (defaults to this.$el)
*/
_setUpBehaviors : function( $where ){
$where = $where || this.$el;
// set up canned behavior on children (bootstrap, popupmenus, editable_text, etc.)
//make_popup_menus( $where );
$where.find( '[title]' ).tooltip({ placement : 'bottom' });
},
// ......................................................................... details
/** shortcut to details DOM (as jQ) */
$details : function( $where ){
$where = $where || this.$el;
return $where.find( '.details' );
},
/** build the DOM for the details and set up behaviors on it */
_renderDetails : function(){
var $newDetails = $( this.templates.details( this.model.toJSON(), this ) );
this._setUpBehaviors( $newDetails );
return $newDetails;
},
// ......................................................................... expansion/details
/** Show or hide the details
* @param {Boolean} expand if true, expand; if false, collapse
*/
toggleExpanded : function( expand ){
expand = ( expand === undefined )?( !this.expanded ):( expand );
if( expand ){
this.expand();
} else {
this.collapse();
}
return this;
},
/** Render and show the full, detailed body of this view including extra data and controls.
* note: if the model does not have detailed data, fetch that data before showing the body
* @fires expanded when a body has been expanded
*/
expand : function(){
var view = this;
return view._fetchModelDetails()
.always(function(){
var $newDetails = view._renderDetails();
view.$details().replaceWith( $newDetails );
// needs to be set after the above or the slide will not show
view.expanded = true;
$newDetails.slideDown( view.fxSpeed, function(){
view.trigger( 'expanded', view );
});
});
},
/** Check for model details and, if none, fetch them.
* @returns {jQuery.promise} the model.fetch.xhr if details are being fetched, an empty promise if not
*/
_fetchModelDetails : function(){
if( !this.model.hasDetails() ){
return this.model.fetch();
}
return jQuery.when();
},
/** Hide the body/details of an HDA.
* @fires collapsed when a body has been collapsed
*/
collapse : function(){
var view = this;
view.expanded = false;
this.$details().slideUp( view.fxSpeed, function(){
view.trigger( 'collapsed', view );
});
}
});
//==============================================================================
/** A view that is displayed in some larger list/grid/collection.
* Inherits from Expandable, Selectable, Draggable.
* The DOM contains warnings, a title bar, and a series of primary action controls.
* Primary actions are meant to be easily accessible item functions (such as delete)
* that are rendered in the title bar.
*
* Details are rendered when the user clicks the title bar or presses enter/space when
* the title bar is in focus.
*
* Designed as a base class for history panel contents - but usable elsewhere (I hope).
*/
var ListItemView = ExpandableView.extend(
BASE_MVC.mixin( BASE_MVC.SelectableViewMixin, BASE_MVC.DraggableViewMixin, {
//TODO: that's a little contradictory
tagName : 'div',
className : 'list-item',
/** Set up the base class and all mixins */
initialize : function( attributes ){
ExpandableView.prototype.initialize.call( this, attributes );
BASE_MVC.SelectableViewMixin.initialize.call( this, attributes );
BASE_MVC.DraggableViewMixin.initialize.call( this, attributes );
},
// ........................................................................ rendering
/** In this override, call methods to build warnings, titlebar and primary actions */
_buildNewRender : function(){
var $newRender = ExpandableView.prototype._buildNewRender.call( this );
$newRender.find( '.warnings' ).replaceWith( this._renderWarnings() );
$newRender.find( '.title-bar' ).replaceWith( this._renderTitleBar() );
$newRender.find( '.primary-actions' ).append( this._renderPrimaryActions() );
$newRender.find( '.subtitle' ).replaceWith( this._renderSubtitle() );
return $newRender;
},
/** In this override, render the selector controls and set up dragging before the swap */
_swapNewRender : function( $newRender ){
ExpandableView.prototype._swapNewRender.call( this, $newRender );
if( this.selectable ){ this.showSelector( 0 ); }
if( this.draggable ){ this.draggableOn(); }
return this.$el;
},
/** Render any warnings the item may need to show (e.g. "I'm deleted") */
_renderWarnings : function(){
var view = this,
$warnings = $( '<div class="warnings"></div>' ),
json = view.model.toJSON();
//TODO:! unordered (map)
_.each( view.templates.warnings, function( templateFn ){
$warnings.append( $( templateFn( json, view ) ) );
});
return $warnings;
},
/** Render the title bar (the main/exposed SUMMARY dom element) */
_renderTitleBar : function(){
return $( this.templates.titleBar( this.model.toJSON(), this ) );
},
/** Return an array of jQ objects containing common/easily-accessible item controls */
_renderPrimaryActions : function(){
// override this
return [];
},
/** Render the title bar (the main/exposed SUMMARY dom element) */
_renderSubtitle : function(){
return $( this.templates.subtitle( this.model.toJSON(), this ) );
},
// ......................................................................... events
/** event map */
events : {
// expand the body when the title is clicked or when in focus and space or enter is pressed
'click .title-bar' : '_clickTitleBar',
'keydown .title-bar' : '_keyDownTitleBar',
// dragging - don't work, originalEvent === null
//'dragstart .dataset-title-bar' : 'dragStartHandler',
//'dragend .dataset-title-bar' : 'dragEndHandler'
'click .selector' : 'toggleSelect'
},
/** expand when the title bar is clicked */
_clickTitleBar : function( event ){
event.stopPropagation();
this.toggleExpanded();
},
/** expand when the title bar is in focus and enter or space is pressed */
_keyDownTitleBar : function( event ){
// bail (with propagation) if keydown and not space or enter
var KEYCODE_SPACE = 32, KEYCODE_RETURN = 13;
if( event && ( event.type === 'keydown' )
&&( event.keyCode === KEYCODE_SPACE || event.keyCode === KEYCODE_RETURN ) ){
this.toggleExpanded();
event.stopPropagation();
return false;
}
return true;
},
// ......................................................................... misc
/** String representation */
toString : function(){
var modelString = ( this.model )?( this.model + '' ):( '(no model)' );
return 'ListItemView(' + modelString + ')';
}
}));
// ............................................................................ TEMPLATES
/** underscore templates */
ListItemView.prototype.templates = (function(){
//TODO: move to require text! plugin
var elTemplato = BASE_MVC.wrapTemplate([
'<div class="list-element">',
// errors, messages, etc.
'<div class="warnings"></div>',
// multi-select checkbox
'<div class="selector">',
'<span class="fa fa-2x fa-square-o"></span>',
'</div>',
// space for title bar buttons - gen. floated to the right
'<div class="primary-actions"></div>',
'<div class="title-bar"></div>',
// expandable area for more details
'<div class="details"></div>',
'</div>'
]);
var warnings = {};
var titleBarTemplate = BASE_MVC.wrapTemplate([
// adding a tabindex here allows focusing the title bar and the use of keydown to expand the dataset display
'<div class="title-bar clear" tabindex="0">',
//TODO: prob. belongs in dataset-list-item
'<span class="state-icon"></span>',
'<div class="title">',
'<span class="name"><%- element.name %></span>',
'</div>',
'<div class="subtitle"></div>',
'</div>'
], 'element' );
var subtitleTemplate = BASE_MVC.wrapTemplate([
// override this
'<div class="subtitle"></div>'
]);
var detailsTemplate = BASE_MVC.wrapTemplate([
// override this
'<div class="details"></div>'
]);
return {
el : elTemplato,
warnings : warnings,
titleBar : titleBarTemplate,
subtitle : subtitleTemplate,
details : detailsTemplate
};
}());
//==============================================================================
return {
ExpandableView : ExpandableView,
ListItemView : ListItemView
};
});
@@ -1,12 +1,24 @@
define([
"mvc/list/list-item",
"mvc/base-mvc",
"utils/localization"
], function( BASE_MVC, _l ){
/* =============================================================================
], function( LIST_ITEM, BASE_MVC, _l ){
/* ============================================================================
TODO:
============================================================================= */
/** @class List that contains ListItemViews.
============================================================================ */
/** @class View for a list/collection of models and the sub-views of those models.
* Sub-views must (at least have the interface if not) inherit from ListItemView.
* (For a list panel that also includes some 'container' model (History->HistoryContents)
* use ModelWithListPanel)
*
* Allows for:
* searching collection/sub-views
* selecting/multi-selecting sub-views
*
* Currently used:
* for dataset/dataset-choice
* as superclass of ModelListPanel
*/
var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
/** @lends ReadOnlyHistoryPanel.prototype */{
@@ -15,7 +27,9 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
//logger : console,
/** class to use for constructing the sub-views */
viewClass : BASE_MVC.ListItemView,
viewClass : LIST_ITEM.ListItemView,
/** class to used for constructing collection of sub-view models */
collectionClass : Backbone.Collection,
tagName : 'div',
className : 'list-panel',
@@ -23,10 +37,15 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
/** (in ms) that jquery effects will use */
fxSpeed : 'fast',
/** string to display when the model has no hdas */
/** string to display when the collection has no contents */
emptyMsg : _l( 'This list is empty' ),
/** string to no hdas match the search terms */
/** displayed when no items match the search terms */
noneFoundMsg : _l( 'No matching items found' ),
/** string used for search placeholder */
searchPlaceholder : _l( 'search' ),
/** actions available for multiselected items */
multiselectActions : [],
// ......................................................................... SET UP
/** Set up the view, set up storage, bind listeners to HistoryContents events
@@ -67,21 +86,42 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
/** list item views */
this.views = [];
/** list item models */
this.collection = attributes.collection || ( new Backbone.Collection([]) );
this.collection = attributes.collection || ( new this.collectionClass([]) );
/** filter fns run over collection items to see if they should show in the list */
this.filters = attributes.filters || [];
/** override $scrollContainer fn via attributes - fn should return jq for elem to call scrollTo on */
this.$scrollContainer = attributes.$scrollContainer || this.$scrollContainer;
//TODO: remove
this.title = attributes.title || '';
this.subtitle = attributes.subtitle || '';
// allow override of multiselectActions through attributes
this.multiselectActions = attributes.multiselectActions || this.multiselectActions;
/** the popup displayed when 'for all selected...' is clicked */
this.actionsPopup = null;
this._setUpListeners();
},
/** free any sub-views the list has */
freeViews : function(){
//TODO: stopListening? remove?
_.each( this.views, function( view ){
view.off();
});
this.views = [];
return this;
},
// ------------------------------------------------------------------------ listeners
/** create any event listeners for the list
*/
_setUpListeners : function(){
this.off();
this.on( 'error', function( model, xhr, options, msg, details ){
//this.errorHandler( model, xhr, options, msg, details );
console.error( model, xhr, options, msg, details );
@@ -112,21 +152,19 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
return this;
},
/** free any sub-views the list has */
freeViews : function(){
//TODO: stopListening? remove?
this.views = [];
return this;
},
// ------------------------------------------------------------------------ item listeners
/** listening for history and HDA events */
/** listening for collection events */
_setUpCollectionListeners : function(){
this.log( this + '._setUpCollectionListeners', this.collection );
this.collection.off();
// bubble up error events
this.collection.on( 'error', function( model, xhr, options, msg, details ){
this.trigger( 'error', model, xhr, options, msg, details );
}, this );
this.collection.on( 'reset', function(){
this.renderItems();
}, this );
this.collection.on( 'add', this.addItemView, this );
this.collection.on( 'remove', this.removeItemView, this );
@@ -139,8 +177,9 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
return this;
},
/** listening for history and HDA events */
/** listening for sub-view events that bubble up with the 'view:' prefix */
_setUpViewListeners : function(){
this.log( this + '._setUpViewListeners' );
// shift to select a range
this.on( 'view:selected', function( view, ev ){
@@ -155,6 +194,11 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
this.selected.push( view.model.id );
this.lastSelected = view.model.id;
}, this );
this.on( 'view:de-selected', function( view, ev ){
this.selected = _.without( this.selected, view.model.id );
//this.lastSelected = view.model.id;
}, this );
},
// ------------------------------------------------------------------------ rendering
@@ -162,6 +206,7 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
* @param {Number or String} speed the speed of the render
*/
render : function( speed ){
this.log( this + '.render', speed );
var $newRender = this._buildNewRender();
this._setUpBehaviors( $newRender );
this._queueNewRender( $newRender, speed );
@@ -171,9 +216,9 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
/** Build a temp div containing the new children for the view's $el.
*/
_buildNewRender : function(){
// create a new render using a skeleton template, render title buttons, render body, and set up events, etc.
var json = this.model? this.model.toJSON() : {},
$newRender = $( this.templates.el( json, this ) );
this.debug( this + '(ListPanel)._buildNewRender' );
var $newRender = $( this.templates.el( {}, this ) );
this._renderControls( $newRender );
this._renderTitle( $newRender );
this._renderSubtitle( $newRender );
this._renderSearch( $newRender );
@@ -181,6 +226,15 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
return $newRender;
},
/** Build a temp div containing the new children for the view's $el.
*/
_renderControls : function( $newRender ){
this.debug( this + '(ListPanel)._renderControls' );
var $controls = $( this.templates.controls( {}, this ) );
$newRender.find( '.controls' ).replaceWith( $controls );
return $controls;
},
/**
*/
_renderTitle : function( $where ){
@@ -201,17 +255,18 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
*/
_queueNewRender : function( $newRender, speed ) {
speed = ( speed === undefined )?( this.fxSpeed ):( speed );
var view = this;
var panel = this;
panel.log( '_queueNewRender:', $newRender, speed );
$( view ).queue( 'fx', [
$( panel ).queue( 'fx', [
function( next ){ this.$el.fadeOut( speed, next ); },
function( next ){
view._swapNewRender( $newRender );
panel._swapNewRender( $newRender );
next();
},
function( next ){ this.$el.fadeIn( speed, next ); },
function( next ){
view.trigger( 'rendered', view );
panel.trigger( 'rendered', panel );
next();
}
]);
@@ -234,7 +289,7 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
// ------------------------------------------------------------------------ sub-$element shortcuts
/** the scroll container for this panel - can be $el, $el.parent(), or grandparent depending on context */
$scrollContainer : function(){
// override
// override or set via attributes.$scrollContainer
return this.$el.parent().parent();
},
/** */
@@ -242,8 +297,8 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
return ( $where || this.$el ).find( '.list-items' );
},
/** container where list messages are attached */
$messages : function( $where ){
return ( $where || this.$el ).find( '.message-container' );
$messages : function( $where ){
return ( $where || this.$el ).find( '.messages' );
},
/** the message displayed when no views can be shown (no views, none matching search) */
$emptyMessage : function( $where ){
@@ -252,52 +307,50 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
// ------------------------------------------------------------------------ hda sub-views
/**
* @param {jQuery} $whereTo what dom element to prepend the HDA views to
* @param {jQuery} $whereTo what dom element to prepend the sub-views to
* @returns the visible item views
*/
renderItems : function( $whereTo ){
$whereTo = $whereTo || this.$el;
var list = this,
newViews = [];
var panel = this;
panel.log( this + '.renderItems', $whereTo );
var $list = this.$list( $whereTo ),
item$els = this._filterCollection().map( function( itemModel ){
var $list = panel.$list( $whereTo );
//TODO: free prev. views?
panel.views = panel._filterCollection().map( function( itemModel ){
//TODO: creates views each time - not neccessarily good
var view = list._createItemView( itemModel );
newViews.push( view );
return view.render( 0 ).$el;
return panel._createItemView( itemModel ).render( 0 );
});
this.debug( item$els );
this.debug( newViews );
//panel.debug( item$els );
//panel.debug( newViews );
$list.empty();
if( item$els.length ){
$list.append( item$els );
this.$emptyMessage( $whereTo ).hide();
if( panel.views.length ){
panel._attachItems( $whereTo );
panel.$emptyMessage( $whereTo ).hide();
} else {
this._renderEmptyMessage( $whereTo ).show();
panel._renderEmptyMessage( $whereTo ).show();
}
this.views = newViews;
return newViews;
return panel.views;
},
/**
*/
_filterCollection : function(){
// override this
var list = this;
return list.collection.filter( _.bind( list._filterItem, list ) );
var panel = this;
return panel.collection.filter( _.bind( panel._filterItem, panel ) );
},
/**
*/
_filterItem : function( model ){
// override this
var list = this;
return ( _.every( list.filters.map( function( fn ){ return fn.call( model ); }) ) )
&& ( !list.searchFor || model.matchesAll( list.searchFor ) );
var panel = this;
return ( _.every( panel.filters.map( function( fn ){ return fn.call( model ); }) ) )
&& ( !panel.searchFor || model.matchesAll( panel.searchFor ) );
},
/**
@@ -312,11 +365,15 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
return view;
},
/**
*/
_getItemViewClass : function( model ){
// override this
return this.viewClass;
},
/**
*/
_getItemViewOptions : function( model ){
// override this
return {
@@ -332,11 +389,12 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
/**
*/
_setUpItemViewListeners : function( view ){
var list = this;
var panel = this;
// send all events to the panel, re-namspaceing them with the view prefix
view.on( 'all', function(){
var args = Array.prototype.slice.call( arguments, 0 );
args[0] = 'view:' + args[0];
list.trigger.apply( list, args );
panel.trigger.apply( panel, args );
});
// debugging
@@ -345,12 +403,21 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
// this.log( this + '(view)', arguments );
// }, this );
//}
return panel;
},
/**
*/
_attachItems : function( $whereTo ){
this.$list( $whereTo ).append( this.views.map( function( view ){
return view.$el;
}));
return this;
},
/** render the empty/none-found message */
_renderEmptyMessage : function( $whereTo ){
//this.debug( '_renderEmptyMessage', $whereTo, this.searchFor );
this.debug( '_renderEmptyMessage', $whereTo, this.searchFor );
var text = this.searchFor? this.noneFoundMsg : this.emptyMsg;
return this.$emptyMessage( $whereTo ).text( text );
},
@@ -374,37 +441,45 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
*/
addItemView : function( model, collection, options ){
this.log( this + '.addItemView:', model );
var list = this;
if( !this._filterItem( model ) ){ return undefined; }
var panel = this;
if( !panel._filterItem( model ) ){ return undefined; }
//TODO: sorted? position?
var view = list._createItemView( model );
this.views.push( view );
var view = panel._createItemView( model );
panel.views.push( view );
$( view ).queue( 'fx', [
function( next ){ list.$emptyMessage().fadeOut( list.fxSpeed, next ); },
function( next ){ panel.$emptyMessage().fadeOut( panel.fxSpeed, next ); },
function( next ){
//TODO: auto render?
list.$list().append( view.render().$el );
// slide down?
panel.$list().append( view.render().$el );
next();
}
]);
return view;
},
/**
*/
/** */
removeItemView : function( model, collection, options ){
this.log( this + '.removeItemView:', model );
var list = this,
view = list.viewFromModel( model );
var panel = this,
view = panel.viewFromModel( model );
if( !view ){ return undefined; }
this.views = _.without( this.views, view );
view.remove();
if( !this.views.length ){
list._renderEmptyMessage().fadeIn( list.fxSpeed );
}
// use anonymous queue here - since remove can happen multiple times
$({}).queue( 'fx', [
function( next ){ view.$el.fadeOut( panel.fxSpeed, next ); },
function( next ){
panel.views = _.without( panel.views, view );
view.remove();
if( !panel.views.length ){
panel._renderEmptyMessage().fadeIn( panel.fxSpeed, next );
} else {
next();
}
}
]);
return view;
},
@@ -420,6 +495,16 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
return undefined;
},
/** get views based on model.id */
viewFromModelId : function( id ){
for( var i=0; i<this.views.length; i++ ){
if( this.views[i].model.id === id ){
return this.views[i];
}
}
return undefined;
},
/** get views based on model properties
*/
viewsWhereModel : function( properties ){
@@ -429,9 +514,9 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
var json = view.model.toJSON();
//console.debug( '\t', json, properties );
for( var key in properties ){
if( properties.hasOwnPropery( key ) ){
if( properties.hasOwnProperty( key ) ){
//console.debug( '\t\t', json[ key ], view.model.properties[ key ] );
if( json[ key ] !== view.model.properties[ key ] ){
if( json[ key ] !== view.model.get( key ) ){
return false;
}
}
@@ -462,7 +547,7 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
// ------------------------------------------------------------------------ searching
/** render a search input for filtering datasets shown
* (see the search section in the HDA model for implementation of the actual searching)
* (see SearchableMixin in base-mvc for implementation of the actual searching)
* return will start the search
* esc will clear the search
* clicking the clear button will clear the search
@@ -470,7 +555,7 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
*/
_renderSearch : function( $where ){
$where.find( '.controls .search-input' ).searchInput({
placeholder : 'search',
placeholder : this.searchPlaceholder,
initialVal : this.searchFor,
onfirstsearch : _.bind( this._firstSearch, this ),
onsearch : _.bind( this.searchItems, this ),
@@ -502,7 +587,7 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
},
// ------------------------------------------------------------------------ selection
/** show selectors on all visible hdas and associated controls */
/** show selectors on all visible itemViews and associated controls */
showSelectors : function( speed ){
speed = ( speed !== undefined )?( speed ):( this.fxSpeed );
this.selecting = true;
@@ -510,11 +595,11 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
_.each( this.views, function( view ){
view.showSelector( speed );
});
this.selected = [];
this.lastSelected = null;
//this.selected = [];
//this.lastSelected = null;
},
/** hide selectors on all visible hdas and associated controls */
/** hide selectors on all visible itemViews and associated controls */
hideSelectors : function( speed ){
speed = ( speed !== undefined )?( speed ):( this.fxSpeed );
this.selecting = false;
@@ -526,7 +611,7 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
this.lastSelected = null;
},
/** show or hide selectors on all visible hdas and associated controls */
/** show or hide selectors on all visible itemViews and associated controls */
toggleSelectors : function(){
if( !this.selecting ){
this.showSelectors();
@@ -535,14 +620,14 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
}
},
/** select all visible hdas */
/** select all visible items */
selectAll : function( event ){
_.each( this.views, function( view ){
view.select( event );
});
},
/** deselect all visible hdas */
/** deselect all visible items */
deselectAll : function( event ){
this.lastSelected = null;
_.each( this.views, function( view ){
@@ -559,14 +644,14 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
return range;
},
/** return an array of all currently selected hdas */
/** return an array of all currently selected itemViews */
getSelectedViews : function(){
return _.filter( this.views, function( v ){
return v.selected;
});
},
/** return an collection of the models of all currenly selected hdas */
/** return a collection of the models of all currenly selected items */
getSelectedModels : function(){
return new this.collection.constructor( _.map( this.getSelectedViews(), function( view ){
return view.model;
@@ -577,9 +662,11 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
//TODO: questionable
/** hide the $el and display a loading indicator (in the $el's parent) when loading new data */
_showLoadingIndicator : function( msg, speed, callback ){
this.debug( '_showLoadingIndicator', this.indicator, msg, speed, callback );
speed = ( speed !== undefined )?( speed ):( this.fxSpeed );
if( !this.indicator ){
this.indicator = new LoadingIndicator( this.$el, this.$el.parent() );
this.debug( '\t created', this.indicator );
}
if( !this.$el.is( ':visible' ) ){
this.indicator.show( 0, callback );
@@ -591,6 +678,7 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
/** hide the loading indicator */
_hideLoadingIndicator : function( speed, callback ){
this.debug( '_hideLoadingIndicator', this.indicator, speed, callback );
speed = ( speed !== undefined )?( speed ):( this.fxSpeed );
if( this.indicator ){
this.indicator.hide( speed, callback );
@@ -617,9 +705,15 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
/** */
scrollToItem : function( view ){
if( !view ){ return; }
if( !view ){ return this; }
var itemTop = view.$el.offset().top;
this.$scrollContainer().scrollTop( itemTop );
return this;
},
/** Scrolls the panel to show the content with the given id. */
scrollToId : function( id ){
return this.scrollToItem( this.viewFromModelId( id ) );
},
// ------------------------------------------------------------------------ panel events
@@ -630,7 +724,7 @@ var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
},
// ------------------------------------------------------------------------ misc
/** Return a string rep of the history */
/** Return a string rep of the panel */
toString : function(){
return 'ListPanel(' + this.collection + ')';
}
@@ -644,44 +738,184 @@ ListPanel.prototype.templates = (function(){
var elTemplate = BASE_MVC.wrapTemplate([
// temp container
'<div>',
'<div class="controls">',
'<div class="title">',
'<div class="name"><%= model.name || view.title %></div>',
'</div>',
'<div class="subtitle"><%= view.subtitle %></div>',
'<div class="actions"></div>',
'<div class="messages"></div>',
'<div class="search">',
'<div class="search-input"></div>',
'</div>',
'<div class="list-actions">',
'<div class="btn-group">',
'<button class="select-all btn btn-default"',
'data-mode="select">', _l( 'All' ), '</button>',
'<button class="deselect-all btn btn-default"',
'data-mode="select">', _l( 'None' ), '</button>',
'</div>',
//'<button class="action-popup-btn btn btn-default">',
// _l( 'For all selected' ), '...',
//'</button>',
'</div>',
'</div>',
'<div class="controls"></div>',
'<div class="list-items"></div>',
'<div class="empty-message infomessagesmall"></div>',
'</div>'
]);
var controlsTemplate = BASE_MVC.wrapTemplate([
'<div class="controls">',
'<div class="title">',
'<div class="name"><%= view.title %></div>',
'</div>',
'<div class="subtitle"><%= view.subtitle %></div>',
'<div class="actions"></div>',
'<div class="messages"></div>',
'<div class="search">',
'<div class="search-input"></div>',
'</div>',
'<div class="list-actions">',
'<div class="btn-group">',
'<button class="select-all btn btn-default"',
'data-mode="select">', _l( 'All' ), '</button>',
'<button class="deselect-all btn btn-default"',
'data-mode="select">', _l( 'None' ), '</button>',
'</div>',
//'<button class="list-action-popup-btn btn btn-default">',
// _l( 'For all selected' ), '...',
//'</button>',
'</div>',
'</div>'
]);
return {
el : elTemplate
el : elTemplate,
controls : controlsTemplate
};
}());
//=============================================================================
/** View for a model that has a sub-collection (e.g. History, DatasetCollection)
*
*
*/
var ModelListPanel = ListPanel.extend({
//==============================================================================
/** key of attribute in model to assign to this.collection */
modelCollectionKey : 'contents',
initialize : function( attributes ){
ListPanel.prototype.initialize.call( this, attributes );
this.selecting = ( attributes.selecting !== undefined )? attributes.selecting : false;
// ---- instance vars
// don't render when setting the first time
this.setModel( this.model, attributes );
},
/** release/free/shutdown old models and set up panel for new models
* @fires new-model with the panel as parameter
*/
setModel : function( model, attributes ){
attributes = attributes || {};
this.debug( this + '.setModel:', model, attributes );
this.freeModel();
this.freeViews();
if( model ){
// set up the new model with user, logger, storage, events
this.model = model;
if( this.logger ){
this.model.logger = this.logger;
}
this._setUpModelListeners();
//TODO: relation btwn model, collection becoming tangled here
// free the collection, and assign the new collection to either
// the model[ modelCollectionKey ], attributes.collection, or an empty vanilla collection
this.collection.off();
this.collection = ( this.model[ this.modelCollectionKey ] )?
this.model[ this.modelCollectionKey ]:
( attributes.collection || ( new this.collectionClass([]) ) );
this._setUpCollectionListeners();
this.trigger( 'new-model', this );
}
return this;
},
/** free the current model and all listeners for it, free any views for the model */
freeModel : function(){
// stop/release the previous model, and clear cache to sub-views
if( this.model ){
this.stopListening( this.model );
//TODO: see base-mvc
//this.model.free();
//this.model = null;
}
return this;
},
// ------------------------------------------------------------------------ listening
/** listening for model events */
_setUpModelListeners : function(){
// override
this.log( this + '._setUpModelListeners', this.model );
// bounce model errors up to the panel
this.model.on( 'error', function(){
//TODO: namespace?
//var args = Array.prototype.slice.call( arguments, 0 );
//args[0] = 'model:' + args[0];
this.trigger.apply( panel, arguments );
}, this );
return this;
},
/** Build a temp div containing the new children for the view's $el.
*/
_renderControls : function( $newRender ){
this.debug( this + '(ListPanel)._renderControls' );
var json = this.model? this.model.toJSON() : {},
$controls = $( this.templates.controls( json, this ) );
$newRender.find( '.controls' ).replaceWith( $controls );
this.debug( '\t .controls:', this.$( '.controls' ) );
this.debug( '\t $controls:', $controls );
return $controls;
},
// ------------------------------------------------------------------------ misc
/** Return a string rep of the panel */
toString : function(){
return 'ModelListPanel(' + this.model + ')';
}
});
// ............................................................................ TEMPLATES
/** underscore templates */
ModelListPanel.prototype.templates = (function(){
//TODO: move to require text! plugin
var controlsTemplate = BASE_MVC.wrapTemplate([
'<div class="controls">',
'<div class="title">',
'<div class="name"><%= model.name %></div>',
'</div>',
'<div class="subtitle"><%= view.subtitle %></div>',
'<div class="actions"></div>',
'<div class="messages"></div>',
'<div class="search">',
'<div class="search-input"></div>',
'</div>',
'<div class="list-actions">',
'<div class="btn-group">',
'<button class="select-all btn btn-default"',
'data-mode="select">', _l( 'All' ), '</button>',
'<button class="deselect-all btn btn-default"',
'data-mode="select">', _l( 'None' ), '</button>',
'</div>',
//'<button class="list-action-popup-btn btn btn-default">',
// _l( 'For all selected' ), '...',
//'</button>',
'</div>',
'</div>'
]);
return _.extend( _.clone( ListPanel.prototype.templates ), {
controls : controlsTemplate
});
}());
//=============================================================================
return {
ListPanel: ListPanel
ListPanel : ListPanel,
ModelListPanel : ModelListPanel
};
});
+2 -1
View File
@@ -157,6 +157,7 @@ define(['mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
// trigger refresh
self.refresh();
self._submit();
}
});
},
@@ -177,7 +178,7 @@ define(['mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
// submit
_submit: function() {
console.log(this.tree.jobDictionary());
console.log(this.tree.finalize());
}
});
+86 -61
View File
@@ -11,24 +11,23 @@ return Backbone.Model.extend({
// creates tree structure
refresh: function() {
// check if section is available
if (!this.app.section) {
return {};
}
// create dictionary
this.dict = {};
// create xml object
this.xml = $('<div/>');
// check if section is available
if (!this.app.section) {
return {};
}
// fill dictionary
this._iterate(this.app.section.$el, this.dict, this.xml);
},
// convert to job dictionary
jobDictionary: function() {
finalize: function() {
// link this
var self = this;
@@ -38,22 +37,48 @@ return Backbone.Model.extend({
// converter between raw dictionary and job dictionary
function convert(identifier, head) {
for (var i in head) {
if (head[i].input) {
var input = head[i].input;
var job_input_id = identifier + input.name;
var node = head[i];
if (node.input) {
// get node
var input = node.input;
if (input.type == 'repeat') {
// create identifier
var job_input_id = identifier;
if (identifier != '') {
job_input_id += '|';
}
job_input_id += input.name;
} else {
//var value = self.app.field_list[input.id].value();
switch(input.type) {
case 'repeat':
job_def[job_input_id] = value;
break;
default:
job_def[job_input_id] = value;
}
// process input type
switch (input.type) {
// handle repeats
case 'repeat':
var index = 0;
for (var j in node) {
if (j.indexOf('section') != -1) {
convert(job_input_id + '_' + index++, node[j]);
}
}
break;
// handle conditionals
case 'conditional':
// get conditional value
var value = self.app.field_list[input.id].value();
// find selected case
for (var j in input.cases) {
if (input.cases[j].value == value) {
convert(job_input_id, head[input.id + '-section-' + j]);
break;
}
}
// break
break;
default:
// handle default value
var value = self.app.field_list[input.id].value();
job_def[job_input_id] = value;
}
}
}
@@ -61,49 +86,10 @@ return Backbone.Model.extend({
// start conversion
convert('', this.dict);
// return result
return job_def;
},
// iterate
_iterate: function(parent, dict, xml) {
// get child nodes
var self = this;
var children = $(parent).children();
children.each(function() {
// get child element
var child = this;
// get id
var id = $(child).attr('id');
// create new branch
if ($(child).hasClass('section-row') || $(child).hasClass('tab-pane')) {
// create sub dictionary
dict[id] = {};
// add input element if it exists
var input = self.app.input_list[id];
if (input) {
dict[id] = {
input : input
}
}
// create xml element
var $el = $('<div id="' + id + '"/>');
// append xml
xml.append($el);
// fill sub dictionary
self._iterate(child, dict[id], $el);
} else {
self._iterate(child, dict, xml);
}
});
},
// find referenced elements
findReferences: function(identifier, type) {
@@ -176,6 +162,45 @@ return Backbone.Model.extend({
// return
return referenced;
},
// iterate
_iterate: function(parent, dict, xml) {
// get child nodes
var self = this;
var children = $(parent).children();
children.each(function() {
// get child element
var child = this;
// get id
var id = $(child).attr('id');
// create new branch
if ($(child).hasClass('section-row') || $(child).hasClass('tab-pane')) {
// create sub dictionary
dict[id] = {};
// add input element if it exists
var input = self.app.input_list[id];
if (input) {
dict[id] = {
input : input
}
}
// create xml element
var $el = $('<div id="' + id + '"/>');
// append xml
xml.append($el);
// fill sub dictionary
self._iterate(child, dict[id], $el);
} else {
self._iterate(child, dict, xml);
}
});
}
});
+3 -5
View File
@@ -612,7 +612,7 @@ function LoadingIndicator( $where, options ){
* of characters, a callback is called. Pressing ESC when the input
* is focused will clear the input and call a separate callback.
*/
var _l = window._l || function( s ){ return s; }
var _l = window._l || function( s ){ return s; };
// contructor
function searchInput( parentNode, options ){
@@ -637,11 +637,9 @@ function LoadingIndicator( $where, options ){
// .................................................................... input rendering and events
// visually clear the search, trigger an event, and call the callback
function clearSearchInput( event ){
//console.debug( this, 'clear' );
var $input = $( this ).parent().children( 'input' );
//console.debug( 'input', $input );
$input.val( '' );
$input.trigger( 'clear:searchInput' );
//console.debug( this, 'clear', $input );
$input.focus().val( '' ).trigger( 'clear:searchInput' );
options.onclear();
}
+13 -3
View File
@@ -20,7 +20,8 @@ var View = Backbone.View.extend({
this.$nav = null;
this.$content = null;
this.first_tab = null;
this.current_id = null;
// configure options
this.options = Utils.merge(options, this.optionsDefault);
@@ -139,6 +140,11 @@ var View = Backbone.View.extend({
self.show(id);
}
});
// initialize current id
if (!this.current_id) {
this.current_id = id;
}
},
// delete tab
@@ -183,10 +189,14 @@ var View = Backbone.View.extend({
// show selected tab
if (id) {
this.$el.find('.tab-element').removeClass('active');
this.$el.find('.tab-pane').removeClass('active');
// reassign active class
this.$el.find('#tab-' + this.current_id).removeClass('active');
this.$el.find('#' + this.current_id).removeClass('active');
this.$el.find('#tab-' + id).addClass('active');
this.$el.find('#' + id).addClass('active');
// update current id
this.current_id = id;
}
// change
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
define(["mvc/dataset/dataset-li","mvc/base-mvc","utils/localization"],function(h,d,f){var c=d.ListItemView;var a=c.extend({className:c.prototype.className+" dataset-collection",id:function(){return["dataset_collection",this.model.get("id")].join("-")},fxSpeed:"fast",initialize:function(i){if(i.logger){this.logger=this.model.logger=i.logger}this.log(this+"(DCListItemView).initialize:",i);c.prototype.initialize.call(this,i)},expand:function(){var i=this;return i._fetchModelDetails().always(function(){i.trigger("expanded",i)})},_renderSubtitle:function(){var i=$('<div class="subtitle"></div>');switch(this.model.get("collection_type")){case"list":return i.text(f("a list of datasets"));case"paired":return i.text(f("a pair of datasets"));case"list:paired":return i.text(f("a list of paired datasets"))}return i},toString:function(){var i=(this.model)?(this.model+""):("(no model)");return"DCListItemView("+i+")"}});a.prototype.templates=(function(){var i=d.wrapTemplate(['<div class="title-bar clear" tabindex="0">','<div class="title">','<span class="name"><%- collection.element_identifier || collection.name %></span>',"</div>",'<div class="subtitle"></div>',"</div>"],"collection");return _.extend({},c.prototype.templates,{titleBar:i})}());var b=c.extend({logger:console,className:c.prototype.className+" dataset-collection-element",fxSpeed:"fast",initialize:function(i){if(i.logger){this.logger=this.model.logger=i.logger}this.log("DCEListItemView.initialize:",i);c.prototype.initialize.call(this,i)},toString:function(){var i=(this.model)?(this.model+""):("(no model)");return"DCEListItemView("+i+")"}});b.prototype.templates=(function(){var i=d.wrapTemplate(['<div class="title-bar clear" tabindex="0">','<div class="title">','<span class="name"><%- element.element_identifier %></span>',"</div>",'<div class="subtitle"></div>',"</div>"],"element");return _.extend({},c.prototype.templates,{titleBar:i})}());var e=h.DatasetListItemView.extend({className:h.DatasetListItemView.prototype.className+" dataset-collection-element",initialize:function(i){if(i.logger){this.logger=this.model.logger=i.logger}this.log("DatasetDCEListItemView.initialize:",i);h.DatasetListItemView.prototype.initialize.call(this,i)},toString:function(){var i=(this.model)?(this.model+""):("(no model)");return"DatasetDCEListItemView("+i+")"}});e.prototype.templates=(function(){var i=d.wrapTemplate(['<div class="title-bar clear" tabindex="0">','<span class="state-icon"></span>','<div class="title">','<span class="name"><%- element.element_identifier %></span>',"</div>","</div>"],"element");return _.extend({},h.DatasetListItemView.prototype.templates,{titleBar:i})}());var g=a.extend({className:a.prototype.className+" dataset-collection-element",_swapNewRender:function(i){a.prototype._swapNewRender.call(this,i);var j=this.model.get("state")||"ok";this.$el.addClass("state-"+j);return this.$el},toString:function(){var i=(this.model)?(this.model+""):("(no model)");return"NestedDCDCEListItemView("+i+")"}});return{DCListItemView:a,DCEListItemView:b,DatasetDCEListItemView:e,NestedDCDCEListItemView:g}});
define(["mvc/list/list-item","mvc/dataset/dataset-li","mvc/base-mvc","utils/localization"],function(a,h,i,d){var e=a.ListItemView;var c=e.extend({className:e.prototype.className+" dataset-collection",id:function(){return["dataset_collection",this.model.get("id")].join("-")},fxSpeed:"fast",initialize:function(j){if(j.logger){this.logger=this.model.logger=j.logger}this.log(this+"(DCListItemView).initialize:",j);e.prototype.initialize.call(this,j)},expand:function(){var j=this;return j._fetchModelDetails().always(function(){j.trigger("expanded",j)})},_renderSubtitle:function(){var j=$('<div class="subtitle"></div>');switch(this.model.get("collection_type")){case"list":return j.text(d("a list of datasets"));case"paired":return j.text(d("a pair of datasets"));case"list:paired":return j.text(d("a list of paired datasets"))}return j},toString:function(){var j=(this.model)?(this.model+""):("(no model)");return"DCListItemView("+j+")"}});c.prototype.templates=(function(){var j=i.wrapTemplate(['<div class="title-bar clear" tabindex="0">','<div class="title">','<span class="name"><%- collection.element_identifier || collection.name %></span>',"</div>",'<div class="subtitle"></div>',"</div>"],"collection");return _.extend({},e.prototype.templates,{titleBar:j})}());var f=e.extend({className:e.prototype.className+" dataset-collection-element",fxSpeed:"fast",initialize:function(j){if(j.logger){this.logger=this.model.logger=j.logger}this.log("DCEListItemView.initialize:",j);e.prototype.initialize.call(this,j)},toString:function(){var j=(this.model)?(this.model+""):("(no model)");return"DCEListItemView("+j+")"}});f.prototype.templates=(function(){var j=i.wrapTemplate(['<div class="title-bar clear" tabindex="0">','<div class="title">','<span class="name"><%- element.element_identifier %></span>',"</div>",'<div class="subtitle"></div>',"</div>"],"element");return _.extend({},e.prototype.templates,{titleBar:j})}());var b=h.DatasetListItemView.extend({className:h.DatasetListItemView.prototype.className+" dataset-collection-element",initialize:function(j){if(j.logger){this.logger=this.model.logger=j.logger}this.log("DatasetDCEListItemView.initialize:",j);h.DatasetListItemView.prototype.initialize.call(this,j)},toString:function(){var j=(this.model)?(this.model+""):("(no model)");return"DatasetDCEListItemView("+j+")"}});b.prototype.templates=(function(){var j=i.wrapTemplate(['<div class="title-bar clear" tabindex="0">','<span class="state-icon"></span>','<div class="title">','<span class="name"><%- element.element_identifier %></span>',"</div>","</div>"],"element");return _.extend({},h.DatasetListItemView.prototype.templates,{titleBar:j})}());var g=c.extend({className:c.prototype.className+" dataset-collection-element",_swapNewRender:function(j){c.prototype._swapNewRender.call(this,j);var k=this.model.get("state")||"ok";this.$el.addClass("state-"+k);return this.$el},toString:function(){var j=(this.model)?(this.model+""):("(no model)");return"NestedDCDCEListItemView("+j+")"}});return{DCListItemView:c,DCEListItemView:f,DatasetDCEListItemView:b,NestedDCDCEListItemView:g}});
@@ -1 +1 @@
define(["mvc/dataset/dataset-model","mvc/base-mvc","utils/localization"],function(l,o,d){var e={defaults:{model_class:"DatasetCollectionElement",element_identifier:null,element_index:null,element_type:null},_mergeObject:function(q){_.extend(q,q.object);delete q.object;return q},constructor:function(q,r){this.debug("\t DatasetCollectionElement.constructor:",q,r);q=this._mergeObject(q);Backbone.Model.apply(this,arguments)},parse:function(r,s){var q=r;q=this._mergeObject(q);return q}};var p=Backbone.Model.extend(o.LoggableMixin).extend(e);var m=Backbone.Collection.extend(o.LoggableMixin).extend({model:p,initialize:function(q,r){this.debug(this+"(DCECollection).initialize:",q,r);r=r||{}},toString:function(){return(["DatasetCollectionElementCollection(",this.length,")"].join(""))}});var f=l.DatasetAssociation.extend(o.mixin(e,{defaults:_.extend({},l.DatasetAssociation.prototype.defaults,e.defaults),constructor:function(q,r){this.debug("\t DatasetDCE.constructor:",q,r);e.constructor.call(this,q,r)},initialize:function(q,r){this.debug(this+"(DatasetDCE).initialize:",q,r);l.DatasetAssociation.prototype.initialize.call(this,q,r)},toString:function(){var q=this.get("element_identifier");return(["DatasetDCE(",q,")"].join(""))}}));var k=m.extend({model:f,initialize:function(q,r){this.debug(this+"(DatasetDCECollection).initialize:",q,r);m.prototype.initialize.call(this,q,r)},toString:function(){return(["DatasetDCECollection(",this.length,")"].join(""))}});var h=Backbone.Model.extend(o.LoggableMixin).extend(o.SearchableModelMixin).extend({defaults:{collection_type:null,deleted:false},collectionClass:m,initialize:function(r,q){this.debug(this+"(DatasetCollection).initialize:",r,q,this);this.elements=this._createElementsModel();this.on("change:elements",function(){this.log("change:elements");this.elements=this._createElementsModel()})},_createElementsModel:function(){this.debug(this+"._createElementsModel",this.collectionClass,this.get("elements"),this.elements);var q=this.get("elements")||[];this.unset("elements",{silent:true});this.elements=new this.collectionClass(q);return this.elements},toJSON:function(){var q=Backbone.Model.prototype.toJSON.call(this);if(this.elements){q.elements=this.elements.toJSON()}return q},inReadyState:function(){return true},hasDetails:function(){this.debug("hasDetails:",this.elements.length);return this.elements.length!==0},getVisibleContents:function(q){return this.elements},"delete":function(q){if(this.get("deleted")){return jQuery.when()}return this.save({deleted:true},q)},undelete:function(q){if(!this.get("deleted")||this.get("purged")){return jQuery.when()}return this.save({deleted:false},q)},searchAttributes:["name"],toString:function(){var q=[this.get("id"),this.get("name")||this.get("element_identifier")];return"DatasetCollection("+(q.join(","))+")"}});var g=h.extend({collectionClass:k,initialize:function(r,q){this.debug(this+"(ListDatasetCollection).initialize:",r,q);h.prototype.initialize.call(this,r,q)},toString:function(){return(["ListDatasetCollection(",this.get("name"),")"].join(""))}});var c=g.extend({initialize:function(r,q){this.debug(this+"(PairDatasetCollection).initialize:",r,q);g.prototype.initialize.call(this,r,q)},toString:function(){return(["PairDatasetCollection(",this.get("name"),")"].join(""))}});var i=h.extend(o.mixin(e,{constructor:function(q,r){this.debug("\t NestedDCDCE.constructor:",q,r);e.constructor.call(this,q,r)},toString:function(){var q=(this.object)?(""+this.object):(this.get("element_identifier"));return(["NestedDCDCE(",q,")"].join(""))}}));var n=m.extend({model:i,initialize:function(r,q){this.debug(this+"(NestedDCDCECollection).initialize:",r,q);m.prototype.initialize.call(this,r,q)},toString:function(){return(["NestedDCDCECollection(",this.length,")"].join(""))}});var a=c.extend(o.mixin(e,{constructor:function(q,r){this.debug("\t NestedPairDCDCE.constructor:",q,r);e.constructor.call(this,q,r)},toString:function(){var q=(this.object)?(""+this.object):(this.get("element_identifier"));return(["NestedPairDCDCE(",q,")"].join(""))}}));var j=n.extend({model:a,initialize:function(r,q){this.debug(this+"(NestedPairDCDCECollection).initialize:",r,q);n.prototype.initialize.call(this,r,q)},toString:function(){return(["NestedPairDCDCECollection(",this.length,")"].join(""))}});var b=h.extend({collectionClass:j,initialize:function(q,r){this.debug(this+"(ListPairedDatasetCollection).initialize:",q,r);h.prototype.initialize.call(this,q,r)},toString:function(){return(["ListPairedDatasetCollection(",this.get("name"),")"].join(""))}});return{ListDatasetCollection:g,PairDatasetCollection:c,ListPairedDatasetCollection:b}});
define(["mvc/dataset/dataset-model","mvc/base-mvc","utils/localization"],function(l,o,d){var e={defaults:{model_class:"DatasetCollectionElement",element_identifier:null,element_index:null,element_type:null},_mergeObject:function(q){_.extend(q,q.object);delete q.object;return q},constructor:function(q,r){this.debug("\t DatasetCollectionElement.constructor:",q,r);q=this._mergeObject(q);Backbone.Model.apply(this,arguments)},parse:function(r,s){var q=r;q=this._mergeObject(q);return q}};var p=Backbone.Model.extend(o.LoggableMixin).extend(e);var m=Backbone.Collection.extend(o.LoggableMixin).extend({model:p,initialize:function(q,r){this.debug(this+"(DCECollection).initialize:",q,r);r=r||{}},toString:function(){return(["DatasetCollectionElementCollection(",this.length,")"].join(""))}});var f=l.DatasetAssociation.extend(o.mixin(e,{defaults:_.extend({},l.DatasetAssociation.prototype.defaults,e.defaults),constructor:function(q,r){this.debug("\t DatasetDCE.constructor:",q,r);e.constructor.call(this,q,r)},initialize:function(q,r){this.debug(this+"(DatasetDCE).initialize:",q,r);l.DatasetAssociation.prototype.initialize.call(this,q,r)},toString:function(){var q=this.get("element_identifier");return(["DatasetDCE(",q,")"].join(""))}}));var k=m.extend({model:f,initialize:function(q,r){this.debug(this+"(DatasetDCECollection).initialize:",q,r);m.prototype.initialize.call(this,q,r)},toString:function(){return(["DatasetDCECollection(",this.length,")"].join(""))}});var h=Backbone.Model.extend(o.LoggableMixin).extend(o.SearchableModelMixin).extend({defaults:{collection_type:null,deleted:false},collectionClass:m,initialize:function(r,q){this.debug(this+"(DatasetCollection).initialize:",r,q,this);this.elements=this._createElementsModel();this.on("change:elements",function(){this.log("change:elements");this.elements=this._createElementsModel()})},_createElementsModel:function(){this.debug(this+"._createElementsModel",this.collectionClass,this.get("elements"),this.elements);var q=this.get("elements")||[];this.unset("elements",{silent:true});this.elements=new this.collectionClass(q);return this.elements},toJSON:function(){var q=Backbone.Model.prototype.toJSON.call(this);if(this.elements){q.elements=this.elements.toJSON()}return q},inReadyState:function(){return true},hasDetails:function(){this.debug("hasDetails:",this.elements.length);return this.elements.length!==0},getVisibleContents:function(q){return this.elements},"delete":function(q){if(this.get("deleted")){return jQuery.when()}return this.save({deleted:true},q)},undelete:function(q){if(!this.get("deleted")||this.get("purged")){return jQuery.when()}return this.save({deleted:false},q)},isDeletedOrPurged:function(){return(this.get("deleted")||this.get("purged"))},searchAttributes:["name"],toString:function(){var q=[this.get("id"),this.get("name")||this.get("element_identifier")];return"DatasetCollection("+(q.join(","))+")"}});var g=h.extend({collectionClass:k,initialize:function(r,q){this.debug(this+"(ListDatasetCollection).initialize:",r,q);h.prototype.initialize.call(this,r,q)},toString:function(){return(["ListDatasetCollection(",this.get("name"),")"].join(""))}});var c=g.extend({initialize:function(r,q){this.debug(this+"(PairDatasetCollection).initialize:",r,q);g.prototype.initialize.call(this,r,q)},toString:function(){return(["PairDatasetCollection(",this.get("name"),")"].join(""))}});var i=h.extend(o.mixin(e,{constructor:function(q,r){this.debug("\t NestedDCDCE.constructor:",q,r);e.constructor.call(this,q,r)},toString:function(){var q=(this.object)?(""+this.object):(this.get("element_identifier"));return(["NestedDCDCE(",q,")"].join(""))}}));var n=m.extend({model:i,initialize:function(r,q){this.debug(this+"(NestedDCDCECollection).initialize:",r,q);m.prototype.initialize.call(this,r,q)},toString:function(){return(["NestedDCDCECollection(",this.length,")"].join(""))}});var a=c.extend(o.mixin(e,{constructor:function(q,r){this.debug("\t NestedPairDCDCE.constructor:",q,r);e.constructor.call(this,q,r)},toString:function(){var q=(this.object)?(""+this.object):(this.get("element_identifier"));return(["NestedPairDCDCE(",q,")"].join(""))}}));var j=n.extend({model:a,initialize:function(r,q){this.debug(this+"(NestedPairDCDCECollection).initialize:",r,q);n.prototype.initialize.call(this,r,q)},toString:function(){return(["NestedPairDCDCECollection(",this.length,")"].join(""))}});var b=h.extend({collectionClass:j,initialize:function(q,r){this.debug(this+"(ListPairedDatasetCollection).initialize:",q,r);h.prototype.initialize.call(this,q,r)},toString:function(){return(["ListPairedDatasetCollection(",this.get("name"),")"].join(""))}});return{ListDatasetCollection:g,PairDatasetCollection:c,ListPairedDatasetCollection:b}});
@@ -1 +1 @@
define(["mvc/collection/collection-model","mvc/collection/collection-li","mvc/base-mvc","utils/localization"],function(h,f,a,e){var d=Backbone.View.extend(a.LoggableMixin).extend({tagName:"div",className:"dataset-collection-panel",fxSpeed:"fast",DatasetDCEViewClass:f.DatasetDCEListItemView,NestedDCDCEViewClass:f.NestedDCDCEListItemView,initialize:function(i){i=i||{};if(i.logger){this.logger=i.logger}this.log(this+".initialize:",i);this.linkTarget=i.linkTarget||"_blank";this.hasUser=i.hasUser;this.panelStack=[];this.parentName=i.parentName},_setUpListeners:function(){this.on("all",function(i){this.log(this+"",arguments)},this);return this},_setUpModelEventHandlers:function(){return this},render:function(k,l){this.log("render:",k,l);k=(k===undefined)?(this.fxSpeed):(k);var i=this,j;if(!this.model){return this}j=this.renderModel();$(i).queue("fx",[function(m){if(k&&i.$el.is(":visible")){i.$el.fadeOut(k,m)}else{m()}},function(m){i.$el.empty();if(j){i.$el.append(j.children())}m()},function(m){if(k&&!i.$el.is(":visible")){i.$el.fadeIn(k,m)}else{m()}},function(m){if(l){l.call(this)}i.trigger("rendered",this);m()}]);return this},renderModel:function(){var k=this.model.get("collection_type")||this.model.object.get("collection_type"),j=_.extend(this.model.toJSON(),{parentName:this.parentName,type:k}),i=$("<div/>").append(this.templates.panel(j));this._setUpBehaviours(i);this.renderContents(i);return i},_setUpBehaviours:function(i){i=i||this.$el;i.find("[title]").tooltip({placement:"bottom"});return this},$container:function(){return(this.findContainerFn)?(this.findContainerFn.call(this)):(this.$el.parent())},$datasetsList:function(i){return(i||this.$el).find(".datasets-list")},renderContents:function(j){j=j||this.$el;this.warn(this+".renderContents:, model:",this.model);var i=this,l={},k=this.model.getVisibleContents();this.$datasetsList(j).empty();if(k&&k.length){k.each(function(n){var o=n.id,m=i._createContentView(n);l[o]=m;i._attachContentView(m.render(),j)})}this.contentViews=l;return this.contentViews},_createContentView:function(k){var j=null,i=this._getContentClass(k);j=new i({model:k,linkTarget:this.linkTarget,hasUser:this.hasUser,logger:this.logger});this._setUpContentListeners(j);return j},_getContentClass:function(i){switch(i.get("element_type")){case"hda":return this.DatasetDCEViewClass;case"dataset_collection":return this.NestedDCDCEViewClass}throw new TypeError("Unknown element type:",i.get("element_type"))},_setUpContentListeners:function(j){var i=this;if(j.model.get("element_type")==="dataset_collection"){j.on("expanded",function(k){i.info("expanded",k);i._addCollectionPanel(k)})}},_addCollectionPanel:function(k){var l=this,i=k.model;var j=new c({model:i,parentName:this.model.get("name"),linkTarget:this.linkTarget});l.panelStack.push(j);l.$(".controls").add(".datasets-list").hide();l.$el.append(j.$el);j.on("close",function(){l.render();k.collapse();l.panelStack.pop()});if(!j.model.hasDetails()){var m=j.model.fetch();m.done(function(){j.render()})}else{j.render()}},_attachContentView:function(k,j){j=j||this.$el;var i=this.$datasetsList(j);i.append(k.$el);return this},events:{"click .navigation .back":"close"},close:function(i){this.$el.remove();this.trigger("close")},toString:function(){return"CollectionPanel("+((this.model)?(this.model.get("name")):(""))+")"}});d.templates=d.prototype.templates=(function(){var i=_.template(['<div class="controls">','<div class="navigation">','<a class="back" href="javascript:void(0)">','<span class="fa fa-icon fa-angle-left"></span>',e("Back to "),"<%- collection.parentName %>","</a>","</div>",'<div class="title">','<div class="name"><%- collection.name || collection.element_identifier %></div>','<div class="subtitle">','<% if( collection.type === "list" ){ %>',e("a list of datasets"),'<% } else if( collection.type === "paired" ){ %>',e("a pair of datasets"),'<% } else if( collection.type === "list:paired" ){ %>',e("a list of paired datasets"),"<% } %>","</div>","</div>","</div>",'<div class="datasets-list"></div>'].join(""));return{panel:function(j){return i({_l:e,collection:j})}}}());var b=d.extend({DatasetDCEViewClass:f.DatasetDCEListItemView,toString:function(){return"ListCollectionPanel("+((this.model)?(this.model.get("name")):(""))+")"}});var c=b.extend({toString:function(){return"PairCollectionPanel("+((this.model)?(this.model.get("name")):(""))+")"}});var g=d.extend({NestedDCDCEViewClass:f.NestedDCDCEListItemView,toString:function(){return"ListOfPairsCollectionPanel("+((this.model)?(this.model.get("name")):(""))+")"}});return{CollectionPanel:d,ListCollectionPanel:b,PairCollectionPanel:c,ListOfPairsCollectionPanel:g}});
define(["mvc/list/list-panel","mvc/collection/collection-model","mvc/collection/collection-li","mvc/base-mvc","utils/localization"],function(a,d,f,j,b){var h=a.ModelListPanel;var g=h.extend({className:h.prototype.className+" dataset-collection-panel",DatasetDCEViewClass:f.DatasetDCEListItemView,NestedDCDCEViewClass:f.NestedDCDCEListItemView,modelCollectionKey:"elements",initialize:function(k){h.prototype.initialize.call(this,k);this.linkTarget=k.linkTarget||"_blank";this.hasUser=k.hasUser;this.panelStack=[];this.parentName=k.parentName},_filterCollection:function(){return this.model.getVisibleContents()},_getItemViewClass:function(k){switch(k.get("element_type")){case"hda":return this.DatasetDCEViewClass;case"dataset_collection":return this.NestedDCDCEViewClass}throw new TypeError("Unknown element type:",k.get("element_type"))},_getItemViewOptions:function(l){var k=h.prototype._getItemViewOptions.call(this,l);return _.extend(k,{linkTarget:this.linkTarget,hasUser:this.hasUser})},_setUpItemViewListeners:function(l){var k=this;h.prototype._setUpItemViewListeners.call(k,l);if(l.model.get("element_type")==="dataset_collection"){l.on("expanded",function(m){k.info("expanded",m);k._addCollectionPanel(m)})}return k},_addCollectionPanel:function(m){var n=this,k=m.model;var l=new i({model:k,parentName:this.model.get("name"),linkTarget:this.linkTarget});n.panelStack.push(l);n.$(".controls").add(".list-items").hide();n.$el.append(l.$el);l.on("close",function(){n.render();m.collapse();n.panelStack.pop()});if(!l.model.hasDetails()){var o=l.model.fetch();o.done(function(){l.render()})}else{l.render()}},events:{"click .navigation .back":"close"},close:function(k){this.$el.remove();this.trigger("close")},toString:function(){return"CollectionPanel("+((this.model)?(this.model.get("name")):(""))+")"}});g.prototype.templates=(function(){var k=j.wrapTemplate(['<div class="controls">','<div class="navigation">','<a class="back" href="javascript:void(0)">','<span class="fa fa-icon fa-angle-left"></span>',b("Back to "),"<%- view.parentName %>","</a>","</div>",'<div class="title">','<div class="name"><%- collection.name || collection.element_identifier %></div>','<div class="subtitle">','<% if( collection.collection_type === "list" ){ %>',b("a list of datasets"),'<% } else if( collection.collection_type === "paired" ){ %>',b("a pair of datasets"),'<% } else if( collection.collection_type === "list:paired" ){ %>',b("a list of paired datasets"),"<% } %>","</div>","</div>","</div>"],"collection");return _.extend(_.clone(h.prototype.templates),{controls:k})}());var e=g.extend({DatasetDCEViewClass:f.DatasetDCEListItemView,toString:function(){return"ListCollectionPanel("+((this.model)?(this.model.get("name")):(""))+")"}});var i=e.extend({toString:function(){return"PairCollectionPanel("+((this.model)?(this.model.get("name")):(""))+")"}});var c=g.extend({NestedDCDCEViewClass:f.NestedDCDCEListItemView,toString:function(){return"ListOfPairsCollectionPanel("+((this.model)?(this.model.get("name")):(""))+")"}});return{CollectionPanel:g,ListCollectionPanel:e,PairCollectionPanel:i,ListOfPairsCollectionPanel:c}});
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
define(["mvc/dataset/list-panel","mvc/dataset/dataset-li","mvc/base-mvc","utils/localization"],function(c,f,a,b){var e=c.ListPanel;var d=e.extend({viewClass:f.DatasetListItemView,className:e.prototype.className+" dataset-list",noneFoundMsg:b("No matching datasets found"),initialize:function(g){e.prototype.initialize.call(this,g)},toString:function(){return"DatasetList("+this.collection+")"}});return{DatasetList:d}});
define(["mvc/list/list-panel","mvc/dataset/dataset-li","mvc/base-mvc","utils/localization"],function(c,f,a,b){var e=c.ListPanel;var d=e.extend({viewClass:f.DatasetListItemView,className:e.prototype.className+" dataset-list",noneFoundMsg:b("No matching datasets found"),initialize:function(g){e.prototype.initialize.call(this,g)},toString:function(){return"DatasetList("+this.collection+")"}});return{DatasetList:d}});
@@ -1 +1 @@
define(["mvc/dataset/states","mvc/base-mvc","utils/localization"],function(a,b,d){var g=b.SearchableModelMixin;var f=Backbone.Model.extend(b.LoggableMixin).extend(b.mixin(g,{defaults:{state:a.NEW,deleted:false,purged:false,name:"(unnamed dataset)",accessible:true,data_type:"",file_ext:"",file_size:0,meta_files:[],misc_blurb:"",misc_info:"",tags:[]},initialize:function(h,i){this.debug(this+"(Dataset).initialize",h,i);if(!this.get("accessible")){this.set("state",a.NOT_VIEWABLE)}this.urls=this._generateUrls();this._setUpListeners()},_generateUrls:function(){var j=this.get("id");if(!j){return{}}var i={purge:"datasets/"+j+"/purge_async",display:"datasets/"+j+"/display/?preview=True",edit:"datasets/"+j+"/edit",download:"datasets/"+j+"/display?to_ext="+this.get("file_ext"),report_error:"dataset/errors?id="+j,rerun:"tool_runner/rerun?id="+j,show_params:"datasets/"+j+"/show_params",visualization:"visualization",meta_download:"dataset/get_metadata_file?hda_id="+j+"&metadata_name="};var h=(window.galaxy_config&&galaxy_config.root)?(galaxy_config.root):("/");_.each(i,function(l,k){i[k]=h+l});this.urls=i;return i},_setUpListeners:function(){this.on("change:state",function(i,h){this.log(this+" has changed state:",i,h);if(this.inReadyState()){this.trigger("state:ready",i,h,this.previous("state"))}});this.on("change:id change:file_ext",function(h){this._generateUrls()})},toJSON:function(){var h=Backbone.Model.prototype.toJSON.call(this);return _.extend(h,{urls:this.urls})},isDeletedOrPurged:function(){return(this.get("deleted")||this.get("purged"))},inReadyState:function(){var h=_.contains(a.READY_STATES,this.get("state"));return(this.isDeletedOrPurged()||h)},hasDetails:function(){return _.has(this.attributes,"genome_build")},hasData:function(){return(this.get("file_size")>0)},"delete":function(h){if(this.get("deleted")){return jQuery.when()}return this.save({deleted:true},h)},undelete:function(h){if(!this.get("deleted")||this.get("purged")){return jQuery.when()}return this.save({deleted:false},h)},purge:function e(h){if(this.get("purged")){return jQuery.when()}h=h||{};h.url=this.urls.purge;var i=this,j=jQuery.ajax(h);j.done(function(m,k,l){i.set({deleted:true,purged:true})});j.fail(function(o,k,n){var l=d("Unable to purge dataset");var m=("Removal of datasets by users is not allowed in this Galaxy instance");if(o.responseJSON&&o.responseJSON.error){l=o.responseJSON.error}else{if(o.responseText.indexOf(m)!==-1){l=m}}o.responseText=l;i.trigger("error",i,o,h,d(l),{error:l})});return j},searchAttributes:["name","file_ext","genome_build","misc_blurb","misc_info","annotation","tags"],searchAliases:{title:"name",format:"file_ext",database:"genome_build",blurb:"misc_blurb",description:"misc_blurb",info:"misc_info",tag:"tags"},toString:function(){var h=this.get("id")||"";if(this.get("name")){h='"'+this.get("name")+'",'+h}return"Dataset("+h+")"}}));var c=Backbone.Collection.extend(b.LoggableMixin).extend({model:f,urlRoot:((window.galaxy_config&&galaxy_config.root)?(galaxy_config.root):("/"))+"api/datasets",ids:function(){return this.map(function(h){return h.get("id")})},notReady:function(){return this.filter(function(h){return !h.inReadyState()})},haveDetails:function(){return this.all(function(h){return h.hasDetails()})},ajaxQueue:function(m,j){var i=jQuery.Deferred(),h=this.length,l=[];if(!h){i.resolve([]);return i}var k=this.chain().reverse().map(function(o,n){return function(){var p=m.call(o,j);p.done(function(q){i.notify({curr:n,total:h,response:q,model:o})});p.always(function(q){l.push(q);if(k.length){k.shift()()}else{i.resolve(l)}})}}).value();k.shift()();return i},matches:function(h){return this.filter(function(i){return i.matches(h)})},set:function(j,h){var i=this;j=_.map(j,function(l){if(!i.get(l.id)){return l}var k=existing.toJSON();_.extend(k,l);return k});Backbone.Collection.prototype.set.call(this,j,h)},toString:function(){return(["DatasetAssociationCollection(",this.length,")"].join(""))}});return{DatasetAssociation:f,DatasetAssociationCollection:c}});
define(["mvc/dataset/states","mvc/base-mvc","utils/localization"],function(a,b,d){var g=b.SearchableModelMixin;var f=Backbone.Model.extend(b.LoggableMixin).extend(b.mixin(g,{defaults:{state:a.NEW,deleted:false,purged:false,name:"(unnamed dataset)",accessible:true,data_type:"",file_ext:"",file_size:0,meta_files:[],misc_blurb:"",misc_info:"",tags:[]},initialize:function(h,i){this.debug(this+"(Dataset).initialize",h,i);if(!this.get("accessible")){this.set("state",a.NOT_VIEWABLE)}this.urls=this._generateUrls();this._setUpListeners()},_generateUrls:function(){var j=this.get("id");if(!j){return{}}var i={purge:"datasets/"+j+"/purge_async",display:"datasets/"+j+"/display/?preview=True",edit:"datasets/"+j+"/edit",download:"datasets/"+j+"/display?to_ext="+this.get("file_ext"),report_error:"dataset/errors?id="+j,rerun:"tool_runner/rerun?id="+j,show_params:"datasets/"+j+"/show_params",visualization:"visualization",meta_download:"dataset/get_metadata_file?hda_id="+j+"&metadata_name="};var h=(window.galaxy_config&&galaxy_config.root)?(galaxy_config.root):("/");_.each(i,function(l,k){i[k]=h+l});this.urls=i;return i},_setUpListeners:function(){this.on("change:state",function(i,h){this.log(this+" has changed state:",i,h);if(this.inReadyState()){this.trigger("state:ready",i,h,this.previous("state"))}});this.on("change:urls",function(){console.warn("change:urls",arguments)});this.on("change:id change:file_ext",function(h){this._generateUrls()})},toJSON:function(){var h=Backbone.Model.prototype.toJSON.call(this);return _.extend(h,{urls:this.urls})},isDeletedOrPurged:function(){return(this.get("deleted")||this.get("purged"))},inReadyState:function(){var h=_.contains(a.READY_STATES,this.get("state"));return(this.isDeletedOrPurged()||h)},hasDetails:function(){return _.has(this.attributes,"genome_build")},hasData:function(){return(this.get("file_size")>0)},"delete":function(h){if(this.get("deleted")){return jQuery.when()}return this.save({deleted:true},h)},undelete:function(h){if(!this.get("deleted")||this.get("purged")){return jQuery.when()}return this.save({deleted:false},h)},purge:function e(h){if(this.get("purged")){return jQuery.when()}h=h||{};h.url=this.urls.purge;var i=this,j=jQuery.ajax(h);j.done(function(m,k,l){i.set({deleted:true,purged:true})});j.fail(function(o,k,n){var l=d("Unable to purge dataset");var m=("Removal of datasets by users is not allowed in this Galaxy instance");if(o.responseJSON&&o.responseJSON.error){l=o.responseJSON.error}else{if(o.responseText.indexOf(m)!==-1){l=m}}o.responseText=l;i.trigger("error",i,o,h,d(l),{error:l})});return j},searchAttributes:["name","file_ext","genome_build","misc_blurb","misc_info","annotation","tags"],searchAliases:{title:"name",format:"file_ext",database:"genome_build",blurb:"misc_blurb",description:"misc_blurb",info:"misc_info",tag:"tags"},toString:function(){var h=this.get("id")||"";if(this.get("name")){h='"'+this.get("name")+'",'+h}return"Dataset("+h+")"}}));var c=Backbone.Collection.extend(b.LoggableMixin).extend({model:f,urlRoot:((window.galaxy_config&&galaxy_config.root)?(galaxy_config.root):("/"))+"api/datasets",ids:function(){return this.map(function(h){return h.get("id")})},notReady:function(){return this.filter(function(h){return !h.inReadyState()})},haveDetails:function(){return this.all(function(h){return h.hasDetails()})},ajaxQueue:function(m,j){var i=jQuery.Deferred(),h=this.length,l=[];if(!h){i.resolve([]);return i}var k=this.chain().reverse().map(function(o,n){return function(){var p=m.call(o,j);p.done(function(q){i.notify({curr:n,total:h,response:q,model:o})});p.always(function(q){l.push(q);if(k.length){k.shift()()}else{i.resolve(l)}})}}).value();k.shift()();return i},matches:function(h){return this.filter(function(i){return i.matches(h)})},set:function(j,h){var i=this;j=_.map(j,function(l){if(!i.get(l.id)){return l}var k=existing.toJSON();_.extend(k,l);return k});Backbone.Collection.prototype.set.call(this,j,h)},toString:function(){return(["DatasetAssociationCollection(",this.length,")"].join(""))}});return{DatasetAssociation:f,DatasetAssociationCollection:c}});
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
define(["mvc/dataset/dataset-li","mvc/base-mvc","utils/localization"],function(e,a,c){var d=e.DatasetListItemView;var b=d.extend({initialize:function(f,g){d.prototype.initialize.call(this,f,g)},className:d.prototype.className+" history-content",toString:function(){var f=(this.model)?(this.model+""):("(no model)");return"HDAListItemView("+f+")"}});b.prototype.templates=(function(){var g=a.wrapTemplate(['<div class="title-bar clear" tabindex="0">','<span class="state-icon"></span>','<div class="title">','<span class="hid"><%- dataset.hid %></span> ','<span class="name"><%- dataset.name %></span>',"</div>","</div>"],"dataset");var f=_.extend({},d.prototype.templates.warnings,{hidden:a.wrapTemplate(["<% if( !dataset.visible ){ %>",'<div class="hidden-msg warningmessagesmall">',c("This dataset has been hidden"),"</div>","<% } %>"],"dataset")});return _.extend({},d.prototype.templates,{titleBar:g,warnings:f})}());return{HDAListItemView:b}});
define(["mvc/dataset/dataset-li","mvc/base-mvc","utils/localization"],function(e,a,c){var d=e.DatasetListItemView;var b=d.extend({className:d.prototype.className+" history-content",initialize:function(f,g){d.prototype.initialize.call(this,f,g)},toString:function(){var f=(this.model)?(this.model+""):("(no model)");return"HDAListItemView("+f+")"}});b.prototype.templates=(function(){var g=a.wrapTemplate(['<div class="title-bar clear" tabindex="0">','<span class="state-icon"></span>','<div class="title">','<span class="hid"><%- dataset.hid %></span> ','<span class="name"><%- dataset.name %></span>',"</div>","</div>"],"dataset");var f=_.extend({},d.prototype.templates.warnings,{hidden:a.wrapTemplate(["<% if( !dataset.visible ){ %>",'<div class="hidden-msg warningmessagesmall">',c("This dataset has been hidden"),"</div>","<% } %>"],"dataset")});return _.extend({},d.prototype.templates,{titleBar:g,warnings:f})}());return{HDAListItemView:b}});
@@ -1 +1 @@
define(["mvc/history/history-content-model","mvc/history/hda-model","mvc/history/hdca-model","mvc/base-mvc","utils/localization"],function(g,e,b,a,c){var f=Backbone.Collection.extend(a.LoggableMixin).extend({model:function(i,h){if(i.history_content_type==="dataset"){return new e.HistoryDatasetAssociation(i,h)}else{if(i.history_content_type==="dataset_collection"){switch(i.collection_type){case"list":return new b.HistoryListDatasetCollection(i,h);case"paired":return new b.HistoryPairDatasetCollection(i,h);case"list:paired":return new b.HistoryListPairedDatasetCollection(i,h)}throw new TypeError("Unknown collection_type: "+i.collection_type)}}throw new TypeError("Unknown history_content_type: "+i.history_content_type)},initialize:function(i,h){h=h||{};this.historyId=h.historyId;this.on("all",function(){this.debug(this+".event:",arguments)})},urlRoot:galaxy_config.root+"api/histories",url:function(){return this.urlRoot+"/"+this.historyId+"/contents"},ids:function(){return this.map(function(h){return h.get("id")})},notReady:function(){return this.filter(function(h){return !h.inReadyState()})},running:function(){var h=[];this.each(function(j){var i=!j.inReadyState();if(i){h.push(j.get("id"))}});return h},getByHid:function(h){return _.first(this.filter(function(i){return i.get("hid")===h}))},getVisible:function(h,k,j){j=j||[];this.debug("checking isVisible");var i=new f(this.filter(function(l){return l.isVisible(h,k)}));_.each(j,function(l){if(!_.isFunction(l)){return}i=new f(i.filter(l))});return i},haveDetails:function(){return this.all(function(h){return h.hasDetails()})},fetchAllDetails:function(i){i=i||{};var h={details:"all"};i.data=(i.data)?(_.extend(i.data,h)):(h);return this.fetch(i)},ajaxQueue:function(m,j){var i=jQuery.Deferred(),h=this.length,l=[];if(!h){i.resolve([]);return i}var k=this.chain().reverse().map(function(o,n){return function(){var p=m.call(o,j);p.done(function(q){i.notify({curr:n,total:h,response:q,model:o})});p.always(function(q){l.push(q);if(k.length){k.shift()()}else{i.resolve(l)}})}}).value();k.shift()();return i},copy:function(j){var i=this,h=jQuery.post(this.url(),{source:"hda",content:j});h.done(function(k){i.add([k])});h.fail(function(l,k,m){i.trigger("error",i,h,{},"Error copying dataset")});return h},matches:function(h){return this.filter(function(i){return i.matches(h)})},set:function(j,h){this.debug("set:",j);var i=this;j=_.map(j,function(m){var l=m.attributes||m,n=g.typeIdStr(l.history_content_type,l.id),o=i.get(n);if(!o){return m}var k=o.toJSON();_.extend(k,m);return k});Backbone.Collection.prototype.set.call(this,j,h)},promoteToHistoryDatasetCollection:function d(m,k,i){i=i||{};i.url=this.url();i.type="POST";var o=k;var l=[],h=null;if(k==="list"){this.chain().each(function(r){var p=r.attributes.name;var s=r.get("id");var q=r.attributes.history_content_type;if(q==="dataset"){if(o!=="list"){this.log("Invalid collection type")}l.push({name:p,src:"hda",id:s})}else{if(o==="list"){o="list:"+r.attributes.collection_type}else{if(o!=="list:"+r.attributes.collection_type){this.log("Invalid collection type")}}l.push({name:p,src:"hdca",id:s})}});h="New Dataset List"}else{if(k==="paired"){var j=this.ids();if(j.length!==2){}l.push({name:"forward",src:"hda",id:j[0]});l.push({name:"reverse",src:"hda",id:j[1]});h="New Dataset Pair"}}i.data={type:"dataset_collection",name:h,collection_type:o,element_identifiers:JSON.stringify(l)};var n=jQuery.ajax(i);n.done(function(r,p,q){m.refresh()});n.fail(function(r,p,q){if(r.responseJSON&&r.responseJSON.error){error=r.responseJSON.error}else{error=r.responseJSON}r.responseText=error});return n},print:function(){var h=this;h.each(function(i){h.debug(i);if(i.elements){h.debug("\t elements:",i.elements)}})},toString:function(){return(["HistoryContents(",[this.historyId,this.length].join(),")"].join(""))}});return{HistoryContents:f}});
define(["mvc/history/history-content-model","mvc/history/hda-model","mvc/history/hdca-model","mvc/base-mvc","utils/localization"],function(g,e,b,a,c){var f=Backbone.Collection.extend(a.LoggableMixin).extend({model:function(i,h){if(i.history_content_type==="dataset"){return new e.HistoryDatasetAssociation(i,h)}else{if(i.history_content_type==="dataset_collection"){switch(i.collection_type){case"list":return new b.HistoryListDatasetCollection(i,h);case"paired":return new b.HistoryPairDatasetCollection(i,h);case"list:paired":return new b.HistoryListPairedDatasetCollection(i,h)}throw new TypeError("Unknown collection_type: "+i.collection_type)}}throw new TypeError("Unknown history_content_type: "+i.history_content_type)},initialize:function(i,h){h=h||{};this.historyId=h.historyId;this.on("all",function(){this.debug(this+".event:",arguments)})},urlRoot:galaxy_config.root+"api/histories",url:function(){return this.urlRoot+"/"+this.historyId+"/contents"},ids:function(){return this.map(function(h){return h.get("id")})},notReady:function(){return this.filter(function(h){return !h.inReadyState()})},running:function(){var h=[];this.each(function(j){var i=!j.inReadyState();if(i){h.push(j.get("id"))}});return h},getByHid:function(h){return _.first(this.filter(function(i){return i.get("hid")===h}))},getVisible:function(h,k,j){j=j||[];this.debug("checking isVisible");var i=new f(this.filter(function(l){return l.isVisible(h,k)}));_.each(j,function(l){if(!_.isFunction(l)){return}i=new f(i.filter(l))});return i},haveDetails:function(){return this.all(function(h){return h.hasDetails()})},fetchAllDetails:function(i){i=i||{};var h={details:"all"};i.data=(i.data)?(_.extend(i.data,h)):(h);return this.fetch(i)},ajaxQueue:function(m,j){var i=jQuery.Deferred(),h=this.length,l=[];if(!h){i.resolve([]);return i}var k=this.chain().reverse().map(function(o,n){return function(){var p=m.call(o,j);p.done(function(q){i.notify({curr:n,total:h,response:q,model:o})});p.always(function(q){l.push(q);if(k.length){k.shift()()}else{i.resolve(l)}})}}).value();k.shift()();return i},copy:function(j){var i=this,h=jQuery.post(this.url(),{source:"hda",content:j});h.done(function(k){i.add([k])});h.fail(function(l,k,m){i.trigger("error",i,h,{},"Error copying dataset")});return h},matches:function(h){return this.filter(function(i){return i.matches(h)})},set:function(j,h){this.debug("set:",j);var i=this;j=_.map(j,function(m){var l=m.attributes||m,n=g.typeIdStr(l.history_content_type,l.id),o=i.get(n);if(!o){return m}var k=_.clone(o.attributes);_.extend(k,m);return k});Backbone.Collection.prototype.set.call(this,j,h)},promoteToHistoryDatasetCollection:function d(m,k,i){i=i||{};i.url=this.url();i.type="POST";var o=k;var l=[],h=null;if(k==="list"){this.chain().each(function(r){var p=r.attributes.name;var s=r.get("id");var q=r.attributes.history_content_type;if(q==="dataset"){if(o!=="list"){this.log("Invalid collection type")}l.push({name:p,src:"hda",id:s})}else{if(o==="list"){o="list:"+r.attributes.collection_type}else{if(o!=="list:"+r.attributes.collection_type){this.log("Invalid collection type")}}l.push({name:p,src:"hdca",id:s})}});h="New Dataset List"}else{if(k==="paired"){var j=this.ids();if(j.length!==2){}l.push({name:"forward",src:"hda",id:j[0]});l.push({name:"reverse",src:"hda",id:j[1]});h="New Dataset Pair"}}i.data={type:"dataset_collection",name:h,collection_type:o,element_identifiers:JSON.stringify(l)};var n=jQuery.ajax(i);n.done(function(r,p,q){m.refresh()});n.fail(function(r,p,q){if(r.responseJSON&&r.responseJSON.error){error=r.responseJSON.error}else{error=r.responseJSON}r.responseText=error});return n},clone:function(){var h=Backbone.Collection.prototype.clone.call(this);h.historyId=this.historyId;return h},print:function(){var h=this;h.each(function(i){h.debug(i);if(i.elements){h.debug("\t elements:",i.elements)}})},toString:function(){return(["HistoryContents(",[this.historyId,this.length].join(),")"].join(""))}});return{HistoryContents:f}});
@@ -1 +1 @@
define(["mvc/history/history-contents","mvc/base-mvc","utils/localization"],function(h,i,d){var e=Backbone.Model.extend(i.LoggableMixin).extend({defaults:{model_class:"History",id:null,name:"Unnamed History",state:"new",diskSize:0,deleted:false},urlRoot:galaxy_config.root+"api/histories",initialize:function(k,l,j){j=j||{};this.logger=j.logger||null;this.log(this+".initialize:",k,l,j);this.log("creating history contents:",l);this.contents=new h.HistoryContents(l||[],{historyId:this.get("id")});this._setUpListeners();this.updateTimeoutId=null},_setUpListeners:function(){this.on("error",function(k,n,j,m,l){this.errorHandler(k,n,j,m,l)});if(this.contents){this.listenTo(this.contents,"error",function(){this.trigger.apply(this,["error:contents"].concat(jQuery.makeArray(arguments)))})}this.on("change:id",function(k,j){if(this.contents){this.contents.historyId=j}},this)},errorHandler:function(k,n,j,m,l){this.clearUpdateTimeout()},ownedByCurrUser:function(){if(!Galaxy||!Galaxy.currUser){return false}if(Galaxy.currUser.isAnonymous()||Galaxy.currUser.id!==this.get("user_id")){return false}return true},contentsCount:function(){return _.reduce(_.values(this.get("state_details")),function(j,k){return j+k},0)},checkForUpdates:function(j){if(this.contents.running().length){this.setUpdateTimeout()}else{this.trigger("ready");if(_.isFunction(j)){j.call(this)}}return this},setUpdateTimeout:function(j){j=j||e.UPDATE_DELAY;var k=this;this.clearUpdateTimeout();this.updateTimeoutId=setTimeout(function(){k.refresh()},j);return this.updateTimeoutId},clearUpdateTimeout:function(){if(this.updateTimeoutId){clearTimeout(this.updateTimeoutId);this.updateTimeoutId=null}},refresh:function(k,j){k=k||[];j=j||{};var l=this;j.data=j.data||{};if(k.length){j.data.details=k.join(",")}var m=this.contents.fetch(j);m.done(function(n){l.checkForUpdates(function(){this.fetch()})});return m},copy:function(m,k){m=(m!==undefined)?(m):(true);if(!this.id){throw new Error("You must set the history ID before copying it.")}var j={history_id:this.id};if(m){j.current=true}if(k){j.name=k}var l=this,n=jQuery.post(this.urlRoot,j);n.done(function(o){l.trigger("copied",l,o)});return n},toString:function(){return"History("+this.get("id")+","+this.get("name")+")"}});e.UPDATE_DELAY=4000;e.getHistoryData=function c(j,v){v=v||{};var p=v.hdaDetailIds||[];var l=v.hdcaDetailIds||[];var r=jQuery.Deferred(),q=null;function k(w){if(j==="current"){return jQuery.getJSON(galaxy_config.root+"history/current_history_json")}return jQuery.ajax(galaxy_config.root+"api/histories/"+j)}function o(w){return w&&w.empty}function u(x){if(o(x)){return[]}if(_.isFunction(p)){p=p(x)}if(_.isFunction(l)){l=l(x)}var w={};if(p.length){w.dataset_details=p.join(",")}if(l.length){w.dataset_collection_details=l.join(",")}return jQuery.ajax(galaxy_config.root+"api/histories/"+x.id+"/contents",{data:w})}var t=v.historyFn||k,s=v.hdaFn||u;var n=t(j);n.done(function(w){q=w;r.notify({status:"history data retrieved",historyJSON:q})});n.fail(function(y,w,x){r.reject(y,"loading the history")});var m=n.then(s);m.then(function(w){r.notify({status:"dataset data retrieved",historyJSON:q,hdaJSON:w});r.resolve(q,w)});m.fail(function(y,w,x){r.reject(y,"loading the datasets",{history:q})});return r};var f=Backbone.Collection.extend(i.LoggableMixin).extend({model:e,urlRoot:(window.galaxy_config?galaxy_config.root:"/")+"api/histories",initialize:function(k,j){j=j||{};this.log("HistoryCollection.initialize",arguments);this.includeDeleted=j.includeDeleted||false;this.setUpListeners()},setUpListeners:function a(){var j=this;this.on("change:deleted",function(k){this.debug("change:deleted",j.includeDeleted,k.get("deleted"));if(!j.includeDeleted&&k.get("deleted")){j.remove(k)}});this.on("copied",function(k,l){this.unshift(new e(l,[]))})},create:function g(m,k,j,l){var o=this,n=new e(m||{},k||[],j||{});return n.save(l).done(function(p){o.unshift(n)})},toString:function b(){return"HistoryCollection("+this.length+")"}});return{History:e,HistoryCollection:f}});
define(["mvc/history/history-contents","mvc/base-mvc","utils/localization"],function(h,i,d){var e=Backbone.Model.extend(i.LoggableMixin).extend({defaults:{model_class:"History",id:null,name:"Unnamed History",state:"new",diskSize:0,deleted:false},urlRoot:galaxy_config.root+"api/histories",initialize:function(k,l,j){j=j||{};this.logger=j.logger||null;this.log(this+".initialize:",k,l,j);this.log("creating history contents:",l);this.contents=new h.HistoryContents(l||[],{historyId:this.get("id")});this._setUpListeners();this.updateTimeoutId=null},_setUpListeners:function(){this.on("error",function(k,n,j,m,l){this.errorHandler(k,n,j,m,l)});if(this.contents){this.listenTo(this.contents,"error",function(){this.trigger.apply(this,["error:contents"].concat(jQuery.makeArray(arguments)))})}this.on("change:id",function(k,j){if(this.contents){this.contents.historyId=j}},this)},errorHandler:function(k,n,j,m,l){this.clearUpdateTimeout()},ownedByCurrUser:function(){if(!Galaxy||!Galaxy.currUser){return false}if(Galaxy.currUser.isAnonymous()||Galaxy.currUser.id!==this.get("user_id")){return false}return true},contentsCount:function(){return _.reduce(_.values(this.get("state_details")),function(j,k){return j+k},0)},checkForUpdates:function(j){if(this.contents.running().length){this.setUpdateTimeout()}else{this.trigger("ready");if(_.isFunction(j)){j.call(this)}}return this},setUpdateTimeout:function(j){j=j||e.UPDATE_DELAY;var k=this;this.clearUpdateTimeout();this.updateTimeoutId=setTimeout(function(){k.refresh()},j);return this.updateTimeoutId},clearUpdateTimeout:function(){if(this.updateTimeoutId){clearTimeout(this.updateTimeoutId);this.updateTimeoutId=null}},refresh:function(k,j){k=k||[];j=j||{};var l=this;j.data=j.data||{};if(k.length){j.data.details=k.join(",")}var m=this.contents.fetch(j);m.done(function(n){l.checkForUpdates(function(){this.fetch()})});return m},copy:function(m,k){m=(m!==undefined)?(m):(true);if(!this.id){throw new Error("You must set the history ID before copying it.")}var j={history_id:this.id};if(m){j.current=true}if(k){j.name=k}var l=this,n=jQuery.post(this.urlRoot,j);n.done(function(o){l.trigger("copied",l,o)});return n},toString:function(){return"History("+this.get("id")+","+this.get("name")+")"}});e.UPDATE_DELAY=4000;e.getHistoryData=function c(j,v){v=v||{};var r=v.detailIdsFn||[];var m=v.hdcaDetailIds||[];var s=jQuery.Deferred(),p=null;function k(w){if(j==="current"){return jQuery.getJSON(galaxy_config.root+"history/current_history_json")}return jQuery.ajax(galaxy_config.root+"api/histories/"+j)}function o(w){return w&&w.empty}function q(x){if(o(x)){return[]}if(_.isFunction(r)){r=r(x)}if(_.isFunction(m)){m=m(x)}var w={};if(r.length){w.dataset_details=r.join(",")}if(m.length){w.dataset_collection_details=m.join(",")}return jQuery.ajax(galaxy_config.root+"api/histories/"+x.id+"/contents",{data:w})}var t=v.historyFn||k,u=v.contentsFn||q;var n=t(j);n.done(function(w){p=w;s.notify({status:"history data retrieved",historyJSON:p})});n.fail(function(y,w,x){s.reject(y,"loading the history")});var l=n.then(u);l.then(function(w){s.notify({status:"contents data retrieved",historyJSON:p,contentsJSON:w});s.resolve(p,w)});l.fail(function(y,w,x){s.reject(y,"loading the contents",{history:p})});return s};var f=Backbone.Collection.extend(i.LoggableMixin).extend({model:e,urlRoot:(window.galaxy_config?galaxy_config.root:"/")+"api/histories",initialize:function(k,j){j=j||{};this.log("HistoryCollection.initialize",arguments);this.includeDeleted=j.includeDeleted||false;this.setUpListeners()},setUpListeners:function a(){var j=this;this.on("change:deleted",function(k){this.debug("change:deleted",j.includeDeleted,k.get("deleted"));if(!j.includeDeleted&&k.get("deleted")){j.remove(k)}});this.on("copied",function(k,l){this.unshift(new e(l,[]))})},create:function g(m,k,j,l){var o=this,n=new e(m||{},k||[],j||{});return n.save(l).done(function(p){o.unshift(n)})},toString:function b(){return"HistoryCollection("+this.length+")"}});return{History:e,HistoryCollection:f}});
@@ -1 +1 @@
define(["mvc/history/history-panel","mvc/history/hda-li","utils/localization"],function(e,b,a){var d=e.ReadOnlyHistoryPanel;var c=d.extend({className:"annotated-history-panel",renderModel:function(){this.$el.addClass(this.className);var h=d.prototype.renderModel.call(this),f=this.$datasetsList(h),g=$("<table/>").addClass("datasets-list datasets-table");g.append(f.children());f.replaceWith(g);h.find(".history-subtitle").after(this.renderHistoryAnnotation());h.find(".history-search-btn").hide();h.find(".history-controls").after(h.find(".history-search-controls").show());return h},renderHistoryAnnotation:function(){var f=this.model.get("annotation");if(!f){return null}return $(['<div class="history-annotation">',f,"</div>"].join(""))},renderHdas:function(g){g=g||this.$el;var f=d.prototype.renderHdas.call(this,g);this.$datasetsList(g).prepend($("<tr/>").addClass("headers").append([$("<th/>").text(a("Dataset")),$("<th/>").text(a("Annotation"))]));return f},attachContentView:function(i,g){g=g||this.$el;var j=_.find(i.el.classList,function(k){return(/^state\-/).test(k)}),f=i.model.get("annotation")||"",h=$("<tr/>").addClass("dataset-row").append([$("<td/>").addClass("dataset-container").append(i.$el).addClass(j?j.replace("-","-color-"):""),$("<td/>").addClass("additional-info").text(f)]);this.$datasetsList(g).append(h)},events:_.extend(_.clone(d.prototype.events),{"click tr":function(f){$(f.currentTarget).find(".dataset-title-bar").click()},"click .icon-btn":function(f){f.stopPropagation()}}),toString:function(){return"AnnotatedHistoryPanel("+((this.model)?(this.model.get("name")):(""))+")"}});return{AnnotatedHistoryPanel:c}});
define(["mvc/history/history-panel","mvc/history/hda-li","mvc/history/hdca-li","mvc/base-mvc","utils/localization"],function(f,c,g,a,b){var e=f.HistoryPanel;var d=e.extend({className:e.prototype.className+" annotated-history-panel",_buildNewRender:function(){var h=e.prototype._buildNewRender.call(this);this.renderHistoryAnnotation(h);return h},renderHistoryAnnotation:function(i){var h=this.model.get("annotation");if(!h){return}i.find(".controls .annotation-display").text(h)},renderItems:function(i){i=i||this.$el;i.find(".list-items").replaceWith($("<table/>").addClass("list-items"));var h=e.prototype.renderItems.call(this,i);this.$list(i).prepend($("<tr/>").addClass("headers").append([$("<th/>").text(b("Dataset")),$("<th/>").text(b("Annotation"))]));return h},_attachItems:function(h){this.$list(h).append(this.views.map(function(j){var l=_.find(j.el.classList,function(m){return(/^state\-/).test(m)}),i=j.model.get("annotation")||"",k=$("<tr/>").append([$("<td/>").addClass("contents-container").append(j.$el).addClass(l?l.replace("-","-color-"):""),$("<td/>").addClass("additional-info").text(i)]);return k}));return this},events:_.extend(_.clone(e.prototype.events),{"click tr":function(h){$(h.currentTarget).find(".title-bar").click()},"click .icon-btn":function(h){h.stopPropagation()}}),toString:function(){return"AnnotatedHistoryPanel("+((this.model)?(this.model.get("name")):(""))+")"}});return{AnnotatedHistoryPanel:d}});
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
define(["mvc/base-mvc","utils/localization"],function(b,c){var d=Backbone.View.extend(b.LoggableMixin).extend({initialize:function(e){this.expanded=e.expanded||false;this.fxSpeed=e.fxSpeed||this.fxSpeed},fxSpeed:"fast",render:function(f){var e=this._buildNewRender();this._setUpBehaviors(e);this._queueNewRender(e,f);return this},_buildNewRender:function(){var e=$(this.templates.el(this.model.toJSON(),this));if(this.expanded){this.$details(e).replaceWith(this._renderDetails().show())}return e},_queueNewRender:function(f,g){g=(g===undefined)?(this.fxSpeed):(g);var e=this;$(e).queue("fx",[function(h){this.$el.fadeOut(g,h)},function(h){e._swapNewRender(f);h()},function(h){this.$el.fadeIn(g,h)},function(h){this.trigger("rendered",e);h()}])},_swapNewRender:function(e){return this.$el.empty().attr("class",this.className).append(e.children())},_setUpBehaviors:function(e){e=e||this.$el;e.find("[title]").tooltip({placement:"bottom"})},$details:function(e){e=e||this.$el;return e.find(".details")},_renderDetails:function(){var e=$(this.templates.details(this.model.toJSON(),this));this._setUpBehaviors(e);return e},toggleExpanded:function(e){e=(e===undefined)?(!this.expanded):(e);if(e){this.expand()}else{this.collapse()}return this},expand:function(){var e=this;return e._fetchModelDetails().always(function(){var f=e._renderDetails();e.$details().replaceWith(f);e.expanded=true;f.slideDown(e.fxSpeed,function(){e.trigger("expanded",e)})})},_fetchModelDetails:function(){if(!this.model.hasDetails()){return this.model.fetch()}return jQuery.when()},collapse:function(){var e=this;e.expanded=false;this.$details().slideUp(e.fxSpeed,function(){e.trigger("collapsed",e)})}});var a=d.extend(b.mixin(b.SelectableViewMixin,b.DraggableViewMixin,{tagName:"div",className:"list-item",initialize:function(e){d.prototype.initialize.call(this,e);b.SelectableViewMixin.initialize.call(this,e);b.DraggableViewMixin.initialize.call(this,e)},_buildNewRender:function(){var e=d.prototype._buildNewRender.call(this);e.find(".warnings").replaceWith(this._renderWarnings());e.find(".title-bar").replaceWith(this._renderTitleBar());e.find(".primary-actions").append(this._renderPrimaryActions());e.find(".subtitle").replaceWith(this._renderSubtitle());return e},_swapNewRender:function(e){d.prototype._swapNewRender.call(this,e);if(this.selectable){this.showSelector(0)}if(this.draggable){this.draggableOn()}return this.$el},_renderWarnings:function(){var e=this,g=$('<div class="warnings"></div>'),f=e.model.toJSON();_.each(e.templates.warnings,function(h){g.append($(h(f,e)))});return g},_renderTitleBar:function(){return $(this.templates.titleBar(this.model.toJSON(),this))},_renderPrimaryActions:function(){return[]},_renderSubtitle:function(){return $(this.templates.subtitle(this.model.toJSON(),this))},events:{"click .title-bar":"_clickTitleBar","keydown .title-bar":"_keyDownTitleBar","click .selector":"toggleSelect"},_clickTitleBar:function(e){e.stopPropagation();this.toggleExpanded()},_keyDownTitleBar:function(g){var e=32,f=13;if(g&&(g.type==="keydown")&&(g.keyCode===e||g.keyCode===f)){this.toggleExpanded();g.stopPropagation();return false}return true},toString:function(){var e=(this.model)?(this.model+""):("(no model)");return"ListItemView("+e+")"}}));a.prototype.templates=(function(){var g=b.wrapTemplate(['<div class="list-element">','<div class="warnings"></div>','<div class="selector">','<span class="fa fa-2x fa-square-o"></span>',"</div>",'<div class="primary-actions"></div>','<div class="title-bar"></div>','<div class="details"></div>',"</div>"]);var e={};var h=b.wrapTemplate(['<div class="title-bar clear" tabindex="0">','<span class="state-icon"></span>','<div class="title">','<span class="name"><%- element.name %></span>',"</div>",'<div class="subtitle"></div>',"</div>"],"element");var i=b.wrapTemplate(['<div class="subtitle"></div>']);var f=b.wrapTemplate(['<div class="details"></div>']);return{el:g,warnings:e,titleBar:h,subtitle:i,details:f}}());return{ExpandableView:d,ListItemView:a}});
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
define(["mvc/ui/ui-portlet","mvc/ui/ui-misc","mvc/citation/citation-model","mvc/citation/citation-view","mvc/tools","mvc/tools/tools-template","mvc/tools/tools-datasets","mvc/tools/tools-section","mvc/tools/tools-tree"],function(g,k,i,a,f,d,h,j,c){var e=Backbone.Model.extend({initialize:function(l){this.url=galaxy_config.root+"api/tools/"+l.id+"?io_details=true"}});var b=Backbone.View.extend({main_el:"body",initialize:function(m){var l=this;this.options=m;this.model=new e({id:m.id});this.tree=new c(this);this.field_list={};this.input_list={};this.datasets=new h({history_id:this.options.history_id,success:function(){l._initializeToolForm()}})},_initializeToolForm:function(){var m=this;var n=new k.ButtonIcon({icon:"fa-question-circle",title:"Question?",tooltip:"Ask a question about this tool (Biostar)",onclick:function(){window.open(m.options.biostar_url+"/p/new/post/")}});var o=new k.ButtonIcon({icon:"fa-search",title:"Search",tooltip:"Search help for this tool (Biostar)",onclick:function(){window.open(m.options.biostar_url+"/t/"+m.options.id+"/")}});var l=new k.ButtonIcon({icon:"fa-share",title:"Share",tooltip:"Share this tool",onclick:function(){prompt("Copy to clipboard: Ctrl+C, Enter",galaxy_config.root+"root?tool_id="+m.options.id)}});this.model.fetch({error:function(p){console.debug("tools-form::_initializeToolForm() : Attempt to fetch tool model failed.")},success:function(){m.inputs=m.model.get("inputs");m.portlet=new g.View({icon:"fa-wrench",title:"<b>"+m.model.get("name")+"</b> "+m.model.get("description"),buttons:{execute:new k.ButtonIcon({icon:"fa-check",tooltip:"Execute the tool",title:"Execute",floating:"clear",onclick:function(){m._submit()}})},operations:{button_question:n,button_search:o,button_share:l}});if(!m.options.biostar_url){n.$el.hide();o.$el.hide()}m.message=new k.Message();m.portlet.append(m.message.$el);$(m.main_el).append(m.portlet.$el);if(m.options.help!=""){$(m.main_el).append(d.help(m.options.help))}if(m.options.citations){$(m.main_el).append(d.citations());var p=new i.ToolCitationCollection();p.tool_id=m.options.id;var q=new a.CitationListView({collection:p});q.render();p.fetch()}m.setElement(m.portlet.content());m.section=new j.View(m,{inputs:m.model.get("inputs")});m.portlet.append(m.section.$el);m.refresh()}})},refresh:function(){this.tree.refresh();for(var l in this.field_list){this.field_list[l].trigger("change")}console.debug("tools-form::refresh() - Recreated tree structure. Refresh.")},_submit:function(){console.log(this.tree.jobDictionary())}});return{View:b}});
define(["mvc/ui/ui-portlet","mvc/ui/ui-misc","mvc/citation/citation-model","mvc/citation/citation-view","mvc/tools","mvc/tools/tools-template","mvc/tools/tools-datasets","mvc/tools/tools-section","mvc/tools/tools-tree"],function(g,k,i,a,f,d,h,j,c){var e=Backbone.Model.extend({initialize:function(l){this.url=galaxy_config.root+"api/tools/"+l.id+"?io_details=true"}});var b=Backbone.View.extend({main_el:"body",initialize:function(m){var l=this;this.options=m;this.model=new e({id:m.id});this.tree=new c(this);this.field_list={};this.input_list={};this.datasets=new h({history_id:this.options.history_id,success:function(){l._initializeToolForm()}})},_initializeToolForm:function(){var m=this;var n=new k.ButtonIcon({icon:"fa-question-circle",title:"Question?",tooltip:"Ask a question about this tool (Biostar)",onclick:function(){window.open(m.options.biostar_url+"/p/new/post/")}});var o=new k.ButtonIcon({icon:"fa-search",title:"Search",tooltip:"Search help for this tool (Biostar)",onclick:function(){window.open(m.options.biostar_url+"/t/"+m.options.id+"/")}});var l=new k.ButtonIcon({icon:"fa-share",title:"Share",tooltip:"Share this tool",onclick:function(){prompt("Copy to clipboard: Ctrl+C, Enter",galaxy_config.root+"root?tool_id="+m.options.id)}});this.model.fetch({error:function(p){console.debug("tools-form::_initializeToolForm() : Attempt to fetch tool model failed.")},success:function(){m.inputs=m.model.get("inputs");m.portlet=new g.View({icon:"fa-wrench",title:"<b>"+m.model.get("name")+"</b> "+m.model.get("description"),buttons:{execute:new k.ButtonIcon({icon:"fa-check",tooltip:"Execute the tool",title:"Execute",floating:"clear",onclick:function(){m._submit()}})},operations:{button_question:n,button_search:o,button_share:l}});if(!m.options.biostar_url){n.$el.hide();o.$el.hide()}m.message=new k.Message();m.portlet.append(m.message.$el);$(m.main_el).append(m.portlet.$el);if(m.options.help!=""){$(m.main_el).append(d.help(m.options.help))}if(m.options.citations){$(m.main_el).append(d.citations());var p=new i.ToolCitationCollection();p.tool_id=m.options.id;var q=new a.CitationListView({collection:p});q.render();p.fetch()}m.setElement(m.portlet.content());m.section=new j.View(m,{inputs:m.model.get("inputs")});m.portlet.append(m.section.$el);m.refresh();m._submit()}})},refresh:function(){this.tree.refresh();for(var l in this.field_list){this.field_list[l].trigger("change")}console.debug("tools-form::refresh() - Recreated tree structure. Refresh.")},_submit:function(){console.log(this.tree.finalize())}});return{View:b}});
@@ -1 +1 @@
define([],function(){return Backbone.Model.extend({initialize:function(a){this.app=a},refresh:function(){if(!this.app.section){return{}}this.dict={};this.xml=$("<div/>");this._iterate(this.app.section.$el,this.dict,this.xml)},jobDictionary:function(){var a=this;var b={};function c(e,g){for(var f in g){if(g[f].input){var d=g[f].input;var h=e+d.name;if(d.type=="repeat"){}else{switch(d.type){case"repeat":b[h]=value;break;default:b[h]=value}}}}}c("",this.dict);return b},_iterate:function(d,e,b){var a=this;var c=$(d).children();c.each(function(){var i=this;var h=$(i).attr("id");if($(i).hasClass("section-row")||$(i).hasClass("tab-pane")){e[h]={};var f=a.app.input_list[h];if(f){e[h]={input:f}}var g=$('<div id="'+h+'"/>');b.append(g);a._iterate(i,e[h],g)}else{a._iterate(i,e,b)}})},findReferences:function(c,e){var g=[];var b=this;function d(h,j){var i=$(j).children();var l=[];var k=false;i.each(function(){var o=this;var n=$(o).attr("id");if(n!==c){var m=b.app.input_list[n];if(m){if(m.name==h){k=true;return false}if(m.data_ref==h&&m.type==e){l.push(n)}}}});if(!k){g=g.concat(l);i.each(function(){d(h,this)})}}var f=this.xml.find("#"+c);if(f.length>0){var a=this.app.input_list[c];if(a){d(a.name,f.parent())}}return g}})});
define([],function(){return Backbone.Model.extend({initialize:function(a){this.app=a},refresh:function(){this.dict={};this.xml=$("<div/>");if(!this.app.section){return{}}this._iterate(this.app.section.$el,this.dict,this.xml)},finalize:function(){var a=this;var b={};function c(k,l){for(var f in l){var d=l[f];if(d.input){var m=d.input;var h=k;if(k!=""){h+="|"}h+=m.name;switch(m.type){case"repeat":var g=0;for(var e in d){if(e.indexOf("section")!=-1){c(h+"_"+g++,d[e])}}break;case"conditional":var n=a.app.field_list[m.id].value();for(var e in m.cases){if(m.cases[e].value==n){c(h,l[m.id+"-section-"+e]);break}}break;default:var n=a.app.field_list[m.id].value();b[h]=n}}}}c("",this.dict);return b},findReferences:function(c,e){var g=[];var b=this;function d(h,j){var i=$(j).children();var l=[];var k=false;i.each(function(){var o=this;var n=$(o).attr("id");if(n!==c){var m=b.app.input_list[n];if(m){if(m.name==h){k=true;return false}if(m.data_ref==h&&m.type==e){l.push(n)}}}});if(!k){g=g.concat(l);i.each(function(){d(h,this)})}}var f=this.xml.find("#"+c);if(f.length>0){var a=this.app.input_list[c];if(a){d(a.name,f.parent())}}return g},_iterate:function(d,e,b){var a=this;var c=$(d).children();c.each(function(){var i=this;var h=$(i).attr("id");if($(i).hasClass("section-row")||$(i).hasClass("tab-pane")){e[h]={};var f=a.app.input_list[h];if(f){e[h]={input:f}}var g=$('<div id="'+h+'"/>');b.append(g);a._iterate(i,e[h],g)}else{a._iterate(i,e,b)}})}})});
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
define(["utils/utils"],function(a){var b=Backbone.View.extend({optionsDefault:{title_new:"",operations:null,onnew:null,min:null,max:null,onchange:null},initialize:function(e){this.visible=false;this.$nav=null;this.$content=null;this.first_tab=null;this.options=a.merge(e,this.optionsDefault);var c=$(this._template(this.options));this.$nav=c.find(".tab-navigation");this.$content=c.find(".tab-content");this.setElement(c);this.list={};var d=this;if(this.options.operations){$.each(this.options.operations,function(g,h){h.$el.prop("id",g);d.$nav.find(".operations").append(h.$el)})}if(this.options.onnew){var f=$(this._template_tab_new(this.options));this.$nav.append(f);f.tooltip({title:"Add a new tab",placement:"bottom",container:d.$el});f.on("click",function(g){f.tooltip("hide");d.options.onnew()})}},size:function(){return _.size(this.list)},current:function(){return this.$el.find(".tab-pane.active").attr("id")},add:function(f){var e=this;var h=f.id;var g=$(this._template_tab(f));var d=$(this._template_tab_content(f));this.list[h]=f.ondel?true:false;if(this.options.onnew){this.$nav.find("#new-tab").before(g)}else{this.$nav.append(g)}d.append(f.$el);this.$content.append(d);if(this.size()==1){g.addClass("active");d.addClass("active");this.first_tab=h}if(this.options.max&&this.size()>=this.options.max){this.$el.find("#new-tab").hide()}if(f.ondel){var c=g.find("#delete");c.tooltip({title:"Delete this tab",placement:"bottom",container:e.$el});c.on("click",function(){c.tooltip("destroy");e.$el.find(".tooltip").remove();f.ondel();return false})}g.on("click",function(i){i.preventDefault();if(f.onclick){f.onclick()}else{e.show(h)}})},del:function(c){this.$el.find("#tab-"+c).remove();this.$el.find("#"+c).remove();if(this.first_tab==c){this.first_tab=null}if(this.first_tab!=null){this.show(this.first_tab)}if(this.list[c]){delete this.list[c]}if(this.size()<this.options.max){this.$el.find("#new-tab").show()}},delRemovable:function(){for(var c in this.list){this.del(c)}},show:function(c){this.$el.fadeIn("fast");this.visible=true;if(c){this.$el.find(".tab-element").removeClass("active");this.$el.find(".tab-pane").removeClass("active");this.$el.find("#tab-"+c).addClass("active");this.$el.find("#"+c).addClass("active")}if(this.options.onchange){this.options.onchange(c)}},hide:function(){this.$el.fadeOut("fast");this.visible=false},hideOperation:function(c){this.$nav.find("#"+c).hide()},showOperation:function(c){this.$nav.find("#"+c).show()},setOperation:function(e,d){var c=this.$nav.find("#"+e);c.off("click");c.on("click",d)},title:function(e,d){var c=this.$el.find("#tab-title-text-"+e);if(d){c.html(d)}return c.html()},retitle:function(d){var c=0;for(var e in this.list){this.title(e,++c+": "+d)}},_template:function(c){return'<div class="ui-tabs tabbable tabs-left"><ul id="tab-navigation" class="tab-navigation nav nav-tabs"><div class="operations" style="float: right; margin-bottom: 4px;"></div></ul><div id="tab-content" class="tab-content"/></div>'},_template_tab_new:function(c){return'<li id="new-tab"><a href="javascript:void(0);"><i class="ui-tabs-add fa fa-plus-circle"/>'+c.title_new+"</a></li>"},_template_tab:function(d){var c='<li id="tab-'+d.id+'" class="tab-element"><a id="tab-title-link-'+d.id+'" title="" href="#'+d.id+'" data-original-title=""><span id="tab-title-text-'+d.id+'" class="tab-title-text">'+d.title+"</span>";if(d.ondel){c+='<i id="delete" class="ui-tabs-delete fa fa-minus-circle"/>'}c+="</a></li>";return c},_template_tab_content:function(c){return'<div id="'+c.id+'" class="tab-pane"/>'}});return{View:b}});
define(["utils/utils"],function(a){var b=Backbone.View.extend({optionsDefault:{title_new:"",operations:null,onnew:null,min:null,max:null,onchange:null},initialize:function(e){this.visible=false;this.$nav=null;this.$content=null;this.first_tab=null;this.current_id=null;this.options=a.merge(e,this.optionsDefault);var c=$(this._template(this.options));this.$nav=c.find(".tab-navigation");this.$content=c.find(".tab-content");this.setElement(c);this.list={};var d=this;if(this.options.operations){$.each(this.options.operations,function(g,h){h.$el.prop("id",g);d.$nav.find(".operations").append(h.$el)})}if(this.options.onnew){var f=$(this._template_tab_new(this.options));this.$nav.append(f);f.tooltip({title:"Add a new tab",placement:"bottom",container:d.$el});f.on("click",function(g){f.tooltip("hide");d.options.onnew()})}},size:function(){return _.size(this.list)},current:function(){return this.$el.find(".tab-pane.active").attr("id")},add:function(f){var e=this;var h=f.id;var g=$(this._template_tab(f));var d=$(this._template_tab_content(f));this.list[h]=f.ondel?true:false;if(this.options.onnew){this.$nav.find("#new-tab").before(g)}else{this.$nav.append(g)}d.append(f.$el);this.$content.append(d);if(this.size()==1){g.addClass("active");d.addClass("active");this.first_tab=h}if(this.options.max&&this.size()>=this.options.max){this.$el.find("#new-tab").hide()}if(f.ondel){var c=g.find("#delete");c.tooltip({title:"Delete this tab",placement:"bottom",container:e.$el});c.on("click",function(){c.tooltip("destroy");e.$el.find(".tooltip").remove();f.ondel();return false})}g.on("click",function(i){i.preventDefault();if(f.onclick){f.onclick()}else{e.show(h)}});if(!this.current_id){this.current_id=h}},del:function(c){this.$el.find("#tab-"+c).remove();this.$el.find("#"+c).remove();if(this.first_tab==c){this.first_tab=null}if(this.first_tab!=null){this.show(this.first_tab)}if(this.list[c]){delete this.list[c]}if(this.size()<this.options.max){this.$el.find("#new-tab").show()}},delRemovable:function(){for(var c in this.list){this.del(c)}},show:function(c){this.$el.fadeIn("fast");this.visible=true;if(c){this.$el.find("#tab-"+this.current_id).removeClass("active");this.$el.find("#"+this.current_id).removeClass("active");this.$el.find("#tab-"+c).addClass("active");this.$el.find("#"+c).addClass("active");this.current_id=c}if(this.options.onchange){this.options.onchange(c)}},hide:function(){this.$el.fadeOut("fast");this.visible=false},hideOperation:function(c){this.$nav.find("#"+c).hide()},showOperation:function(c){this.$nav.find("#"+c).show()},setOperation:function(e,d){var c=this.$nav.find("#"+e);c.off("click");c.on("click",d)},title:function(e,d){var c=this.$el.find("#tab-title-text-"+e);if(d){c.html(d)}return c.html()},retitle:function(d){var c=0;for(var e in this.list){this.title(e,++c+": "+d)}},_template:function(c){return'<div class="ui-tabs tabbable tabs-left"><ul id="tab-navigation" class="tab-navigation nav nav-tabs"><div class="operations" style="float: right; margin-bottom: 4px;"></div></ul><div id="tab-content" class="tab-content"/></div>'},_template_tab_new:function(c){return'<li id="new-tab"><a href="javascript:void(0);"><i class="ui-tabs-add fa fa-plus-circle"/>'+c.title_new+"</a></li>"},_template_tab:function(d){var c='<li id="tab-'+d.id+'" class="tab-element"><a id="tab-title-link-'+d.id+'" title="" href="#'+d.id+'" data-original-title=""><span id="tab-title-text-'+d.id+'" class="tab-title-text">'+d.title+"</span>";if(d.ondel){c+='<i id="delete" class="ui-tabs-delete fa fa-minus-circle"/>'}c+="</a></li>";return c},_template_tab_content:function(c){return'<div id="'+c.id+'" class="tab-pane"/>'}});return{View:b}});
+3
View File
@@ -14,6 +14,9 @@ function addLogging( obj, namespace ){
return this.logger.emit( logFn, this._logNamespace, arguments );
}
if( this.logger[ logFn ] ){
//TODO:! there has to be a way to get the lineno/file into this
// http://stackoverflow.com/questions/13815640/a-proper-wrapper-for-console-log-with-correct-line-number
// http://www.paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/
return this.logger[ logFn ].apply( this.logger, arguments );
}
return undefined;
+39 -49
View File
@@ -1656,15 +1656,20 @@ div.permissionContainer{padding-left:20px}
.list-item .details label{margin:0px;padding:0px;font-weight:normal}
.list-item .details .prompt{font-weight:normal;color:#555}
.list-item .details .prompt:after{content:':';margin-right:4px}
.list-panel .vertical-spacing{margin-bottom:8px}
.list-panel .controls>*:not(:empty){margin-bottom:8px}
.list-panel .controls .name{word-wrap:break-word;font-weight:bold}
.list-panel .controls .subtitle{color:grey}.list-panel .controls .subtitle:not(:empty){margin-top:-8px}
.list-panel .controls .subtitle{color:#777;font-size:90%}
.list-panel .controls .actions{display:inline-block;float:right}.list-panel .controls .actions .icon-btn:not(:last-child){margin:0px;border-radius:0px;border-right:none}
.list-panel .controls .actions .icon-btn:first-child{margin-right:0px;border-top-left-radius:3px;border-bottom-left-radius:3px}
.list-panel .controls .actions .icon-btn:last-child{margin-left:0px;border-radius:0px 3px 3px 0px}
.list-panel .controls .actions .icon-btn:only-child{margin:0px;border-radius:3px}
.list-panel .controls .actions .icon-btn{margin-left:2px}
.list-panel .controls .messages [class$=message]{margin:0px}.list-panel .controls .messages [class$=message]:not(:last-child){margin-bottom:8px}
.list-panel .controls .messages:before,.list-panel .controls .messages:after{content:" ";display:table;}
.list-panel .controls .messages:after{clear:both}
.list-panel .controls .messages:before,.list-panel .controls .messages:after{content:" ";display:table;}
.list-panel .controls .messages:after{clear:both}
.list-panel .controls .messages [class$=message],.list-panel .controls .messages [class$=messagesmall]{margin:0px}.list-panel .controls .messages [class$=message]:not(:last-child),.list-panel .controls .messages [class$=messagesmall]:not(:last-child){margin-bottom:8px}
.list-panel .controls .list-actions{display:none}.list-panel .controls .list-actions:before,.list-panel .controls .list-actions:after{content:" ";display:table;}
.list-panel .controls .list-actions:after{clear:both}
.list-panel .controls .list-actions:before,.list-panel .controls .list-actions:after{content:" ";display:table;}
@@ -1719,58 +1724,44 @@ div.permissionContainer{padding-left:20px}
.dataset .details .actions .right .icon-btn{margin-left:2px}
.dataset .details .actions:not(:last-child){margin-bottom:8px}
.dataset .details .tags-display{display:none;margin-bottom:8px}.dataset .details .tags-display .select2-container{min-width:0px}.dataset .details .tags-display .select2-container .select2-choices{border-radius:3px}
.dataset .details .annotation-display{display:none;margin-bottom:8px}.dataset .details .annotation-display .annotation{border-radius:3px;border:1px solid rgba(153,153,153,0.30000000000000004);padding:4px;white-space:pre-line;overflow:auto}
.dataset .details .annotation-display{display:none;margin-bottom:8px}.dataset .details .annotation-display .annotation{border-radius:3px;border:1px solid rgba(153,153,153,0.30000000000000004);padding:4px;white-space:pre-wrap;overflow:auto}
.dataset .details .annotation-display .annotation:empty:after{position:relative;top:-4px;font-size:10px;font-style:italic;color:grey;content:'Click here to edit annotation'}
.dataset .details .annotation-display textarea{margin:0px 0px 2px 0px;display:block;border-radius:3px;width:100%}
.dataset .details .display-applications .display-application:last-child{margin-bottom:8px}
.dataset .details .dataset-peek{margin-bottom:8px;width:100%;margin:0px;border-radius:3px;background:white;color:black;font-size:10px;overflow:auto}.dataset .details .dataset-peek th{color:white;background:#5f6990}
.dataset .details .dataset-peek table,.dataset .details .dataset-peek th,.dataset .details .dataset-peek tr,.dataset .details .dataset-peek td{font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:10px}
.history-content.dataset .title-bar .title .hid:after,.history-content.dataset-collection .title-bar .title .hid:after{content:':'}
.history-panel .history-controls{margin:10px;padding:0px}.history-panel .history-controls [class$="messagesmall"]{margin:0px}
.history-panel .history-controls .message-container{cursor:pointer}
.history-panel .history-controls .message-container [class$=message]{margin:0px;margin-bottom:8px}
.history-panel .history-controls .history-search-controls{display:none;padding:0px 0px 8px 0px}
.history-panel .history-controls .history-title{margin-bottom:8px}
.history-panel .history-controls .history-name{word-wrap:break-word;font-weight:bold}
.history-panel .history-controls .history-title input{width:100%;margin:-2px 0 -2px -4px;font-weight:bold}
.history-panel .history-controls .editable-text{border:solid transparent 1px}
.history-panel .history-controls .editable-text:hover{cursor:pointer;border:1px dotted #999999}
.history-panel .history-controls .history-subtitle{margin-bottom:8px}
.history-panel .history-controls .history-size{float:left}
.history-panel .history-controls .history-secondary-actions{display:inline-block;float:right}.history-panel .history-controls .history-secondary-actions .icon-btn:not(:last-child){margin:0px;border-radius:0px;border-right:none}
.history-panel .history-controls .history-secondary-actions .icon-btn:first-child{margin-right:0px;border-top-left-radius:3px;border-bottom-left-radius:3px}
.history-panel .history-controls .history-secondary-actions .icon-btn:last-child{margin-left:0px;border-radius:0px 3px 3px 0px}
.history-panel .history-controls .history-secondary-actions .icon-btn:only-child{margin:0px;border-radius:3px}
.history-panel .history-controls .history-secondary-actions .icon-btn{margin-left:2px}
.history-panel .history-controls .quota-message{display:none;margin:8px 0px 5px 0px}
.history-panel .history-controls .tags-display,.history-panel .history-controls .annotation-display{display:none;margin-bottom:8px}.history-panel .history-controls .tags-display label,.history-panel .history-controls .annotation-display label{display:block;margin:0px;padding:0px;font-weight:normal;color:#555}
.history-panel .history-controls .tags-display label:after,.history-panel .history-controls .annotation-display label:after{content:':'}
.history-panel .history-controls .tags-display .select2-container{min-width:0px}.history-panel .history-controls .tags-display .select2-container .select2-choices{border-radius:3px}
.history-panel .history-controls .tags-display input{border-radius:3px}
.history-panel .history-controls .annotation-display .annotation{border-radius:3px;border:1px solid rgba(153,153,153,0.5);padding:4px;white-space:pre-line;overflow:auto}
.history-panel .history-controls .annotation-display .annotation:empty:after{position:relative;top:-4px;font-size:10px;font-style:italic;color:grey;content:'Click here to edit annotation'}
.history-panel .history-controls .annotation-display textarea{margin:0px 0px 2px 0px;display:block;border-radius:3px;width:100%}
.history-panel .history-controls .history-dataset-actions{display:none}.history-panel .history-controls .history-dataset-actions:before,.history-panel .history-controls .history-dataset-actions:after{content:" ";display:table;}
.history-panel .history-controls .history-dataset-actions:after{clear:both}
.history-panel .history-controls .history-dataset-actions:before,.history-panel .history-controls .history-dataset-actions:after{content:" ";display:table;}
.history-panel .history-controls .history-dataset-actions:after{clear:both}
.history-panel .history-controls .history-dataset-actions .btn{padding-top:2px;padding-bottom:2px;font-size:90%}
.history-panel .history-controls .history-dataset-actions .history-dataset-action-popup-btn{float:right}
.history-panel .controls{margin:10px;padding:0px}.history-panel .controls .messages>*{cursor:pointer}
.history-panel .controls .title{margin-bottom:4px}.history-panel .controls .title input{width:100%;margin:-3px 0 -3px -3px;font-weight:bold}
.history-panel .controls .subtitle:not(:empty){margin-top:-4px;margin-bottom:4px}
.history-panel .controls .editable-text{border:solid transparent 1px}
.history-panel .controls .editable-text:hover{cursor:pointer;border:1px dotted #999999}
.history-panel .controls .history-size{display:inline-block;color:black}
.history-panel .controls .actions{margin-bottom:0px}
.history-panel .controls .quota-message{display:none;margin:8px 0px 5px 0px}
.history-panel .controls .tags-display,.history-panel .controls .annotation-display{display:none;margin-bottom:8px}.history-panel .controls .tags-display label,.history-panel .controls .annotation-display label{display:block;margin:0px;padding:0px;font-weight:normal;color:#555}
.history-panel .controls .tags-display label:after,.history-panel .controls .annotation-display label:after{content:':'}
.history-panel .controls .tags-display .select2-container{min-width:0px}.history-panel .controls .tags-display .select2-container .select2-choices{border-radius:3px}
.history-panel .controls .tags-display input{border-radius:3px}
.history-panel .controls .annotation-display .annotation{border-radius:3px;border:1px solid rgba(153,153,153,0.5);padding:4px;white-space:pre-wrap;overflow:auto}
.history-panel .controls .annotation-display .annotation:empty:after{position:relative;top:-4px;font-size:10px;font-style:italic;color:grey;content:'Click here to edit annotation'}
.history-panel .controls .annotation-display textarea{margin:0px 0px 2px 0px;display:block;border-radius:3px;width:100%}
.history-panel .controls .list-actions .list-action-popup-btn{float:right}
.history-panel .list-item.history-content{border-width:1px 0px 0px 0px}.history-panel .list-item.history-content:last-child{border-width:1px 0px 1px 0px}
.history-panel .empty-history-message{display:none;margin:0px 10px 0px 10px}
.annotated-history-panel [class$=messagesmall]{margin:8px 0px 8px 0px}
.annotated-history-panel .history-controls{margin:0px 0px 16px 4px;padding:0px}.annotated-history-panel .history-controls .history-name{font-size:150%;margin-bottom:4px}
.annotated-history-panel .history-controls .history-subtitle{margin:0px;padding:0px 0px 0px 4px;padding-left:4px}
.annotated-history-panel .history-controls .history-annotation{border:1px solid lightgrey;border-width:1px 0px 0px 0px;padding:4px 0px 4px 0px;margin:4px;white-space:pre-wrap}
.annotated-history-panel .history-controls .history-annotation:empty{display:none}
.annotated-history-panel .history-controls .history-search-controls{padding:16px 0px 0px 0px}
.annotated-history-panel table.datasets-list{width:100%;table-layout:fixed}.annotated-history-panel table.datasets-list .headers{border-bottom:2px solid grey}
.annotated-history-panel table.datasets-list .headers th{padding:8px}
.annotated-history-panel table.datasets-list .dataset-row{cursor:pointer;border-bottom:1px solid grey}
.annotated-history-panel table.datasets-list .dataset-row>td{margin:0px;padding:0px;vertical-align:top}
.annotated-history-panel table.datasets-list .dataset-row>td:nth-child(1){width:50%}
.annotated-history-panel table.datasets-list .dataset-row>td:nth-child(2){padding:8px 16px 8px 16px;white-space:pre-wrap}
.annotated-history-panel table.datasets-list .dataset-row .dataset{border:0px}
.history-panel .empty-message{margin:0px 10px 0px 10px}
.annotated-history-panel .controls{margin:0px}.annotated-history-panel .controls .name{font-size:150%;margin-bottom:4px}
.annotated-history-panel .controls .subtitle{color:black}.annotated-history-panel .controls .subtitle:not(:empty){margin:0px 0px 0px 4px}
.annotated-history-panel .controls .messages:not(:empty){margin-top:16px}
.annotated-history-panel .controls .annotation-display{display:block;border:1px solid lightgrey;border-width:1px 0px 0px 0px;padding:4px 0px 4px 0px;margin:4px 4px 0px 4px;white-space:pre-wrap}.annotated-history-panel .controls .annotation-display:empty{display:none}
.annotated-history-panel .controls .search{padding:16px 0px 0px 0px;margin-bottom:0px}
.annotated-history-panel table.list-items{width:100%;table-layout:fixed}.annotated-history-panel table.list-items .headers{border-bottom:2px solid grey}
.annotated-history-panel table.list-items .headers th{padding:8px}
.annotated-history-panel table.list-items>tbody>tr{cursor:pointer;border-bottom:1px solid grey}.annotated-history-panel table.list-items>tbody>tr>td{margin:0px;padding:0px;vertical-align:top}.annotated-history-panel table.list-items>tbody>tr>td:nth-child(1){width:50%}
.annotated-history-panel table.list-items>tbody>tr>td:nth-child(2){padding:8px 16px 8px 16px;white-space:pre-wrap}
.annotated-history-panel table.list-items>tbody>tr .list-item{border:0px}
.annotated-history-panel .empty-message{margin-top:8px}
.history-panel .dataset-collection .subtitle{margin-top:2px;font-size:90%;color:#777}
.history-panel .dataset-collection-panel .controls{padding:0px}
body.historyPage{background:#dfe5f9;color:#000;margin:5px;border:0;padding:0}
div.historyLinks{margin:5px 5px}
div.historyItem{margin:0 -5px;padding:8px 10px;border-top:solid #bfbfbf 1px;border-right:none;word-wrap:break-word;background:#eee}div.historyItem .state-icon{display:inline-block;vertical-align:middle;width:16px;height:16px;background-position:0 1px;background-repeat:no-repeat}
@@ -1824,8 +1815,7 @@ pre.peek table,pre.peek th,pre.peek tr,pre.peek td{font-family:Monaco,Menlo,Cons
.dataset-collection-panel .controls{padding:8px}.dataset-collection-panel .controls .navigation{margin-top:4px}.dataset-collection-panel .controls .navigation .back .fa-icon{margin-right:4px;font-size:120%;font-weight:bold;text-decoration:none}
.dataset-collection-panel .controls .title{margin-top:12px}.dataset-collection-panel .controls .title .name{font-weight:bold}
.dataset-collection-panel .controls .subtitle{color:#777}
.dataset-collection-panel .datasets-list{margin-top:8px}.dataset-collection-panel .datasets-list .dataset-collection-element{border-width:1px 0px 0px 0px}.dataset-collection-panel .datasets-list .dataset-collection-element:last-child{border-bottom-width:1px}
.history-panel .dataset-collection .subtitle{margin-top:2px;font-size:90%;color:#777}
.dataset-collection-panel .list-items{margin-top:8px}.dataset-collection-panel .list-items .dataset-collection-element{border-width:1px 0px 0px 0px}.dataset-collection-panel .list-items .dataset-collection-element:last-child{border-bottom-width:1px}
.collection-creator{height:100%;overflow:hidden;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.collection-creator ol,.collection-creator li{list-style:none;padding:0;margin:0}
.collection-creator>*:not(.popover){padding:0px 8px 0px 8px}
.collection-creator .btn{border-color:#BFBFBF}
+1 -1
View File
@@ -11,7 +11,7 @@
.embedded-item .expanded-content{display:none;background-color:white;padding:5px}
.embedded-item .item-content{max-height:25em;overflow:auto}
.embedded-item.visualization .item-content{overflow:hidden}
.embedded-item .title{vertical-align:top;text-align:center;font-weight:bold;padding-bottom:5px}
.embedded-item>.title{vertical-align:top;text-align:center;font-weight:bold;padding-bottom:5px}
.embedded-item.placeholder .content{padding:0.5em 0.5em;font-style:italic;text-align:center}
table.annotated-item{width:100%;border-collapse:collapse}
table.annotated-item td,th{padding:0}
+1 -14
View File
@@ -58,7 +58,7 @@
color: #777;
}
}
.datasets-list {
.list-items {
margin-top: 8px;
.dataset-collection-element {
border-width: 1px 0px 0px 0px;
@@ -68,16 +68,3 @@
}
}
}
//============================================================================= collection inside history panel
.history-panel .dataset-collection {
.subtitle {
margin-top: 2px;
font-size: 90%;
color: #777;
}
}
//============================================================================= collection panel inside history panel
//.history-panel .dataset-collection-panel {
//}
+2 -2
View File
@@ -66,7 +66,7 @@
overflow: hidden;
}
.embedded-item .title {
.embedded-item > .title {
vertical-align: top;
text-align: center;
font-weight: bold;
@@ -96,4 +96,4 @@ table.annotated-item .annotation {
table.annotated-item td.annotation {
vertical-align: text-top;
padding-top: 1em;
}
}
+85 -87
View File
@@ -305,7 +305,8 @@
.list-item .vertical-spacing;
.annotation {
.list-item .info-section;
white-space: pre-line;
//white-space: pre-line;
white-space: pre-wrap;
overflow: auto;
}
// fake placeholder for editable text annotation
@@ -371,38 +372,26 @@
// ---------------------------------------------------------------------------- history
.history-panel {
.history-controls {
.controls {
margin: 10px;
padding: 0px;
[class$="messagesmall"] {
margin: 0px;
}
.message-container {
.messages > * {
cursor: pointer;
}
.message-container [class$=message] {
margin: 0px;
margin-bottom: 8px;
}
.history-search-controls {
display: none;
padding: 0px 0px 8px 0px;
.title {
margin-bottom: 4px;
input {
width: 100%;
// keep the text in position
margin: -3px 0px -3px -3px;
font-weight: bold;
}
}
.history-title {
margin-bottom: 8px;
}
.history-name {
word-wrap: break-word;
font-weight: bold;
}
.history-title input {
width: 100%;
// keep the text in position
margin: -2px 0px -2px -4px;
font-weight: bold;
.subtitle:not(:empty){
margin-top: -4px;
margin-bottom: 4px;
}
.editable-text {
border: solid transparent 1px;
@@ -412,18 +401,12 @@
border: 1px dotted #999999;
}
.history-subtitle {
margin-bottom: 8px;
}
.history-size {
float: left;
display: inline-block;
color: black;
}
.history-secondary-actions {
.icon-btn-group();
float: right;
.icon-btn {
margin-left: @icon-btn-margin;
}
.actions {
margin-bottom: 0px;
}
.quota-message {
@@ -462,7 +445,8 @@
border-radius: 3px;
border: 1px solid fadeout( @layout-border-color, 50% );
padding: 4px;
white-space: pre-line;
//white-space: pre-line;
white-space: pre-wrap;
overflow: auto;
}
// fake placeholder for editable text annotation
@@ -483,15 +467,8 @@
}
}
.history-dataset-actions {
display: none;
.clear;
.btn {
padding-top: 2px;
padding-bottom: 2px;
font-size: 90%;
}
.history-dataset-action-popup-btn {
.list-actions {
.list-action-popup-btn {
float: right;
}
}
@@ -506,52 +483,50 @@
}
}
.empty-history-message {
display: none;
.empty-message {
margin: 0px 10px 0px 10px;
}
}
// ---------------------------------------------------------------------------- annotated-history-panel
.annotated-history-panel {
//TODO: most of these styles are specific to history/display.mako and not to this type of panel in general
//TODO: some of these styles are also overrides of history-panel - remove those from hpanel and revisit this
[class$=messagesmall] {
margin: 8px 0px 8px 0px;
}
.history-controls {
margin: 0px 0px 16px 4px;
padding: 0px;
.history-name {
.controls {
margin: 0px;
.name {
font-size: 150%;
margin-bottom: 4px;
}
.history-subtitle {
margin: 0px;
padding: 0px 0px 0px 4px;
padding-left: 4px;
.subtitle {
color: black;
&:not(:empty) {
margin: 0px 0px 0px 4px;
}
}
.history-annotation {
.messages {
&:not(:empty) {
margin-top: 16px;
}
}
// annotations are displayed by default in this view
.annotation-display {
display: block;
border: 1px solid lightgrey;
border-width: 1px 0px 0px 0px;
padding: 4px 0px 4px 0px;
margin: 4px;
margin: 4px 4px 0px 4px;
white-space: pre-wrap;
}
.history-annotation:empty {
display: none;
&:empty {
display: none;
}
}
.history-search-controls {
.search {
padding: 16px 0px 0px 0px;
margin-bottom: 0px;
}
}
table.datasets-list {
table.list-items {
width: 100%;
table-layout: fixed;
@@ -561,25 +536,48 @@
.headers th {
padding: 8px;
}
.dataset-row {
& > tbody > tr {
// tr is clickable for expansion
cursor: pointer;
border-bottom: 1px solid grey;
& > td {
margin: 0px;
padding: 0px;
vertical-align: top;
&:nth-child(1) {
width: 50%;
}
&:nth-child(2) {
/* top and bottom should be == title-bar padding */
padding: 8px 16px 8px 16px;
// do not html format
white-space: pre-wrap;
}
}
// tr has border - remove from items
.list-item {
border: 0px;
}
}
.dataset-row > td {
margin: 0px;
}
.empty-message {
margin-top: 8px;
}
}
// ---------------------------------------------------------------------------- collections nested in histories
.history-panel {
.dataset-collection {
.subtitle {
margin-top: 2px;
font-size: 90%;
color: #777;
}
}
.dataset-collection-panel {
.controls {
padding: 0px;
vertical-align: top;
}
.dataset-row > td:nth-child(1) {
width: 50%;
}
.dataset-row > td:nth-child(2) {
/* top and bottom should be <= title-bar padding */
padding: 8px 16px 8px 16px;
white-space: pre-wrap;
}
.dataset-row .dataset {
border: 0px;
}
}
}
+13 -17
View File
@@ -101,24 +101,25 @@
// ---------------------------------------------------------------------------- generic panel list (of list-items)
.list-panel {
//TODO: duplicated
@vertical-gap: 8px;
.vertical-spacing {
margin-bottom: @vertical-gap;
}
.controls {
& > *:not(:empty) {
//background: rgba( 0, 255, 0, 0.2 );
margin-bottom: 8px;
}
.title {
}
.name {
word-wrap: break-word;
font-weight: bold;
}
.subtitle {
color: grey;
&:not(:empty) {
margin-top: -8px;
}
color: #777;
font-size: 90%;
}
.actions {
.icon-btn-group();
float: right;
@@ -126,19 +127,16 @@
margin-left: @icon-btn-margin;
}
}
.messages {
[class$=message] {
.clearfix();
[class$=message],
[class$=messagesmall] {
margin: 0px;
&:not(:last-child) {
margin-bottom: 8px;
}
}
}
.search {
}
.list-actions {
display: none;
.clear;
@@ -149,8 +147,7 @@
}
}
}
// display only a top border on all
// display only a top border on all but the last
.list-items {
.list-item {
&:not(:last-child) {
@@ -158,7 +155,6 @@
}
}
}
.empty-message {
display: none;
margin: 0px;
+3 -10
View File
@@ -45,11 +45,8 @@
<div id="history-${ history_dict[ 'id' ] }" class="history-panel">
</div>
<script type="text/javascript">
var debugging = JSON.parse( sessionStorage.getItem( 'debugging' ) ) || false,
historyJSON = ${h.dumps( history_dict )},
var historyJSON = ${h.to_json_string( history_dict )},
hdaJSON = ${h.dumps( hda_dicts )};
//window.historyJSON = historyJSON;
//window.hdaJSON = hdaJSON;
require.config({
baseUrl : "${h.url_for( '/static/scripts' )}"
@@ -57,18 +54,14 @@
// history module is already in the dpn chain from the panel. We can re-scope it here.
var historyModel = require( 'mvc/history/history-model' ),
history = new historyModel.History( historyJSON, hdaJSON, {
logger: ( debugging )?( console ):( null )
});
window.historyPanel = new panelMod.AnnotatedHistoryPanel({
show_deleted : false,
show_hidden : false,
el : $( "#history-" + historyJSON.id ),
model : history,
onready : function(){
this.render();
}
});
model : history
}).render();
});
</script>
</%def>
+2 -4
View File
@@ -62,14 +62,12 @@
}
$(function(){
var debugging = JSON.parse( sessionStorage.getItem( 'debugging' ) ) || false,
historyModel = require( 'mvc/history/history-model' ),
var historyModel = require( 'mvc/history/history-model' ),
panel = new panelMod.AnnotatedHistoryPanel({
el : $embeddedHistory.find( ".history-panel" ),
model : new historyModel.History(
${h.dumps( history_dict )},
${h.dumps( hda_dicts )},
{ logger: ( debugging )?( console ):( null ) }
${h.dumps( hda_dicts )}
)
}).render();
+10 -13
View File
@@ -168,8 +168,8 @@ ${parent.javascripts()}
hdaJSON = ${h.dumps( hdas )};
panelToUse = ( userIsOwner )?
//TODO: change class names
({ location: 'mvc/history/history-panel-edit', className: 'HistoryPanel' }):
({ location: 'mvc/history/history-panel', className: 'ReadOnlyHistoryPanel' });
({ location: 'mvc/history/history-panel-edit', className: 'HistoryPanelEdit' }):
({ location: 'mvc/history/history-panel', className: 'HistoryPanel' });
require.config({
baseUrl : "${h.url_for( '/static/scripts' )}"
@@ -187,17 +187,14 @@ ${parent.javascripts()}
show_hidden : ${show_hidden_json},
purgeAllowed : Galaxy.config.allow_user_dataset_purge,
el : $( "#history-" + historyJSON.id ),
model : history,
onready : function(){
var panel = this;
$( '#toggle-deleted' ).on( 'click', function(){
panel.toggleShowDeleted();
});
$( '#toggle-hidden' ).on( 'click', function(){
panel.toggleShowHidden();
});
this.render();
}
model : history
}).render();
$( '#toggle-deleted' ).on( 'click', function(){
historyPanel.toggleShowDeleted();
});
$( '#toggle-hidden' ).on( 'click', function(){
historyPanel.toggleShowHidden();
});
});
});
+9 -5
View File
@@ -20,21 +20,25 @@ $(function(){
<script type="text/javascript">
define( 'app', function(){
require([
//'mvc/history/history-panel'
//'mvc/history/history-panel-annotated'
//'mvc/history/history-panel-edit'
'mvc/history/history-panel-edit-current'
], function( historyPanel ){
$(function(){
// history module is already in the dpn chain from the panel. We can re-scope it here.
var historyModel = require( 'mvc/history/history-model' );
//window.panel = new historyPanel.HistoryPanel({
//window.panel = new historyPanel.AnnotatedHistoryPanel({
//window.panel = new historyPanel.HistoryPanelEdit({
window.panel = new historyPanel.CurrentHistoryPanel({
show_deleted : bootstrapped.show_deleted,
show_hidden : bootstrapped.show_hidden,
purgeAllowed : Galaxy.config.allow_user_dataset_purge,
el : $( "body" ),
model : new historyModel.History( bootstrapped.history, bootstrapped.hdas ),
onready : function(){
this.render();
}
model : new historyModel.History( bootstrapped.history, bootstrapped.hdas )
});
panel.render().$el.appendTo( 'body' );
$( 'body' ).css( 'padding', '10px' );
});
});
});
+6 -6
View File
@@ -66,7 +66,7 @@
},
"${_("Collapse Expanded Datasets")}": function() {
if( Galaxy && Galaxy.currHistoryPanel ){
Galaxy.currHistoryPanel.collapseAllHdaBodies();
Galaxy.currHistoryPanel.collapseAll();
}
},
"${_("Include Deleted Datasets")}": function( clickEvent, thisMenuOption ) {
@@ -214,12 +214,12 @@
el : $( "#current-history-panel" ),
purgeAllowed : Galaxy.config.allow_user_dataset_purge,
linkTarget : 'galaxy_main',
onready : function loadAsCurrentHistoryPanel(){
this.connectToQuotaMeter( Galaxy.quotaMeter )
.connectToOptionsMenu( Galaxy.historyOptionsMenu );
this.loadCurrentHistory();
}
$scrollContainer: function(){ return this.$el.parent(); }
});
currPanel
.connectToQuotaMeter( Galaxy.quotaMeter )
.connectToOptionsMenu( Galaxy.historyOptionsMenu );
currPanel.loadCurrentHistory();
Galaxy.currHistoryPanel = currPanel;
});
});
+6 -6
View File
@@ -23,7 +23,7 @@ var tooltipSelector = spaceghost.data.selectors.tooltipBalloon,
unnamedName = spaceghost.historypanel.data.text.history.newName,
nameSelector = spaceghost.historypanel.data.selectors.history.name,
subtitleSelector = spaceghost.historypanel.data.selectors.history.subtitle,
sizeSelector = spaceghost.historypanel.data.selectors.history.size,
initialSizeStr = spaceghost.historypanel.data.text.history.newSize,
tagIconSelector = spaceghost.historypanel.data.selectors.history.tagIcon,
annoIconSelector = spaceghost.historypanel.data.selectors.history.annoIcon,
@@ -47,11 +47,11 @@ spaceghost.openHomePage().historypanel.waitForHdas( function testPanelStructure(
this.test.assertVisible( nameSelector, 'History name is visible' );
this.test.assertSelectorHasText( nameSelector, unnamedName, 'History name is ' + unnamedName );
this.test.comment( "history subtitle should display size and size should be 0 bytes" );
this.test.assertExists( subtitleSelector, 'Found ' + subtitleSelector );
this.test.assertVisible( subtitleSelector, 'History subtitle is visible' );
this.test.assertSelectorHasText( subtitleSelector, initialSizeStr,
'History subtitle has "' + initialSizeStr + '"' );
this.test.comment( "history should display size and size should be 0 bytes" );
this.test.assertExists( sizeSelector, 'Found ' + sizeSelector );
this.test.assertVisible( sizeSelector, 'History size is visible' );
this.test.assertSelectorHasText( sizeSelector, initialSizeStr,
'History size has "' + initialSizeStr + '"' );
this.test.comment( "NO tags or annotations icons should be available for an anonymous user" );
this.test.assertDoesntExist( tagIconSelector, 'Tag icon button not found' );
+2 -2
View File
@@ -8,7 +8,7 @@ spaceghost.test.begin( 'Test API functions for histories with an anonymous user'
spaceghost.start();
// =================================================================== TESTS
spaceghost.thenOpen( spaceghost.baseUrl ).waitForSelector( '.history-name' );
spaceghost.thenOpen( spaceghost.baseUrl ).waitForSelector( spaceghost.historypanel.data.selectors.history.name );
spaceghost.then( function(){
// ------------------------------------------------------------------------------------------- anon allowed
@@ -65,7 +65,7 @@ spaceghost.then( function(){
});
// ------------------------------------------------------------------------------------------- hdas
spaceghost.thenOpen( spaceghost.baseUrl ).waitForSelector( '.history-name' );
spaceghost.thenOpen( spaceghost.baseUrl ).waitForSelector( spaceghost.historypanel.data.selectors.history.name );
spaceghost.then( function(){
spaceghost.tools.uploadFile( '../../test-data/1.sam', function( uploadInfo ){
this.test.assert( uploadInfo.hdaElement !== null, "Convenience function produced hda" );
+12 -11
View File
@@ -27,6 +27,7 @@ var tooltipSelector = spaceghost.data.selectors.tooltipBalloon,
nameSelector = spaceghost.historypanel.data.selectors.history.name,
subtitleSelector = spaceghost.historypanel.data.selectors.history.subtitle,
sizeSelector = spaceghost.historypanel.data.selectors.history.size,
unnamedName = spaceghost.historypanel.data.text.history.newName,
initialSizeStr = spaceghost.historypanel.data.text.history.newSize,
tagIconSelector = spaceghost.historypanel.data.selectors.history.tagIcon,
@@ -64,11 +65,11 @@ spaceghost.openHomePage().historypanel.waitForHdas( function(){
this.test.assertVisible( nameSelector, 'History name is visible' );
this.test.assertSelectorHasText( nameSelector, unnamedName, 'History name is ' + unnamedName );
this.test.comment( "history subtitle should display size and size should be: " + initialSizeStr );
this.test.assertExists( subtitleSelector, 'Found ' + subtitleSelector );
this.test.assertVisible( subtitleSelector, 'History subtitle is visible' );
this.test.assertSelectorHasText( subtitleSelector, initialSizeStr,
'History subtitle has "' + initialSizeStr + '"' );
this.test.comment( "history should display size and size should be: " + initialSizeStr );
this.test.assertExists( sizeSelector, 'Found ' + sizeSelector );
this.test.assertVisible( sizeSelector, 'History size is visible' );
this.test.assertSelectorHasText( sizeSelector, initialSizeStr,
'History size has "' + initialSizeStr + '"' );
this.test.comment( "tags and annotation icons should be available" );
this.test.assertExists( tagIconSelector, 'Tag icon button found' );
@@ -157,12 +158,12 @@ spaceghost.then( function checkPanelStructure(){
this.test.assertSelectorHasText( nameSelector, newHistoryName, 'History name is ' + newHistoryName );
var onetxtFilesize = require( 'fs' ).size( filepathToUpload ),
expectedSubtitle = onetxtFilesize + ' bytes';
this.test.comment( "history subtitle should display size and size should be " + onetxtFilesize + " bytes" );
this.test.assertExists( subtitleSelector, 'Found ' + subtitleSelector );
this.test.assertVisible( subtitleSelector, 'History subtitle is visible' );
this.test.assertSelectorHasText( subtitleSelector, expectedSubtitle,
'History subtitle has "' + expectedSubtitle + '": ' + this.fetchText( subtitleSelector ).trim() );
expectedSize = onetxtFilesize + ' bytes';
this.test.comment( "history should display size and size should be " + onetxtFilesize + " bytes" );
this.test.assertExists( sizeSelector, 'Found ' + sizeSelector );
this.test.assertVisible( sizeSelector, 'History size is visible' );
this.test.assertSelectorHasText( sizeSelector, expectedSize,
'History size has "' + expectedSize + '": ' + this.fetchText( sizeSelector ).trim() );
this.test.comment( "tags and annotation icons should be available" );
this.test.assertExists( tagIconSelector, 'Tag icon button found' );
+2 -1
View File
@@ -17,7 +17,8 @@ if( spaceghost.fixtureData.testUser ){
password = spaceghost.fixtureData.testUser.password;
}
var userEmailSelector = '//a[contains(text(),"Logged in as")]';
//var userEmailSelector = '//a[contains(text(),"Logged in as")]';
var userEmailSelector = spaceghost.data.selectors.masthead.userMenu.userEmail_xpath;
// =================================================================== TESTS
// register a user (again...)
+10 -9
View File
@@ -356,15 +356,16 @@ HistoryPanel.prototype.data = {
},
selectors : {
history : {
title : '.history-title',
name : '.history-title .history-name',
nameEditableTextInput : '.history-name input',
subtitle : '.history-subtitle',
tagIcon : '.history-secondary-actions .history-tag-btn',
tagArea : '.history-controls .tags-display',
annoIcon : '.history-secondary-actions .history-annotate-btn',
annoArea : '.history-controls .annotation-display',
emptyMsg : '.empty-history-message',
title : '.controls .title',
name : '.title .name',
nameEditableTextInput : '.name input',
subtitle : '.subtitle',
size : '.history-size',
tagIcon : '.actions .history-tag-btn',
tagArea : '.controls .tags-display',
annoIcon : '.actions .history-annotate-btn',
annoArea : '.controls .annotation-display',
emptyMsg : '.empty-message',
hdaContainer: '.datasets-list'
},
hda : {
+6 -6
View File
@@ -56,14 +56,14 @@ User.prototype._submitRegistration = function _submitRegistration( email, passwo
// need manual submit (not a normal html form)
this.click( xpath( spaceghost.data.selectors.registrationPage.submit_xpath ) );
});
this.waitForNavigation( 'user/create', function afterRegister(){
// this.withMainPanel( function mainAfterRegister(){
// var messageInfo = spaceghost.getElementInfo( spaceghost.data.selectors.messages.all );
// spaceghost.debug( 'post registration message:\n' + spaceghost.jsonStr( messageInfo ) );
// });
});
});
this.waitForNavigation( 'user/create', function afterRegister(){
// this.withMainPanel( function mainAfterRegister(){
// var messageInfo = spaceghost.getElementInfo( spaceghost.data.selectors.messages.all );
// spaceghost.debug( 'post registration message:\n' + spaceghost.jsonStr( messageInfo ) );
// });
});
});
};
+1 -1
View File
@@ -638,7 +638,7 @@ SpaceGhost.prototype.waitForMultipleNavigation = function waitForMultipleNavigat
}
function catchNavReq( url ){
//this.debug( 'nav.req: ' + url );
this.debug( 'nav.req: ' + url );
for( var i=( urlsToWaitFor.length - 1 ); i>=0; i -= 1 ){
//this.debug( '\t checking: ' + urlsToWaitFor[i] );
if( urlMatches( urlsToWaitFor[i], url ) ){