commit/galaxy-central: 2 new changesets
2 new commits in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/737f78bb4a45/ Changeset: 737f78bb4a45 User: carlfeberhard Date: 2014-08-26 18:59:15 Summary: UI, Dataset choice control: add DatasetChoiceModal for choosing single or multiple datasets, add DatasetChoice and MultiDatasetChoice for displaying and activating selection modal from within a page; correct lookup of galaxy_config in dataset-model; add ListPanel for displaying collections of ListViews; add DatasetListPanel for displaying collections of generic datasets; add default no-op localizer (_l) to ui.js until that file is AMD; factor out icon-btn.less from history.less; remove make_popup_menus in default expandable behaviors Affected #: 17 files diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/scripts/mvc/base-mvc.js --- a/static/scripts/mvc/base-mvc.js +++ b/static/scripts/mvc/base-mvc.js @@ -1,6 +1,7 @@ define([ - 'utils/add-logging' -], function( addLogging ){ + 'utils/add-logging', + 'utils/localization' +], function( addLogging, _l ){ //ASSUMES: backbone //============================================================================== /** @class Mixin to add logging capabilities to an object. @@ -390,6 +391,7 @@ /** 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 @@ -451,7 +453,7 @@ _setUpBehaviors : function( $where ){ $where = $where || this.$el; // set up canned behavior on children (bootstrap, popupmenus, editable_text, etc.) - make_popup_menus( $where ); + //make_popup_menus( $where ); $where.find( '[title]' ).tooltip({ placement : 'bottom' }); }, diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/scripts/mvc/dataset/dataset-choice.js --- /dev/null +++ b/static/scripts/mvc/dataset/dataset-choice.js @@ -0,0 +1,442 @@ +define([ + 'mvc/dataset/dataset-model', + 'mvc/dataset/dataset-list', + 'mvc/ui/ui-modal', + 'mvc/base-mvc', + 'utils/localization' +], function( DATASET, DATASET_LIST, MODAL, BASE_MVC, _l ){ +/* ============================================================================ +TODO: + does this really work with mixed contents? + Single dataset choice: allow none? + tooltips rendered *behind* modal + collection selector + better handling when no results returned from filterDatasetJSON + pass optional subtitle from choice display to modal + onfirstclick + drop target + return modal with promise? + + auto showing the modal may not be best + + add hidden inputs + // cut1 on single dataset (17 in the list) + __switch_default__ select_single + input 17 + + // cut1 on two datasets + __switch_default__ select_single + input|__multirun__ 13 + input|__multirun__ 15 + + // cut1 on a collection + __switch_default__ select_collection + input|__collection_multirun__ f2db41e1fa331b3e + +============================================================================ */ +/** Filters an array of dataset plain JSON objs. + */ +function _filterDatasetJSON( datasetJSON, where, datasetsOnly ){ +//TODO: replace with _.matches (underscore 1.6.0) + function matches( obj, toMatch ){ + for( var key in toMatch ){ + if( toMatch.hasOwnProperty( key ) ){ + if( obj[ key ] !== toMatch[ key ] ){ + return false; + } + } + } + return true; + } + + return datasetJSON.filter( function( json ){ + return ( !json.deleted && json.visible ) + && ( !datasetsOnly || json.collection_type === undefined ) + && ( matches( json, where ) ); + }); +} + +// ============================================================================ +/** Given an array of plain JSON objs rep. datasets, show a modal allowing a choice + * of one or more of those datasets. + * + * Pass: + * an array of plain JSON objects representing allowed dataset choices + * a map of options (see below) + * + * Options: + * datasetsOnly: T: display only datasets, F: datasets + dataset collections + * where: a map of attributes available choices *must have* (defaults to { state: 'ok' }) + * multiselect: T: user can select more than one, F: only one + * selected: array of dataset ids to make them selected by default + * + * @example: + * var datasetJSON = // from ajax or bootstrap + * // returns a jQuery promise (that 'fail's only if no datasets are found matching 'where' below) + * var choice = new DatasetChoiceModal( datasetJSON, { + * datasetsOnly : false, + * where : { state: 'ok', data_type: 'bed', ... }, + * multiselect : true, + * selected : [ 'df7a1f0c02a5b08e', 'abcdef0123456789' ] + * + * }).done( function( json ){ + * if( json ){ + * console.debug( json ); + * // returned choice will always be an array (single or multi) + * // [{ <selected dataset JSON 1>, <selected dataset JSON 2>, ... }] + * // ... do stuff + * } else { + * // json will === null if the user cancelled selection + * console.debug( 'cancelled' ); + * } + * }); + */ +var DatasetChoiceModal = function( datasetJSON, options ){ + + // option defaults + options = _.defaults( options || {}, { + // show datasets or datasets and collections + datasetsOnly : true, + // map of attributes to filter datasetJSON by + where : { state: 'ok' }, + // select more than one dataset? + multiselect : false, + // any dataset ids that will display as already selected + selected : [] + }); + // default title should depend on multiselect + options.title = options.title || + ( options.multiselect? _l( 'Choose datasets:' ): _l( 'Choose a dataset:' ) ); + + var modal, list, buttons, + promise = jQuery.Deferred(), + filterFn = options.filter || _filterDatasetJSON; + + // filter the given datasets and if none left return a rejected promise for use with fail() + datasetJSON = filterFn( datasetJSON, options.where, options.datasetsOnly ); + if( !datasetJSON.length ){ + return promise.reject( 'No matches found' ); + } + + // resolve the returned promise with the json of the selected datasets + function resolveWithSelected(){ + promise.resolve( list.getSelectedModels().map( function( model ){ + return model.toJSON(); + })); + } + // if multiselect - add a button for the user to complete the changes + if( options.multiselect ){ + buttons = {}; + buttons[ _l( 'Ok' ) ] = resolveWithSelected; + } + + // create a full-height modal that's cancellable, remove unneeded elements and styles + modal = new MODAL.View({ + height : 'auto', + buttons : buttons, + closing_events : true, + closing_callback : function(){ promise.resolve( null ); }, + body : [ + '<div class="list-panel"></div>' + ].join('') + }); + modal.$( '.modal-header' ).remove(); + modal.$( '.modal-footer' ).css( 'margin-top', '0px' ); + + // attach a dataset list (of the filtered datasets) to that modal that's selectable + list = new DATASET_LIST.DatasetList({ + title : options.title, + subtitle : options.subtitle || _l([ +//TODO: as option + 'Click the checkboxes on the right to select datasets. ', + 'Click the datasets names to see their details. ' + ].join('')), + el : modal.$body.find( '.list-panel' ), + selecting : true, + selected : options.selected, + collection : new DATASET.DatasetAssociationCollection( datasetJSON ) + }); + + // when the list is rendered, show the modal (also add a specifying class for css) + list.once( 'rendered:initial', function(){ + modal.show(); + modal.$el.addClass( 'dataset-choice-modal' ); + }); + if( !options.multiselect ){ + // if single select, remove the all/none list actions from the panel + list.on( 'rendered', function(){ + list.$( '.list-actions' ).hide(); + }); + // if single select, immediately resolve on a single selection + list.on( 'view:selected', function( view ){ + promise.resolve([ view.model.toJSON() ]); + }); + } + list.render( 0 ); + + // return the promise, and on any resolution close the modal + return promise.always( function(){ + modal.hide(); + }); +}; + + +// ============================================================================ +/** Activator for single dataset selection modal and display of the selected dataset. + * The activator/display will show as a single div and, when a dataset is selected, + * show the name and details of the selected dataset. + * + * When clicked the div will generate a DatasetChoiceModal of the available choices. + * + * Options: + * datasetJSON: array of plain json objects representing allowed choices + * datasetsOnly: T: only show datasets in the allowed choices, F: datasets + collections + * where: map of attributes to filter datasetJSON by (e.g. { data_type: 'bed' }) + * label: the label/prompt displayed + * selected: array of dataset ids that will show as already selected in the control + * + * @example: + * var choice1 = new DATASET_CHOICE.DatasetChoice({ + * datasetJSON : datasetJSON, + * label : 'Input dataset', + * selected : [ 'df7a1f0c02a5b08e' ] + * }); + * $( 'body' ).append( choice1.render().$el ) + * + * Listen to the DatasetChoice to react to changes in the user's choice/selection: + * @example: + * choice1.on( 'selected', function( chooser, selectionJSONArray ){ + * // ... do stuff with new selections + * }); + */ +var DatasetChoice = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend({ + + //logger : console, + + className : 'dataset-choice', + + /** set up defaults, options, and listeners */ + initialize : function( attributes ){ + this.debug( this + '(DatasetChoice).initialize:', attributes ); + + this.label = attributes.label !== undefined? _l( attributes.label ) : ''; + this.where = attributes.where; + this.datasetsOnly = attributes.datasetsOnly !== undefined? attributes.datasetsOnly: true; + + this.datasetJSON = attributes.datasetJSON || []; + this.selected = attributes.selected || []; + + this._setUpListeners(); + }, + + /** add any (bbone) listeners */ + _setUpListeners : function(){ + //this.on( 'all', function(){ + // this.log( this + '', arguments ); + //}); + }, + + /** render the view */ + render : function(){ + var json = this.toJSON(); + this.$el.html( this._template( json ) ); + this.$( '.selected' ).replaceWith( this._renderSelected( json ) ); + return this; + }, + + /** return plain html for the overall control */ + _template : function( json ){ + return _.template([ + '<label>', + '<span class="prompt"><%= json.label %></span>', + '<div class="selected"></div>', + '</label>' + ].join(''), { json: json }); + }, + + /** return jQ DOM for the selected dataset (only one) */ + _renderSelected : function( json ){ + if( json.selected.length ){ +//TODO: break out? + return $( _.template([ + '<div class="selected">', + '<span class="title"><%= selected.hid %>: <%= selected.name %></span>', + '<span class="subtitle">', + '<i><%= selected.misc_blurb %></i>', + '<i>', _l( 'format' ) + ': ', '<%= selected.data_type %></i>', + '<i><%= selected.misc_info %></i>', + '</span>', + '</div>' + ].join( '' ), { selected: json.selected[0] })); + } + return $([ + '<span class="none-selected-msg">(', + _l( 'click to select a dataset' ), + ')</span>' + ].join( '' )); + }, + +//TODO:?? why not just pass in view? + /** return a plain JSON object with both the view and dataset attributes */ + toJSON : function(){ + var chooser = this; + return { + label : chooser.label, + datasets : chooser.datasetJSON, + selected : _.compact( _.map( chooser.selected, function( id ){ + return _.findWhere( chooser.datasetJSON, { id: id }); + })) + }; + }, + + /** event map: when to open the modal */ + events : { + // the whole thing functions as a button + 'click' : 'chooseWithModal' + }, + +//TODO:?? modal to prop of this? +//TODO:?? should be able to handle 'none selectable' on initialize + /** open the modal and handle the promise representing the user's choice + * @fires 'selected' when the user selects dataset(s) - passed full json of the selected datasets + * @fires 'cancelled' when the user clicks away/closes the modal (no selection made) - passed this + * @fires 'error' if the modal has no selectable datasets based on this.where - passed this and other args + */ + chooseWithModal : function(){ + var chooser = this; + + return this._createModal() + .done( function( json ){ + if( json ){ + chooser.selected = _.pluck( json, 'id' ); + chooser.trigger( 'selected', chooser, json ); + chooser.render(); + + } else { + chooser.trigger( 'cancelled', chooser ); + } + }) + + .fail( function(){ + chooser.trigger( 'error', chooser, arguments ); + }); + }, + + /** create and return the modal to use for choosing */ + _createModal : function(){ + return new DatasetChoiceModal( this.datasetJSON, this._getModalOptions() ); + }, + + /** return a plain JSON containing the options to pass to the modal */ + _getModalOptions : function(){ + return { + title : this.label, + multiselect : false, + selected : this.selected, + where : this.where, + datasetsOnly : this.datasetsOnly + }; + }, + + // ------------------------------------------------------------------------ misc + /** string rep */ + toString : function(){ + return 'DatasetChoice(' + this.selected + ')'; + } +}); + + +// ============================================================================ +/** Activator for multiple dataset selection modal and display of the selected datasets. + * The activator/display will show as a table of all choices. + * + * See DatasetChoice (above) for example usage. + * + * Additional options: + * showHeaders: T: show headers for selected dataset attributes in the display table + * cells: map of attribute keys -> Human readable/localized column headers + * (e.g. { data_type: _l( 'Format' ) }) - defaults are listed below + */ +var MultiDatasetChoice = DatasetChoice.extend({ + + className : DatasetChoice.prototype.className + ' multi', + + /** default (dataset attribute key -> table header text) map of what cells to display in the table */ + cells : { + hid : _l( 'History #' ), + name : _l( 'Name' ), + misc_blurb : _l( 'Summary' ), + data_type : _l( 'Format' ), + genome_build : _l( 'Genome' ), + tags : _l( 'Tags' ), + annotation : _l( 'Annotation' ) + }, + + /** in this override, add the showHeaders and cells options */ + initialize : function( attributes ){ + this.showHeaders = attributes.showHeaders !== undefined? attributes.showHeaders : true; + this.cells = attributes.cells || this.cells; + DatasetChoice.prototype.initialize.call( this, attributes ); + }, + + /** in this override, display the selected datasets as a table with optional headers */ + _renderSelected : function( json ){ + if( json.selected.length ){ + return $( _.template([ + '<table class="selected">', + '<% if( json.showHeaders ){ %>', + '<thead><tr>', + '<% _.map( json.cells, function( val, key ){ %>', + '<th><%= val %></th>', + '<% }); %>', + '</tr></thead>', + '<% } %>', + '<tbody>', + '<% _.map( json.selected, function( selected ){ %>', + '<tr>', + '<% _.map( json.cells, function( val, key ){ %>', + '<td class="cell-<%= key %>"><%= selected[ key ] %></td>', + '<% }) %>', + '</tr>', + '<% }); %>', + '</tbody>', + '</table>' + ].join( '' ), { json: json })); + } + return $([ + '<span class="none-selected-msg">(', + _l( 'click to select a dataset' ), + ')</span>' + ].join( '' )); + }, + + /** in this override, send the showHeaders and cells options as well */ + toJSON : function(){ + return _.extend( DatasetChoice.prototype.toJSON.call( this ), { + showHeaders : this.showHeaders, + cells : this.cells + }); + }, + + /** in this override, set multiselect to true */ + _getModalOptions : function(){ + return _.extend( DatasetChoice.prototype._getModalOptions.call( this ), { + multiselect : true + }); + }, + + // ------------------------------------------------------------------------ misc + /** string rep */ + toString : function(){ + return 'DatasetChoice(' + this.selected + ')'; + } +}); + + +// ============================================================================ + return { + DatasetChoiceModal : DatasetChoiceModal, + DatasetChoice : DatasetChoice, + MultiDatasetChoice : MultiDatasetChoice + }; +}); diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/scripts/mvc/dataset/dataset-li.js --- a/static/scripts/mvc/dataset/dataset-li.js +++ b/static/scripts/mvc/dataset/dataset-li.js @@ -42,14 +42,14 @@ /** event listeners */ _setUpListeners : function(){ //TODO:?? may want to move this to ListItemView (although this is only needed in the *narrow* panel views (current)) - // hide the primary actions in the title bar when selectable + // hide the primary actions in the title bar when selectable and narrow this.on( 'selectable', function( isSelectable ){ if( isSelectable ){ this.$( '.primary-actions' ).hide(); } else { this.$( '.primary-actions' ).show(); } - }); + }, this ); // re-rendering on any model changes this.model.on( 'change', function( model, options ){ diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/scripts/mvc/dataset/dataset-list.js --- /dev/null +++ b/static/scripts/mvc/dataset/dataset-list.js @@ -0,0 +1,45 @@ +define([ + "mvc/dataset/list-panel", + "mvc/dataset/dataset-li", + "mvc/base-mvc", + "utils/localization" +], function( LIST_PANEL, DATASET_LI, BASE_MVC, _l ){ +/* ============================================================================= +TODO: + +============================================================================= */ +var _super = LIST_PANEL.ListPanel; +/** @class non-editable, read-only View/Controller for a list of datasets. + */ +var DatasetList = _super.extend( +/** @lends DatasetList.prototype */{ + + /** logger used to record this.log messages, commonly set to console */ + //logger : console, + + /** class to use for constructing the sub-views */ + viewClass : DATASET_LI.DatasetListItemView, + className : _super.prototype.className + ' dataset-list', + + /** string to no hdas match the search terms */ + noneFoundMsg : _l( 'No matching datasets found' ), + + // ......................................................................... SET UP + /** Set up the view, set up storage, bind listeners to HistoryContents events + * @param {Object} attributes optional settings for the panel + */ + initialize : function( attributes ){ + _super.prototype.initialize.call( this, attributes ); + }, + + /** Return a string rep of the history */ + toString : function(){ + return 'DatasetList(' + this.collection + ')'; + } +}); + +//============================================================================== + return { + DatasetList : DatasetList + }; +}); diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/scripts/mvc/dataset/dataset-model.js --- a/static/scripts/mvc/dataset/dataset-model.js +++ b/static/scripts/mvc/dataset/dataset-model.js @@ -75,7 +75,7 @@ 'meta_download' : 'dataset/get_metadata_file?hda_id=' + id + '&metadata_name=' }; //TODO: global - var root = ( galaxy_config && galaxy_config.root )?( galaxy_config.root ):( '/' ); + var root = ( window.galaxy_config && galaxy_config.root )?( galaxy_config.root ):( '/' ); _.each( urls, function( value, key ){ urls[ key ] = root + value; }); @@ -229,7 +229,210 @@ //============================================================================== +/** @class Backbone collection for dataset associations. + */ +var DatasetAssociationCollection = Backbone.Collection.extend( BASE_MVC.LoggableMixin ).extend( +/** @lends HistoryContents.prototype */{ + model : DatasetAssociation, + + /** logger used to record this.log messages, commonly set to console */ + //logger : console, + + /** root api url */ + urlRoot : (( window.galaxy_config && galaxy_config.root )?( galaxy_config.root ):( '/' )) + + 'api/datasets', + + // ........................................................................ common queries + /** Get the ids of every item in this collection + * @returns array of encoded ids + */ + ids : function(){ + return this.map( function( item ){ return item.get('id'); }); + }, + + /** Get contents that are not ready + * @returns array of content models + */ + notReady : function(){ + return this.filter( function( content ){ + return !content.inReadyState(); + }); + }, + +// /** Get the id of every model in this collection not in a 'ready' state (running). +// * @returns an array of model ids +// */ +// running : function(){ +// var idList = []; +// this.each( function( item ){ +// var isRunning = !item.inReadyState(); +// if( isRunning ){ +////TODO: is this still correct since type_id +// idList.push( item.get( 'id' ) ); +// } +// }); +// return idList; +// }, + + /** return true if any datasets don't have details */ + haveDetails : function(){ + return this.all( function( dataset ){ return dataset.hasDetails(); }); + }, + + // ........................................................................ ajax + ///** fetch detailed model data for all datasets in this collection */ + //fetchAllDetails : function( options ){ + // options = options || {}; + // var detailsFlag = { details: 'all' }; + // options.data = ( options.data )?( _.extend( options.data, detailsFlag ) ):( detailsFlag ); + // return this.fetch( options ); + //}, + + /** using a queue, perform ajaxFn on each of the models in this collection */ + ajaxQueue : function( ajaxFn, options ){ + var deferred = jQuery.Deferred(), + startingLength = this.length, + responses = []; + + if( !startingLength ){ + deferred.resolve([]); + return deferred; + } + + // use reverse order (stylistic choice) + var ajaxFns = this.chain().reverse().map( function( dataset, i ){ + return function(){ + var xhr = ajaxFn.call( dataset, options ); + // if successful, notify using the deferred to allow tracking progress + xhr.done( function( response ){ + deferred.notify({ curr: i, total: startingLength, response: response, model: dataset }); + }); + // (regardless of previous error or success) if not last ajax call, shift and call the next + // if last fn, resolve deferred + xhr.always( function( response ){ + responses.push( response ); + if( ajaxFns.length ){ + ajaxFns.shift()(); + } else { + deferred.resolve( responses ); + } + }); + }; + }).value(); + // start the queue + ajaxFns.shift()(); + + return deferred; + }, + + // ........................................................................ sorting/filtering + /** return a new collection of datasets whose attributes contain the substring matchesWhat */ + matches : function( matchesWhat ){ + return this.filter( function( dataset ){ + return dataset.matches( matchesWhat ); + }); + }, + + // ........................................................................ misc + /** override to get a correct/smarter merge when incoming data is partial */ + set : function( models, options ){ + // arrrrrrrrrrrrrrrrrg... + // (e.g. stupid backbone) + // w/o this partial models from the server will fill in missing data with model defaults + // and overwrite existing data on the client + // see Backbone.Collection.set and _prepareModel + var collection = this; + models = _.map( models, function( model ){ + if( !collection.get( model.id ) ){ return model; } + + // merge the models _BEFORE_ calling the superclass version + var merged = existing.toJSON(); + _.extend( merged, model ); + return merged; + }); + // now call superclass when the data is filled + Backbone.Collection.prototype.set.call( this, models, options ); + }, + +// /** Convert this ad-hoc collection of hdas to a formal collection tracked +// by the server. +// **/ +// promoteToHistoryDatasetCollection : function _promote( history, collection_type, options ){ +////TODO: seems like this would be better in mvc/collections +// options = options || {}; +// options.url = this.url(); +// options.type = "POST"; +// var full_collection_type = collection_type; +// var element_identifiers = [], +// name = null; +// +// // This mechanism is rough - no error handling, allows invalid selections, no way +// // for user to pick/override element identifiers. This is only really meant +// if( collection_type === "list" ) { +// this.chain().each( function( hda ) { +// // TODO: Handle duplicate names. +// var name = hda.attributes.name; +// var id = hda.get('id'); +// var content_type = hda.attributes.history_content_type; +// if( content_type === "dataset" ) { +// if( full_collection_type !== "list" ) { +// this.log( "Invalid collection type" ); +// } +// element_identifiers.push( { name: name, src: "hda", id: id } ); +// } else { +// if( full_collection_type === "list" ) { +// full_collection_type = "list:" + hda.attributes.collection_type; +// } else { +// if( full_collection_type !== "list:" + hda.attributes.collection_type ) { +// this.log( "Invalid collection type" ); +// } +// } +// element_identifiers.push( { name: name, src: "hdca", id: id } ); +// } +// }); +// name = "New Dataset List"; +// } else if( collection_type === "paired" ) { +// var ids = this.ids(); +// if( ids.length !== 2 ){ +// // TODO: Do something... +// } +// element_identifiers.push( { name: "forward", src: "hda", id: ids[ 0 ] } ); +// element_identifiers.push( { name: "reverse", src: "hda", id: ids[ 1 ] } ); +// name = "New Dataset Pair"; +// } +// options.data = { +// type: "dataset_collection", +// name: name, +// collection_type: full_collection_type, +// element_identifiers: JSON.stringify( element_identifiers ) +// }; +// +// var xhr = jQuery.ajax( options ); +// xhr.done( function( message, status, responseObj ){ +// history.refresh( ); +// }); +// xhr.fail( function( xhr, status, message ){ +// if( xhr.responseJSON && xhr.responseJSON.error ){ +// error = xhr.responseJSON.error; +// } else { +// error = xhr.responseJSON; +// } +// xhr.responseText = error; +// // Do something? +// }); +// return xhr; +// }, + + /** String representation. */ + toString : function(){ + return ([ 'DatasetAssociationCollection(', this.length, ')' ].join( '' )); + } +}); + + +//============================================================================== return { - DatasetAssociation : DatasetAssociation + DatasetAssociation : DatasetAssociation, + DatasetAssociationCollection : DatasetAssociationCollection }; }); diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/scripts/mvc/dataset/list-panel.js --- /dev/null +++ b/static/scripts/mvc/dataset/list-panel.js @@ -0,0 +1,687 @@ +define([ + "mvc/base-mvc", + "utils/localization" +], function( BASE_MVC, _l ){ +/* ============================================================================= +TODO: + +============================================================================= */ +/** @class List that contains ListItemViews. + */ +var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend( +/** @lends ReadOnlyHistoryPanel.prototype */{ + + /** logger used to record this.log messages, commonly set to console */ + //logger : console, + + /** class to use for constructing the sub-views */ + viewClass : BASE_MVC.ListItemView, + + tagName : 'div', + className : 'list-panel', + + /** (in ms) that jquery effects will use */ + fxSpeed : 'fast', + + /** string to display when the model has no hdas */ + emptyMsg : _l( 'This list is empty' ), + /** string to no hdas match the search terms */ + noneFoundMsg : _l( 'No matching items found' ), + + // ......................................................................... SET UP + /** Set up the view, set up storage, bind listeners to HistoryContents events + * @param {Object} attributes optional settings for the list + */ + initialize : function( attributes, options ){ + attributes = attributes || {}; + // set the logger if requested + if( attributes.logger ){ + this.logger = attributes.logger; + } + this.log( this + '.initialize:', attributes ); + + // ---- instance vars + /** how quickly should jquery fx run? */ + this.fxSpeed = _.has( attributes, 'fxSpeed' )?( attributes.fxSpeed ):( this.fxSpeed ); + + /** filters for displaying subviews */ + this.filters = []; + /** current search terms */ + this.searchFor = attributes.searchFor || ''; + + /** loading indicator */ + this.indicator = new LoadingIndicator( this.$el ); + + /** currently showing selectors on items? */ + this.selecting = ( attributes.selecting !== undefined )? attributes.selecting : true; + //this.selecting = false; + + /** cached selected item.model.ids to persist btwn renders */ + this.selected = attributes.selected || []; + /** the last selected item.model.id */ + this.lastSelected = null; + + /** list item view class (when passed models) */ + this.viewClass = attributes.viewClass || this.viewClass; + + /** list item views */ + this.views = []; + /** list item models */ + this.collection = attributes.collection || ( new Backbone.Collection([]) ); + + /** filter fns run over collection items to see if they should show in the list */ + this.filters = attributes.filters || []; + +//TODO: remove + this.title = attributes.title || ''; + this.subtitle = attributes.subtitle || ''; + + this._setUpListeners(); + }, + + /** create any event listeners for the list + */ + _setUpListeners : function(){ + this.on( 'error', function( model, xhr, options, msg, details ){ + //this.errorHandler( model, xhr, options, msg, details ); + console.error( model, xhr, options, msg, details ); + }, this ); + + // show hide the loading indicator + this.on( 'loading', function(){ + this._showLoadingIndicator( 'loading...', 40 ); + }, this ); + this.on( 'loading-done', function(){ + this._hideLoadingIndicator( 40 ); + }, this ); + + // throw the first render up as a diff namespace using once (for outside consumption) + this.once( 'rendered', function(){ + this.trigger( 'rendered:initial', this ); + }, this ); + + // debugging + if( this.logger ){ + this.on( 'all', function( event ){ + this.log( this + '', arguments ); + }, this ); + } + + this._setUpCollectionListeners(); + this._setUpViewListeners(); + 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 */ + _setUpCollectionListeners : function(){ + + this.collection.on( 'reset', function(){ + this.renderItems(); + }, this ); + + this.collection.on( 'add', this.addItemView, this ); + this.collection.on( 'remove', this.removeItemView, this ); + + // debugging + if( this.logger ){ + this.collection.on( 'all', function( event ){ + this.info( this + '(collection)', arguments ); + }, this ); + } + return this; + }, + + /** listening for history and HDA events */ + _setUpViewListeners : function(){ + + // shift to select a range + this.on( 'view:selected', function( view, ev ){ + if( ev && ev.shiftKey && this.lastSelected ){ + var lastSelectedView = _.find( this.views, function( view ){ + return view.model.id === this.lastSelected; + }); + if( lastSelectedView ){ + this.selectRange( view, lastSelectedView ); + } + } + this.selected.push( view.model.id ); + this.lastSelected = view.model.id; + }, this ); + }, + + // ------------------------------------------------------------------------ rendering + /** 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. + */ + _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._renderTitle( $newRender ); + this._renderSubtitle( $newRender ); + this._renderSearch( $newRender ); + this.renderItems( $newRender ); + return $newRender; + }, + + /** + */ + _renderTitle : function( $where ){ + //$where = $where || this.$el; + //$where.find( '.title' ).replaceWith( ... ) + }, + + /** + */ + _renderSubtitle : function( $where ){ + //$where = $where || this.$el; + //$where.find( '.title' ).replaceWith( ... ) + }, + + /** 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 ){ + view.trigger( 'rendered', view ); + next(); + } + ]); + }, + + /** empty out the current el, move the $newRender's children in */ + _swapNewRender : function( $newRender ){ + this.$el.empty().attr( 'class', this.className ).append( $newRender.children() ); + if( this.selecting ){ this.showSelectors( 0 ); } + return this; + }, + + /** */ + _setUpBehaviors : function( $where ){ + $where = $where || this.$el; + $where.find( '.controls [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 */ + $scrollContainer : function(){ + // override + return this.$el.parent().parent(); + }, + /** */ + $list : function( $where ){ + return ( $where || this.$el ).find( '.list-items' ); + }, + /** container where list messages are attached */ + $messages : function( $where ){ + return ( $where || this.$el ).find( '.message-container' ); + }, + /** the message displayed when no views can be shown (no views, none matching search) */ + $emptyMessage : function( $where ){ + return ( $where || this.$el ).find( '.empty-message' ); + }, + + // ------------------------------------------------------------------------ hda sub-views + /** + * @param {jQuery} $whereTo what dom element to prepend the HDA views to + * @returns the visible item views + */ + renderItems : function( $whereTo ){ + $whereTo = $whereTo || this.$el; + var list = this, + newViews = []; + + var $list = this.$list( $whereTo ), + item$els = this._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; + }); + this.debug( item$els ); + this.debug( newViews ); + + $list.empty(); + if( item$els.length ){ + $list.append( item$els ); + this.$emptyMessage( $whereTo ).hide(); + + } else { + this._renderEmptyMessage( $whereTo ).show(); + } + + this.views = newViews; + return newViews; + }, + + /** + */ + _filterCollection : function(){ + // override this + var list = this; + return list.collection.filter( _.bind( list._filterItem, list ) ); + }, + + /** + */ + _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 ) ); + }, + + /** + */ + _createItemView : function( model ){ + var ViewClass = this._getItemViewClass( model ), + options = _.extend( this._getItemViewOptions( model ), { + model : model + }), + view = new ViewClass( options ); + this._setUpItemViewListeners( view ); + return view; + }, + + _getItemViewClass : function( model ){ + // override this + return this.viewClass; + }, + + _getItemViewOptions : function( model ){ + // override this + return { + //logger : this.logger, + fxSpeed : this.fxSpeed, + expanded : false, + selectable : this.selecting, + selected : _.contains( this.selected, model.id ), + draggable : this.dragging + }; + }, + + /** + */ + _setUpItemViewListeners : function( view ){ + var list = this; + view.on( 'all', function(){ + var args = Array.prototype.slice.call( arguments, 0 ); + args[0] = 'view:' + args[0]; + list.trigger.apply( list, args ); + }); + + // debugging + //if( this.logger ){ + // view.on( 'all', function( event ){ + // this.log( this + '(view)', arguments ); + // }, this ); + //} + return this; + }, + + /** render the empty/none-found message */ + _renderEmptyMessage : function( $whereTo ){ + //this.debug( '_renderEmptyMessage', $whereTo, this.searchFor ); + var text = this.searchFor? this.noneFoundMsg : this.emptyMsg; + return this.$emptyMessage( $whereTo ).text( text ); + }, + + /** collapse all item views */ + expandAll : function(){ + _.each( this.views, function( view ){ + view.expand(); + }); + }, + + /** collapse all item views */ + collapseAll : function(){ + _.each( this.views, function( view ){ + view.collapse(); + }); + }, + + // ------------------------------------------------------------------------ collection/views syncing + /** + */ + addItemView : function( model, collection, options ){ + this.log( this + '.addItemView:', model ); + var list = this; + if( !this._filterItem( model ) ){ return undefined; } + +//TODO: sorted? position? + var view = list._createItemView( model ); + this.views.push( view ); + + $( view ).queue( 'fx', [ + function( next ){ list.$emptyMessage().fadeOut( list.fxSpeed, next ); }, + function( next ){ +//TODO: auto render? + list.$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 ); + if( !view ){ return undefined; } + + this.views = _.without( this.views, view ); + view.remove(); + if( !this.views.length ){ + list._renderEmptyMessage().fadeIn( list.fxSpeed ); + } + return view; + }, + + /** get views based on model properties + */ + viewFromModel : function( model ){ + for( var i=0; i<this.views.length; i++ ){ + var view = this.views[i]; + if( view.model === model ){ + return view; + } + } + return undefined; + }, + + /** get views based on model properties + */ + viewsWhereModel : function( properties ){ + return this.views.filter( function( view ){ + //return view.model.matches( properties ); +//TODO: replace with _.matches (underscore 1.6.0) + var json = view.model.toJSON(); + //console.debug( '\t', json, properties ); + for( var key in properties ){ + if( properties.hasOwnPropery( key ) ){ + //console.debug( '\t\t', json[ key ], view.model.properties[ key ] ); + if( json[ key ] !== view.model.properties[ key ] ){ + return false; + } + } + } + return true; + }); + }, + + /** + */ + viewRange : function( viewA, viewB ){ + if( viewA === viewB ){ return ( viewA )?( [ viewA ] ):( [] ); } + + var indexA = this.views.indexOf( viewA ), + indexB = this.views.indexOf( viewB ); + + // handle not found + if( indexA === -1 || indexB === -1 ){ + if( indexA === indexB ){ return []; } + return ( indexA === -1 )?( [ viewB ] ):( [ viewA ] ); + } + // reverse if indeces are + //note: end inclusive + return ( indexA < indexB )? + this.views.slice( indexA, indexB + 1 ) : + this.views.slice( indexB, indexA + 1 ); + }, + + // ------------------------------------------------------------------------ searching + /** render a search input for filtering datasets shown + * (see the search section in the HDA model for implementation of the actual searching) + * return will start the search + * esc will clear the search + * clicking the clear button will clear the search + * uses searchInput in ui.js + */ + _renderSearch : function( $where ){ + $where.find( '.controls .search-input' ).searchInput({ + placeholder : 'search', + initialVal : this.searchFor, + onfirstsearch : _.bind( this._firstSearch, this ), + onsearch : _.bind( this.searchItems, this ), + onclear : _.bind( this.clearSearch, this ) + }); + return $where; + }, + + _firstSearch : function( searchFor ){ + this.log( 'onFirstSearch', searchFor ); + return this.searchItems( searchFor ); + }, + + /** filter view list to those that contain the searchFor terms */ + searchItems : function( searchFor ){ + this.searchFor = searchFor; + this.trigger( 'search:searching', searchFor, this ); + this.renderItems(); + return this; + }, + + /** clear the search filters and show all views that are normally shown */ + clearSearch : function( searchFor ){ + //this.log( 'onSearchClear', this ); + this.searchFor = ''; + this.trigger( 'search:clear', this ); + this.renderItems(); + return this; + }, + + // ------------------------------------------------------------------------ selection + /** show selectors on all visible hdas and associated controls */ + showSelectors : function( speed ){ + speed = ( speed !== undefined )?( speed ):( this.fxSpeed ); + this.selecting = true; + this.$( '.list-actions' ).slideDown( speed ); + _.each( this.views, function( view ){ + view.showSelector( speed ); + }); + this.selected = []; + this.lastSelected = null; + }, + + /** hide selectors on all visible hdas and associated controls */ + hideSelectors : function( speed ){ + speed = ( speed !== undefined )?( speed ):( this.fxSpeed ); + this.selecting = false; + this.$( '.list-actions' ).slideUp( speed ); + _.each( this.views, function( view ){ + view.hideSelector( speed ); + }); + this.selected = []; + this.lastSelected = 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 */ + selectAll : function( event ){ + _.each( this.views, function( view ){ + view.select( event ); + }); + }, + + /** deselect all visible hdas */ + deselectAll : function( event ){ + this.lastSelected = null; + _.each( this.views, function( view ){ + view.deselect( event ); + }); + }, + + /** select a range of datasets between A and B */ + selectRange : function( viewA, viewB ){ + var range = this.viewRange( viewA, viewB ); + _.each( range, function( view ){ + view.select(); + }); + return range; + }, + + /** return an array of all currently selected hdas */ + getSelectedViews : function(){ + return _.filter( this.views, function( v ){ + return v.selected; + }); + }, + + /** return an collection of the models of all currenly selected hdas */ + getSelectedModels : function(){ + return new this.collection.constructor( _.map( this.getSelectedViews(), function( view ){ + return view.model; + })); + }, + + // ------------------------------------------------------------------------ loading indicator +//TODO: questionable + /** hide the $el and display a loading indicator (in the $el's parent) when loading new data */ + _showLoadingIndicator : function( msg, speed, callback ){ + speed = ( speed !== undefined )?( speed ):( this.fxSpeed ); + if( !this.indicator ){ + this.indicator = new LoadingIndicator( this.$el, this.$el.parent() ); + } + if( !this.$el.is( ':visible' ) ){ + this.indicator.show( 0, callback ); + } else { + this.$el.fadeOut( speed ); + this.indicator.show( msg, speed, callback ); + } + }, + + /** hide the loading indicator */ + _hideLoadingIndicator : function( speed, callback ){ + speed = ( speed !== undefined )?( speed ):( this.fxSpeed ); + if( this.indicator ){ + this.indicator.hide( speed, callback ); + } + }, + + // ------------------------------------------------------------------------ scrolling + /** get the current scroll position of the panel in its parent */ + scrollPosition : function(){ + return this.$scrollContainer().scrollTop(); + }, + + /** set the current scroll position of the panel in its parent */ + scrollTo : function( pos ){ + this.$scrollContainer().scrollTop( pos ); + return this; + }, + + /** Scrolls the panel to the top. */ + scrollToTop : function(){ + this.$scrollContainer().scrollTop( 0 ); + return this; + }, + + /** */ + scrollToItem : function( view ){ + if( !view ){ return; } + var itemTop = view.$el.offset().top; + this.$scrollContainer().scrollTop( itemTop ); + }, + + // ------------------------------------------------------------------------ panel events + /** event map */ + events : { + 'click .select-all' : 'selectAll', + 'click .deselect-all' : 'deselectAll' + }, + + // ------------------------------------------------------------------------ misc + /** Return a string rep of the history */ + toString : function(){ + return 'ListPanel(' + this.collection + ')'; + } +}); + +// ............................................................................ TEMPLATES +/** underscore templates */ +ListPanel.prototype.templates = (function(){ +//TODO: move to require text! plugin + + 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="list-items"></div>', + '<div class="empty-message infomessagesmall"></div>', + '</div>' + ]); + + return { + el : elTemplate + }; +}()); + + + +//============================================================================== + return { + ListPanel: ListPanel + }; +}); diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/scripts/mvc/ui.js --- a/static/scripts/mvc/ui.js +++ b/static/scripts/mvc/ui.js @@ -610,6 +610,7 @@ * 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; } // contructor function searchInput( parentNode, options ){ @@ -670,6 +671,11 @@ }) // attach behaviors to esc, return if desired, search on some min len string .keyup( function( event ){ + event.preventDefault(); + event.stopPropagation(); +//TODO: doesn't work + if( !$( this ).val() ){ $( this ).blur(); } + // esc key will clear if desired if( event.which === KEYCODE_ESC && options.escWillClear ){ clearSearchInput.call( this, event ); diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/scripts/packed/mvc/base-mvc.js --- a/static/scripts/packed/mvc/base-mvc.js +++ b/static/scripts/packed/mvc/base-mvc.js @@ -1,1 +1,1 @@ -define(["utils/add-logging"],function(i){var j={logger:null,_logNamespace:"?",log:function(){if(this.logger){var l=this.logger.log;if(typeof this.logger.log==="object"){l=Function.prototype.bind.call(this.logger.log,this.logger)}return l.apply(this.logger,arguments)}return undefined}};i(j);var a=Backbone.Model.extend({initialize:function(m){this._checkEnabledSessionStorage();if(!m.id){throw new Error("SessionStorageModel requires an id in the initial attributes")}this.id=m.id;var l=(!this.isNew())?(this._read(this)):({});this.clear({silent:true});this.save(_.extend({},this.defaults,l,m),{silent:true});this.on("change",function(){this.save()})},_checkEnabledSessionStorage:function(){try{return sessionStorage.length}catch(l){alert("Please enable cookies in your browser for this Galaxy site");return false}},sync:function(o,m,l){if(!l.silent){m.trigger("request",m,{},l)}var n;switch(o){case"create":n=this._create(m);break;case"read":n=this._read(m);break;case"update":n=this._update(m);break;case"delete":n=this._delete(m);break}if(n!==undefined||n!==null){if(l.success){l.success()}}else{if(l.error){l.error()}}return n},_create:function(l){var m=l.toJSON(),n=sessionStorage.setItem(l.id,JSON.stringify(m));return(n===null)?(n):(m)},_read:function(l){return JSON.parse(sessionStorage.getItem(l.id))},_update:function(l){return l._create(l)},_delete:function(l){return sessionStorage.removeItem(l.id)},isNew:function(){return !sessionStorage.hasOwnProperty(this.id)},_log:function(){return JSON.stringify(this.toJSON(),null," ")},toString:function(){return"SessionStorageModel("+this.id+")"}});(function(){a.prototype=_.omit(a.prototype,"url","urlRoot")}());var g={searchAttributes:[],searchAliases:{},searchAttribute:function(n,l){var m=this.get(n);if(!l||(m===undefined||m===null)){return false}if(_.isArray(m)){return this._searchArrayAttribute(m,l)}return(m.toString().toLowerCase().indexOf(l.toLowerCase())!==-1)},_searchArrayAttribute:function(m,l){l=l.toLowerCase();return _.any(m,function(n){return(n.toString().toLowerCase().indexOf(l.toLowerCase())!==-1)})},search:function(l){var m=this;return _.filter(this.searchAttributes,function(n){return m.searchAttribute(n,l)})},matches:function(m){var o="=",l=m.split(o);if(l.length>=2){var n=l[0];n=this.searchAliases[n]||n;return this.searchAttribute(n,l[1])}return !!this.search(m).length},matchesAll:function(m){var l=this;m=m.match(/(".*"|\w*=".*"|\S*)/g).filter(function(n){return !!n});return _.all(m,function(n){n=n.replace(/"/g,"");return l.matches(n)})}};var c={hiddenUntilActivated:function(l,n){n=n||{};this.HUAVOptions={$elementShown:this.$el,showFn:jQuery.prototype.toggle,showSpeed:"fast"};_.extend(this.HUAVOptions,n||{});this.HUAVOptions.hasBeenShown=this.HUAVOptions.$elementShown.is(":visible");this.hidden=this.isHidden();if(l){var m=this;l.on("click",function(o){m.toggle(m.HUAVOptions.showSpeed)})}},isHidden:function(){return(this.HUAVOptions.$elementShown.is(":hidden"))},toggle:function(){if(this.hidden){if(!this.HUAVOptions.hasBeenShown){if(_.isFunction(this.HUAVOptions.onshowFirstTime)){this.HUAVOptions.hasBeenShown=true;this.HUAVOptions.onshowFirstTime.call(this)}}if(_.isFunction(this.HUAVOptions.onshow)){this.HUAVOptions.onshow.call(this);this.trigger("hiddenUntilActivated:shown",this)}this.hidden=false}else{if(_.isFunction(this.HUAVOptions.onhide)){this.HUAVOptions.onhide.call(this);this.trigger("hiddenUntilActivated:hidden",this)}this.hidden=true}return this.HUAVOptions.showFn.apply(this.HUAVOptions.$elementShown,arguments)}};function k(o,n){var l=Array.prototype.slice.call(arguments,0),m=l.pop();l.unshift(m);return _.defaults.apply(_,l)}function e(m,l){l=l||"model";var n=_.template(m.join(""));return function(p,o){var q={view:o||{},_l:_l};q[l]=p||{};return n(q)}}var b=Backbone.View.extend(j).extend({initialize:function(l){this.expanded=l.expanded||false},fxSpeed:"fast",render:function(m){var l=this._buildNewRender();this._setUpBehaviors(l);this._queueNewRender(l,m);return this},_buildNewRender:function(){var l=$(this.templates.el(this.model.toJSON(),this));if(this.expanded){this.$details(l).replaceWith(this._renderDetails().show())}return l},_queueNewRender:function(m,n){n=(n===undefined)?(this.fxSpeed):(n);var l=this;$(l).queue("fx",[function(o){this.$el.fadeOut(n,o)},function(o){l._swapNewRender(m);o()},function(o){this.$el.fadeIn(n,o)},function(o){this.trigger("rendered",l);o()}])},_swapNewRender:function(l){return this.$el.empty().attr("class",this.className).append(l.children())},_setUpBehaviors:function(l){l=l||this.$el;make_popup_menus(l);l.find("[title]").tooltip({placement:"bottom"})},$details:function(l){l=l||this.$el;return l.find(".details")},_renderDetails:function(){var l=$(this.templates.details(this.model.toJSON(),this));this._setUpBehaviors(l);return l},toggleExpanded:function(l){l=(l===undefined)?(!this.expanded):(l);if(l){this.expand()}else{this.collapse()}return this},expand:function(){var l=this;return l._fetchModelDetails().always(function(){var m=l._renderDetails();l.$details().replaceWith(m);l.expanded=true;m.slideDown(l.fxSpeed,function(){l.trigger("expanded",l)})})},_fetchModelDetails:function(){if(!this.model.hasDetails()){return this.model.fetch()}return jQuery.when()},collapse:function(){var l=this;l.expanded=false;this.$details().slideUp(l.fxSpeed,function(){l.trigger("collapsed",l)})}});var f={initialize:function(l){this.draggable=l.draggable||false},$dragHandle:function(){return this.$(".title-bar")},toggleDraggable:function(){if(this.draggable){this.draggableOff()}else{this.draggableOn()}},draggableOn:function(){this.draggable=true;this.dragStartHandler=_.bind(this._dragStartHandler,this);this.dragEndHandler=_.bind(this._dragEndHandler,this);var l=this.$dragHandle().attr("draggable",true).get(0);l.addEventListener("dragstart",this.dragStartHandler,false);l.addEventListener("dragend",this.dragEndHandler,false)},draggableOff:function(){this.draggable=false;var l=this.$dragHandle().attr("draggable",false).get(0);l.removeEventListener("dragstart",this.dragStartHandler,false);l.removeEventListener("dragend",this.dragEndHandler,false)},_dragStartHandler:function(l){this.trigger("dragstart",this);l.dataTransfer.effectAllowed="move";l.dataTransfer.setData("text",JSON.stringify(this.model.toJSON()));return false},_dragEndHandler:function(l){this.trigger("dragend",this);return false}};var d={initialize:function(l){this.selectable=l.selectable||false;this.selected=l.selected||false},$selector:function(){return this.$(".selector")},_renderSelected:function(){this.$selector().find("span").toggleClass("fa-check-square-o",this.selected).toggleClass("fa-square-o",!this.selected)},toggleSelector:function(){if(!this.$selector().is(":visible")){this.showSelector()}else{this.hideSelector()}},showSelector:function(l){l=l!==undefined?l:this.fxSpeed;this.selectable=true;this.trigger("selectable",true,this);this._renderSelected();this.$selector().show(l)},hideSelector:function(l){l=l!==undefined?l:this.fxSpeed;this.selectable=false;this.trigger("selectable",false,this);this.$selector().hide(l)},toggleSelect:function(l){if(this.selected){this.deselect(l)}else{this.select(l)}},select:function(l){if(!this.selected){this.trigger("selected",this,l);this.selected=true;this._renderSelected()}return false},deselect:function(l){if(this.selected){this.trigger("de-selected",this,l);this.selected=false;this._renderSelected()}return false}};var h=b.extend(k(d,f,{tagName:"div",className:"list-item",initialize:function(l){b.prototype.initialize.call(this,l);d.initialize.call(this,l);f.initialize.call(this,l)},_buildNewRender:function(){var l=b.prototype._buildNewRender.call(this);l.find(".warnings").replaceWith(this._renderWarnings());l.find(".title-bar").replaceWith(this._renderTitleBar());l.find(".primary-actions").append(this._renderPrimaryActions());l.find(".subtitle").replaceWith(this._renderSubtitle());return l},_swapNewRender:function(l){b.prototype._swapNewRender.call(this,l);if(this.selectable){this.showSelector(0)}if(this.draggable){this.draggableOn()}return this.$el},_renderWarnings:function(){var l=this,n=$('<div class="warnings"></div>'),m=l.model.toJSON();_.each(l.templates.warnings,function(o){n.append($(o(m,l)))});return n},_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(l){l.stopPropagation();this.toggleExpanded()},_keyDownTitleBar:function(n){var l=32,m=13;if(n&&(n.type==="keydown")&&(n.keyCode===l||n.keyCode===m)){this.toggleExpanded();n.stopPropagation();return false}return true},toString:function(){var l=(this.model)?(this.model+""):("(no model)");return"ListItemView("+l+")"}}));h.prototype.templates=(function(){var n=e(['<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 l={};var o=e(['<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 p=e(['<div class="subtitle"></div>']);var m=e(['<div class="details"></div>']);return{el:n,warnings:l,titleBar:o,subtitle:p,details:m}}());return{LoggableMixin:j,SessionStorageModel:a,SearchableModelMixin:g,HiddenUntilActivatedViewMixin:c,mixin:k,wrapTemplate:e,ExpandableView:b,DraggableViewMixin:f,SelectableViewMixin:d,ListItemView:h}}); \ No newline at end of file +define(["utils/add-logging","utils/localization"],function(j,b){var k={logger:null,_logNamespace:"?",log:function(){if(this.logger){var m=this.logger.log;if(typeof this.logger.log==="object"){m=Function.prototype.bind.call(this.logger.log,this.logger)}return m.apply(this.logger,arguments)}return undefined}};j(k);var a=Backbone.Model.extend({initialize:function(n){this._checkEnabledSessionStorage();if(!n.id){throw new Error("SessionStorageModel requires an id in the initial attributes")}this.id=n.id;var m=(!this.isNew())?(this._read(this)):({});this.clear({silent:true});this.save(_.extend({},this.defaults,m,n),{silent:true});this.on("change",function(){this.save()})},_checkEnabledSessionStorage:function(){try{return sessionStorage.length}catch(m){alert("Please enable cookies in your browser for this Galaxy site");return false}},sync:function(p,n,m){if(!m.silent){n.trigger("request",n,{},m)}var o;switch(p){case"create":o=this._create(n);break;case"read":o=this._read(n);break;case"update":o=this._update(n);break;case"delete":o=this._delete(n);break}if(o!==undefined||o!==null){if(m.success){m.success()}}else{if(m.error){m.error()}}return o},_create:function(m){var n=m.toJSON(),o=sessionStorage.setItem(m.id,JSON.stringify(n));return(o===null)?(o):(n)},_read:function(m){return JSON.parse(sessionStorage.getItem(m.id))},_update:function(m){return m._create(m)},_delete:function(m){return sessionStorage.removeItem(m.id)},isNew:function(){return !sessionStorage.hasOwnProperty(this.id)},_log:function(){return JSON.stringify(this.toJSON(),null," ")},toString:function(){return"SessionStorageModel("+this.id+")"}});(function(){a.prototype=_.omit(a.prototype,"url","urlRoot")}());var h={searchAttributes:[],searchAliases:{},searchAttribute:function(o,m){var n=this.get(o);if(!m||(n===undefined||n===null)){return false}if(_.isArray(n)){return this._searchArrayAttribute(n,m)}return(n.toString().toLowerCase().indexOf(m.toLowerCase())!==-1)},_searchArrayAttribute:function(n,m){m=m.toLowerCase();return _.any(n,function(o){return(o.toString().toLowerCase().indexOf(m.toLowerCase())!==-1)})},search:function(m){var n=this;return _.filter(this.searchAttributes,function(o){return n.searchAttribute(o,m)})},matches:function(n){var p="=",m=n.split(p);if(m.length>=2){var o=m[0];o=this.searchAliases[o]||o;return this.searchAttribute(o,m[1])}return !!this.search(n).length},matchesAll:function(n){var m=this;n=n.match(/(".*"|\w*=".*"|\S*)/g).filter(function(o){return !!o});return _.all(n,function(o){o=o.replace(/"/g,"");return m.matches(o)})}};var d={hiddenUntilActivated:function(m,o){o=o||{};this.HUAVOptions={$elementShown:this.$el,showFn:jQuery.prototype.toggle,showSpeed:"fast"};_.extend(this.HUAVOptions,o||{});this.HUAVOptions.hasBeenShown=this.HUAVOptions.$elementShown.is(":visible");this.hidden=this.isHidden();if(m){var n=this;m.on("click",function(p){n.toggle(n.HUAVOptions.showSpeed)})}},isHidden:function(){return(this.HUAVOptions.$elementShown.is(":hidden"))},toggle:function(){if(this.hidden){if(!this.HUAVOptions.hasBeenShown){if(_.isFunction(this.HUAVOptions.onshowFirstTime)){this.HUAVOptions.hasBeenShown=true;this.HUAVOptions.onshowFirstTime.call(this)}}if(_.isFunction(this.HUAVOptions.onshow)){this.HUAVOptions.onshow.call(this);this.trigger("hiddenUntilActivated:shown",this)}this.hidden=false}else{if(_.isFunction(this.HUAVOptions.onhide)){this.HUAVOptions.onhide.call(this);this.trigger("hiddenUntilActivated:hidden",this)}this.hidden=true}return this.HUAVOptions.showFn.apply(this.HUAVOptions.$elementShown,arguments)}};function l(p,o){var m=Array.prototype.slice.call(arguments,0),n=m.pop();m.unshift(n);return _.defaults.apply(_,m)}function f(n,m){m=m||"model";var o=_.template(n.join(""));return function(q,p){var r={view:p||{},_l:b};r[m]=q||{};return o(r)}}var c=Backbone.View.extend(k).extend({initialize:function(m){this.expanded=m.expanded||false;this.fxSpeed=m.fxSpeed||this.fxSpeed},fxSpeed:"fast",render:function(n){var m=this._buildNewRender();this._setUpBehaviors(m);this._queueNewRender(m,n);return this},_buildNewRender:function(){var m=$(this.templates.el(this.model.toJSON(),this));if(this.expanded){this.$details(m).replaceWith(this._renderDetails().show())}return m},_queueNewRender:function(n,o){o=(o===undefined)?(this.fxSpeed):(o);var m=this;$(m).queue("fx",[function(p){this.$el.fadeOut(o,p)},function(p){m._swapNewRender(n);p()},function(p){this.$el.fadeIn(o,p)},function(p){this.trigger("rendered",m);p()}])},_swapNewRender:function(m){return this.$el.empty().attr("class",this.className).append(m.children())},_setUpBehaviors:function(m){m=m||this.$el;m.find("[title]").tooltip({placement:"bottom"})},$details:function(m){m=m||this.$el;return m.find(".details")},_renderDetails:function(){var m=$(this.templates.details(this.model.toJSON(),this));this._setUpBehaviors(m);return m},toggleExpanded:function(m){m=(m===undefined)?(!this.expanded):(m);if(m){this.expand()}else{this.collapse()}return this},expand:function(){var m=this;return m._fetchModelDetails().always(function(){var n=m._renderDetails();m.$details().replaceWith(n);m.expanded=true;n.slideDown(m.fxSpeed,function(){m.trigger("expanded",m)})})},_fetchModelDetails:function(){if(!this.model.hasDetails()){return this.model.fetch()}return jQuery.when()},collapse:function(){var m=this;m.expanded=false;this.$details().slideUp(m.fxSpeed,function(){m.trigger("collapsed",m)})}});var g={initialize:function(m){this.draggable=m.draggable||false},$dragHandle:function(){return this.$(".title-bar")},toggleDraggable:function(){if(this.draggable){this.draggableOff()}else{this.draggableOn()}},draggableOn:function(){this.draggable=true;this.dragStartHandler=_.bind(this._dragStartHandler,this);this.dragEndHandler=_.bind(this._dragEndHandler,this);var m=this.$dragHandle().attr("draggable",true).get(0);m.addEventListener("dragstart",this.dragStartHandler,false);m.addEventListener("dragend",this.dragEndHandler,false)},draggableOff:function(){this.draggable=false;var m=this.$dragHandle().attr("draggable",false).get(0);m.removeEventListener("dragstart",this.dragStartHandler,false);m.removeEventListener("dragend",this.dragEndHandler,false)},_dragStartHandler:function(m){this.trigger("dragstart",this);m.dataTransfer.effectAllowed="move";m.dataTransfer.setData("text",JSON.stringify(this.model.toJSON()));return false},_dragEndHandler:function(m){this.trigger("dragend",this);return false}};var e={initialize:function(m){this.selectable=m.selectable||false;this.selected=m.selected||false},$selector:function(){return this.$(".selector")},_renderSelected:function(){this.$selector().find("span").toggleClass("fa-check-square-o",this.selected).toggleClass("fa-square-o",!this.selected)},toggleSelector:function(){if(!this.$selector().is(":visible")){this.showSelector()}else{this.hideSelector()}},showSelector:function(m){m=m!==undefined?m:this.fxSpeed;this.selectable=true;this.trigger("selectable",true,this);this._renderSelected();this.$selector().show(m)},hideSelector:function(m){m=m!==undefined?m:this.fxSpeed;this.selectable=false;this.trigger("selectable",false,this);this.$selector().hide(m)},toggleSelect:function(m){if(this.selected){this.deselect(m)}else{this.select(m)}},select:function(m){if(!this.selected){this.trigger("selected",this,m);this.selected=true;this._renderSelected()}return false},deselect:function(m){if(this.selected){this.trigger("de-selected",this,m);this.selected=false;this._renderSelected()}return false}};var i=c.extend(l(e,g,{tagName:"div",className:"list-item",initialize:function(m){c.prototype.initialize.call(this,m);e.initialize.call(this,m);g.initialize.call(this,m)},_buildNewRender:function(){var m=c.prototype._buildNewRender.call(this);m.find(".warnings").replaceWith(this._renderWarnings());m.find(".title-bar").replaceWith(this._renderTitleBar());m.find(".primary-actions").append(this._renderPrimaryActions());m.find(".subtitle").replaceWith(this._renderSubtitle());return m},_swapNewRender:function(m){c.prototype._swapNewRender.call(this,m);if(this.selectable){this.showSelector(0)}if(this.draggable){this.draggableOn()}return this.$el},_renderWarnings:function(){var m=this,o=$('<div class="warnings"></div>'),n=m.model.toJSON();_.each(m.templates.warnings,function(p){o.append($(p(n,m)))});return o},_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(m){m.stopPropagation();this.toggleExpanded()},_keyDownTitleBar:function(o){var m=32,n=13;if(o&&(o.type==="keydown")&&(o.keyCode===m||o.keyCode===n)){this.toggleExpanded();o.stopPropagation();return false}return true},toString:function(){var m=(this.model)?(this.model+""):("(no model)");return"ListItemView("+m+")"}}));i.prototype.templates=(function(){var o=f(['<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 m={};var p=f(['<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 q=f(['<div class="subtitle"></div>']);var n=f(['<div class="details"></div>']);return{el:o,warnings:m,titleBar:p,subtitle:q,details:n}}());return{LoggableMixin:k,SessionStorageModel:a,SearchableModelMixin:h,HiddenUntilActivatedViewMixin:d,mixin:l,wrapTemplate:f,ExpandableView:c,DraggableViewMixin:g,SelectableViewMixin:e,ListItemView:i}}); \ No newline at end of file diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/scripts/packed/mvc/dataset/dataset-li.js --- a/static/scripts/packed/mvc/dataset/dataset-li.js +++ b/static/scripts/packed/mvc/dataset/dataset-li.js @@ -1,1 +1,1 @@ -define(["mvc/dataset/states","mvc/base-mvc","utils/localization"],function(a,b,c){var e=b.ListItemView;var d=e.extend({className:e.prototype.className+" dataset",id:function(){return["dataset",this.model.get("id")].join("-")},initialize:function(f){if(f.logger){this.logger=this.model.logger=f.logger}this.log(this+".initialize:",f);e.prototype.initialize.call(this,f);this.linkTarget=f.linkTarget||"_blank";this._setUpListeners()},_setUpListeners:function(){this.on("selectable",function(f){if(f){this.$(".primary-actions").hide()}else{this.$(".primary-actions").show()}});this.model.on("change",function(g,f){if(this.model.changedAttributes().state&&this.model.inReadyState()&&this.expanded&&!this.model.hasDetails()){this.model.fetch()}else{this.render()}},this);this.on("all",function(f){this.log(f)},this)},_fetchModelDetails:function(){var f=this;if(f.model.inReadyState()&&!f.model.hasDetails()){return f.model.fetch({silent:true})}return jQuery.when()},remove:function(g,h){var f=this;g=g||this.fxSpeed;this.$el.fadeOut(g,function(){Backbone.View.prototype.remove.call(f);if(h){h.call(f)}})},render:function(f){return e.prototype.render.call(this,f)},_swapNewRender:function(f){e.prototype._swapNewRender.call(this,f);if(this.model.has("state")){this.$el.addClass("state-"+this.model.get("state"))}return this.$el},_renderPrimaryActions:function(){return[this._renderDisplayButton()]},_renderDisplayButton:function(){var h=this.model.get("state");if((h===a.NOT_VIEWABLE)||(h===a.DISCARDED)||(!this.model.get("accessible"))){return null}var g={target:this.linkTarget,classes:"display-btn"};if(this.model.get("purged")){g.disabled=true;g.title=c("Cannot display datasets removed from disk")}else{if(h===a.UPLOAD){g.disabled=true;g.title=c("This dataset must finish uploading before it can be viewed")}else{if(h===a.NEW){g.disabled=true;g.title=c("This dataset is not yet viewable")}else{g.title=c("View data");g.href=this.model.urls.display;var f=this;g.onclick=function(i){if(Galaxy.frame&&Galaxy.frame.active){Galaxy.frame.add({title:"Data Viewer: "+f.model.get("name"),type:"other",content:function(j){require(["mvc/data"],function(k){var l=new k.TabularDataset({id:f.model.get("id")});$.when(l.fetch()).then(function(){k.createTabularDatasetChunkedView({model:l,parent_elt:j,embedded:true,height:"100%"})})})}});i.preventDefault()}}}}}g.faIcon="fa-eye";return faIconButton(g)},_renderDetails:function(){if(this.model.get("state")===a.NOT_VIEWABLE){return $(this.templates.noAccess(this.model.toJSON(),this))}var f=e.prototype._renderDetails.call(this);f.find(".actions .left").empty().append(this._renderSecondaryActions());f.find(".summary").html(this._renderSummary()).prepend(this._renderDetailMessages());f.find(".display-applications").html(this._renderDisplayApplications());this._setUpBehaviors(f);return f},_renderSummary:function(){var f=this.model.toJSON(),g=this.templates.summaries[f.state];g=g||this.templates.summaries.unknown;return g(f,this)},_renderDetailMessages:function(){var f=this,h=$('<div class="detail-messages"></div>'),g=f.model.toJSON();_.each(f.templates.detailMessages,function(i){h.append($(i(g,f)))});return h},_renderDisplayApplications:function(){if(this.model.isDeletedOrPurged()){return""}return[this.templates.displayApplications(this.model.get("display_apps"),this),this.templates.displayApplications(this.model.get("display_types"),this)].join("")},_renderSecondaryActions:function(){this.debug("_renderSecondaryActions");switch(this.model.get("state")){case a.NOT_VIEWABLE:return[];case a.OK:case a.FAILED_METADATA:case a.ERROR:return[this._renderDownloadButton(),this._renderShowParamsButton()]}return[this._renderShowParamsButton()]},_renderShowParamsButton:function(){return faIconButton({title:c("View details"),classes:"params-btn",href:this.model.urls.show_params,target:this.linkTarget,faIcon:"fa-info-circle"})},_renderDownloadButton:function(){if(this.model.get("purged")||!this.model.hasData()){return null}if(!_.isEmpty(this.model.get("meta_files"))){return this._renderMetaFileDownloadButton()}return $(['<a class="download-btn icon-btn" href="',this.model.urls.download,'" title="'+c("Download")+'">','<span class="fa fa-floppy-o"></span>',"</a>"].join(""))},_renderMetaFileDownloadButton:function(){var f=this.model.urls;return $(['<div class="metafile-dropdown dropdown">','<a class="download-btn icon-btn" href="javascript:void(0)" data-toggle="dropdown"',' title="'+c("Download")+'">','<span class="fa fa-floppy-o"></span>',"</a>",'<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">','<li><a href="'+f.download+'">',c("Download dataset"),"</a></li>",_.map(this.model.get("meta_files"),function(g){return['<li><a href="',f.meta_download+g.file_type,'">',c("Download")," ",g.file_type,"</a></li>"].join("")}).join("\n"),"</ul>","</div>"].join("\n"))},toString:function(){var f=(this.model)?(this.model+""):("(no model)");return"DatasetListItemView("+f+")"}});d.prototype.templates=(function(){var h=_.extend({},e.prototype.templates.warnings,{failed_metadata:b.wrapTemplate(['<% if( model.state === "failed_metadata" ){ %>','<div class="warningmessagesmall">',c("An error occurred setting the metadata for this dataset"),"</div>","<% } %>"]),error:b.wrapTemplate(["<% if( model.error ){ %>",'<div class="errormessagesmall">',c("There was an error getting the data for this dataset"),": <%- model.error %>","</div>","<% } %>"]),purged:b.wrapTemplate(["<% if( model.purged ){ %>",'<div class="purged-msg warningmessagesmall">',c("This dataset has been deleted and removed from disk"),"</div>","<% } %>"]),deleted:b.wrapTemplate(["<% if( model.deleted && !model.purged ){ %>",'<div class="deleted-msg warningmessagesmall">',c("This dataset has been deleted"),"</div>","<% } %>"])});var i=b.wrapTemplate(['<div class="details">','<div class="summary"></div>','<div class="actions clear">','<div class="left"></div>','<div class="right"></div>',"</div>","<% if( !dataset.deleted && !dataset.purged ){ %>",'<div class="tags-display"></div>','<div class="annotation-display"></div>','<div class="display-applications"></div>',"<% if( dataset.peek ){ %>",'<pre class="dataset-peek"><%= dataset.peek %></pre>',"<% } %>","<% } %>","</div>"],"dataset");var g=b.wrapTemplate(['<div class="details">','<div class="summary">',c("You do not have permission to view this dataset"),"</div>","</div>"],"dataset");var j={};j[a.OK]=j[a.FAILED_METADATA]=b.wrapTemplate(["<% if( dataset.misc_blurb ){ %>",'<div class="blurb">','<span class="value"><%- dataset.misc_blurb %></span>',"</div>","<% } %>","<% if( dataset.data_type ){ %>",'<div class="datatype">','<label class="prompt">',c("format"),"</label>",'<span class="value"><%- dataset.data_type %></span>',"</div>","<% } %>","<% if( dataset.metadata_dbkey ){ %>",'<div class="dbkey">','<label class="prompt">',c("database"),"</label>",'<span class="value">',"<%- dataset.metadata_dbkey %>","</span>","</div>","<% } %>","<% if( dataset.misc_info ){ %>",'<div class="info">','<span class="value"><%- dataset.misc_info %></span>',"</div>","<% } %>"],"dataset");j[a.NEW]=b.wrapTemplate(["<div>",c("This is a new dataset and not all of its data are available yet"),"</div>"],"dataset");j[a.NOT_VIEWABLE]=b.wrapTemplate(["<div>",c("You do not have permission to view this dataset"),"</div>"],"dataset");j[a.DISCARDED]=b.wrapTemplate(["<div>",c("The job creating this dataset was cancelled before completion"),"</div>"],"dataset");j[a.QUEUED]=b.wrapTemplate(["<div>",c("This job is waiting to run"),"</div>"],"dataset");j[a.RUNNING]=b.wrapTemplate(["<div>",c("This job is currently running"),"</div>"],"dataset");j[a.UPLOAD]=b.wrapTemplate(["<div>",c("This dataset is currently uploading"),"</div>"],"dataset");j[a.SETTING_METADATA]=b.wrapTemplate(["<div>",c("Metadata is being auto-detected"),"</div>"],"dataset");j[a.PAUSED]=b.wrapTemplate(["<div>",c('This job is paused. Use the "Resume Paused Jobs" in the history menu to resume'),"</div>"],"dataset");j[a.ERROR]=b.wrapTemplate(["<% if( !dataset.purged ){ %>","<div><%- dataset.misc_blurb %></div>","<% } %>",'<span class="help-text">',c("An error occurred with this dataset"),":</span>",'<div class="job-error-text"><%- dataset.misc_info %></div>'],"dataset");j[a.EMPTY]=b.wrapTemplate(["<div>",c("No data"),": <i><%- dataset.misc_blurb %></i></div>"],"dataset");j.unknown=b.wrapTemplate(['<div>Error: unknown dataset state: "<%- dataset.state %>"</div>'],"dataset");var k={resubmitted:b.wrapTemplate(["<% if( model.resubmitted ){ %>",'<div class="resubmitted-msg infomessagesmall">',c("The job creating this dataset has been resubmitted"),"</div>","<% } %>"])};var f=b.wrapTemplate(["<% _.each( apps, function( app ){ %>",'<div class="display-application">','<span class="display-application-location"><%- app.label %></span> ','<span class="display-application-links">',"<% _.each( app.links, function( link ){ %>",'<a target="<%= link.target %>" href="<%= link.href %>">',"<% print( _l( link.text ) ); %>","</a> ","<% }); %>","</span>","</div>","<% }); %>"],"apps");return _.extend({},e.prototype.templates,{warnings:h,details:i,noAccess:g,summaries:j,detailMessages:k,displayApplications:f})}());return{DatasetListItemView:d}}); \ No newline at end of file +define(["mvc/dataset/states","mvc/base-mvc","utils/localization"],function(a,b,c){var e=b.ListItemView;var d=e.extend({className:e.prototype.className+" dataset",id:function(){return["dataset",this.model.get("id")].join("-")},initialize:function(f){if(f.logger){this.logger=this.model.logger=f.logger}this.log(this+".initialize:",f);e.prototype.initialize.call(this,f);this.linkTarget=f.linkTarget||"_blank";this._setUpListeners()},_setUpListeners:function(){this.on("selectable",function(f){if(f){this.$(".primary-actions").hide()}else{this.$(".primary-actions").show()}},this);this.model.on("change",function(g,f){if(this.model.changedAttributes().state&&this.model.inReadyState()&&this.expanded&&!this.model.hasDetails()){this.model.fetch()}else{this.render()}},this);this.on("all",function(f){this.log(f)},this)},_fetchModelDetails:function(){var f=this;if(f.model.inReadyState()&&!f.model.hasDetails()){return f.model.fetch({silent:true})}return jQuery.when()},remove:function(g,h){var f=this;g=g||this.fxSpeed;this.$el.fadeOut(g,function(){Backbone.View.prototype.remove.call(f);if(h){h.call(f)}})},render:function(f){return e.prototype.render.call(this,f)},_swapNewRender:function(f){e.prototype._swapNewRender.call(this,f);if(this.model.has("state")){this.$el.addClass("state-"+this.model.get("state"))}return this.$el},_renderPrimaryActions:function(){return[this._renderDisplayButton()]},_renderDisplayButton:function(){var h=this.model.get("state");if((h===a.NOT_VIEWABLE)||(h===a.DISCARDED)||(!this.model.get("accessible"))){return null}var g={target:this.linkTarget,classes:"display-btn"};if(this.model.get("purged")){g.disabled=true;g.title=c("Cannot display datasets removed from disk")}else{if(h===a.UPLOAD){g.disabled=true;g.title=c("This dataset must finish uploading before it can be viewed")}else{if(h===a.NEW){g.disabled=true;g.title=c("This dataset is not yet viewable")}else{g.title=c("View data");g.href=this.model.urls.display;var f=this;g.onclick=function(i){if(Galaxy.frame&&Galaxy.frame.active){Galaxy.frame.add({title:"Data Viewer: "+f.model.get("name"),type:"other",content:function(j){require(["mvc/data"],function(k){var l=new k.TabularDataset({id:f.model.get("id")});$.when(l.fetch()).then(function(){k.createTabularDatasetChunkedView({model:l,parent_elt:j,embedded:true,height:"100%"})})})}});i.preventDefault()}}}}}g.faIcon="fa-eye";return faIconButton(g)},_renderDetails:function(){if(this.model.get("state")===a.NOT_VIEWABLE){return $(this.templates.noAccess(this.model.toJSON(),this))}var f=e.prototype._renderDetails.call(this);f.find(".actions .left").empty().append(this._renderSecondaryActions());f.find(".summary").html(this._renderSummary()).prepend(this._renderDetailMessages());f.find(".display-applications").html(this._renderDisplayApplications());this._setUpBehaviors(f);return f},_renderSummary:function(){var f=this.model.toJSON(),g=this.templates.summaries[f.state];g=g||this.templates.summaries.unknown;return g(f,this)},_renderDetailMessages:function(){var f=this,h=$('<div class="detail-messages"></div>'),g=f.model.toJSON();_.each(f.templates.detailMessages,function(i){h.append($(i(g,f)))});return h},_renderDisplayApplications:function(){if(this.model.isDeletedOrPurged()){return""}return[this.templates.displayApplications(this.model.get("display_apps"),this),this.templates.displayApplications(this.model.get("display_types"),this)].join("")},_renderSecondaryActions:function(){this.debug("_renderSecondaryActions");switch(this.model.get("state")){case a.NOT_VIEWABLE:return[];case a.OK:case a.FAILED_METADATA:case a.ERROR:return[this._renderDownloadButton(),this._renderShowParamsButton()]}return[this._renderShowParamsButton()]},_renderShowParamsButton:function(){return faIconButton({title:c("View details"),classes:"params-btn",href:this.model.urls.show_params,target:this.linkTarget,faIcon:"fa-info-circle"})},_renderDownloadButton:function(){if(this.model.get("purged")||!this.model.hasData()){return null}if(!_.isEmpty(this.model.get("meta_files"))){return this._renderMetaFileDownloadButton()}return $(['<a class="download-btn icon-btn" href="',this.model.urls.download,'" title="'+c("Download")+'">','<span class="fa fa-floppy-o"></span>',"</a>"].join(""))},_renderMetaFileDownloadButton:function(){var f=this.model.urls;return $(['<div class="metafile-dropdown dropdown">','<a class="download-btn icon-btn" href="javascript:void(0)" data-toggle="dropdown"',' title="'+c("Download")+'">','<span class="fa fa-floppy-o"></span>',"</a>",'<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">','<li><a href="'+f.download+'">',c("Download dataset"),"</a></li>",_.map(this.model.get("meta_files"),function(g){return['<li><a href="',f.meta_download+g.file_type,'">',c("Download")," ",g.file_type,"</a></li>"].join("")}).join("\n"),"</ul>","</div>"].join("\n"))},toString:function(){var f=(this.model)?(this.model+""):("(no model)");return"DatasetListItemView("+f+")"}});d.prototype.templates=(function(){var h=_.extend({},e.prototype.templates.warnings,{failed_metadata:b.wrapTemplate(['<% if( model.state === "failed_metadata" ){ %>','<div class="warningmessagesmall">',c("An error occurred setting the metadata for this dataset"),"</div>","<% } %>"]),error:b.wrapTemplate(["<% if( model.error ){ %>",'<div class="errormessagesmall">',c("There was an error getting the data for this dataset"),": <%- model.error %>","</div>","<% } %>"]),purged:b.wrapTemplate(["<% if( model.purged ){ %>",'<div class="purged-msg warningmessagesmall">',c("This dataset has been deleted and removed from disk"),"</div>","<% } %>"]),deleted:b.wrapTemplate(["<% if( model.deleted && !model.purged ){ %>",'<div class="deleted-msg warningmessagesmall">',c("This dataset has been deleted"),"</div>","<% } %>"])});var i=b.wrapTemplate(['<div class="details">','<div class="summary"></div>','<div class="actions clear">','<div class="left"></div>','<div class="right"></div>',"</div>","<% if( !dataset.deleted && !dataset.purged ){ %>",'<div class="tags-display"></div>','<div class="annotation-display"></div>','<div class="display-applications"></div>',"<% if( dataset.peek ){ %>",'<pre class="dataset-peek"><%= dataset.peek %></pre>',"<% } %>","<% } %>","</div>"],"dataset");var g=b.wrapTemplate(['<div class="details">','<div class="summary">',c("You do not have permission to view this dataset"),"</div>","</div>"],"dataset");var j={};j[a.OK]=j[a.FAILED_METADATA]=b.wrapTemplate(["<% if( dataset.misc_blurb ){ %>",'<div class="blurb">','<span class="value"><%- dataset.misc_blurb %></span>',"</div>","<% } %>","<% if( dataset.data_type ){ %>",'<div class="datatype">','<label class="prompt">',c("format"),"</label>",'<span class="value"><%- dataset.data_type %></span>',"</div>","<% } %>","<% if( dataset.metadata_dbkey ){ %>",'<div class="dbkey">','<label class="prompt">',c("database"),"</label>",'<span class="value">',"<%- dataset.metadata_dbkey %>","</span>","</div>","<% } %>","<% if( dataset.misc_info ){ %>",'<div class="info">','<span class="value"><%- dataset.misc_info %></span>',"</div>","<% } %>"],"dataset");j[a.NEW]=b.wrapTemplate(["<div>",c("This is a new dataset and not all of its data are available yet"),"</div>"],"dataset");j[a.NOT_VIEWABLE]=b.wrapTemplate(["<div>",c("You do not have permission to view this dataset"),"</div>"],"dataset");j[a.DISCARDED]=b.wrapTemplate(["<div>",c("The job creating this dataset was cancelled before completion"),"</div>"],"dataset");j[a.QUEUED]=b.wrapTemplate(["<div>",c("This job is waiting to run"),"</div>"],"dataset");j[a.RUNNING]=b.wrapTemplate(["<div>",c("This job is currently running"),"</div>"],"dataset");j[a.UPLOAD]=b.wrapTemplate(["<div>",c("This dataset is currently uploading"),"</div>"],"dataset");j[a.SETTING_METADATA]=b.wrapTemplate(["<div>",c("Metadata is being auto-detected"),"</div>"],"dataset");j[a.PAUSED]=b.wrapTemplate(["<div>",c('This job is paused. Use the "Resume Paused Jobs" in the history menu to resume'),"</div>"],"dataset");j[a.ERROR]=b.wrapTemplate(["<% if( !dataset.purged ){ %>","<div><%- dataset.misc_blurb %></div>","<% } %>",'<span class="help-text">',c("An error occurred with this dataset"),":</span>",'<div class="job-error-text"><%- dataset.misc_info %></div>'],"dataset");j[a.EMPTY]=b.wrapTemplate(["<div>",c("No data"),": <i><%- dataset.misc_blurb %></i></div>"],"dataset");j.unknown=b.wrapTemplate(['<div>Error: unknown dataset state: "<%- dataset.state %>"</div>'],"dataset");var k={resubmitted:b.wrapTemplate(["<% if( model.resubmitted ){ %>",'<div class="resubmitted-msg infomessagesmall">',c("The job creating this dataset has been resubmitted"),"</div>","<% } %>"])};var f=b.wrapTemplate(["<% _.each( apps, function( app ){ %>",'<div class="display-application">','<span class="display-application-location"><%- app.label %></span> ','<span class="display-application-links">',"<% _.each( app.links, function( link ){ %>",'<a target="<%= link.target %>" href="<%= link.href %>">',"<% print( _l( link.text ) ); %>","</a> ","<% }); %>","</span>","</div>","<% }); %>"],"apps");return _.extend({},e.prototype.templates,{warnings:h,details:i,noAccess:g,summaries:j,detailMessages:k,displayApplications:f})}());return{DatasetListItemView:d}}); \ No newline at end of file diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/scripts/packed/mvc/dataset/dataset-model.js --- a/static/scripts/packed/mvc/dataset/dataset-model.js +++ b/static/scripts/packed/mvc/dataset/dataset-model.js @@ -1,1 +1,1 @@ -define(["mvc/dataset/states","mvc/base-mvc","utils/localization"],function(a,b,c){var f=b.SearchableModelMixin;var e=Backbone.Model.extend(b.LoggableMixin).extend(b.mixin(f,{defaults:{state:a.NEW,deleted:false,purged:false,name:"(unnamed dataset)",accessible:true,data_type:"",file_ext:"",file_size:0,meta_files:[],misc_blurb:"",misc_info:"",tags:[]},initialize:function(g,h){this.debug(this+"(Dataset).initialize",g,h);if(!this.get("accessible")){this.set("state",a.NOT_VIEWABLE)}this.urls=this._generateUrls();this._setUpListeners()},_generateUrls:function(){var i=this.get("id");if(!i){return{}}var h={purge:"datasets/"+i+"/purge_async",display:"datasets/"+i+"/display/?preview=True",edit:"datasets/"+i+"/edit",download:"datasets/"+i+"/display?to_ext="+this.get("file_ext"),report_error:"dataset/errors?id="+i,rerun:"tool_runner/rerun?id="+i,show_params:"datasets/"+i+"/show_params",visualization:"visualization",meta_download:"dataset/get_metadata_file?hda_id="+i+"&metadata_name="};var g=(galaxy_config&&galaxy_config.root)?(galaxy_config.root):("/");_.each(h,function(k,j){h[j]=g+k});this.urls=h;return h},_setUpListeners:function(){this.on("change:state",function(h,g){this.log(this+" has changed state:",h,g);if(this.inReadyState()){this.trigger("state:ready",h,g,this.previous("state"))}});this.on("change:id change:file_ext",function(g){this._generateUrls()})},toJSON:function(){var g=Backbone.Model.prototype.toJSON.call(this);return _.extend(g,{urls:this.urls})},isDeletedOrPurged:function(){return(this.get("deleted")||this.get("purged"))},inReadyState:function(){var g=_.contains(a.READY_STATES,this.get("state"));return(this.isDeletedOrPurged()||g)},hasDetails:function(){return _.has(this.attributes,"genome_build")},hasData:function(){return(this.get("file_size")>0)},"delete":function(g){if(this.get("deleted")){return jQuery.when()}return this.save({deleted:true},g)},undelete:function(g){if(!this.get("deleted")||this.get("purged")){return jQuery.when()}return this.save({deleted:false},g)},purge:function d(g){if(this.get("purged")){return jQuery.when()}g=g||{};g.url=this.urls.purge;var h=this,i=jQuery.ajax(g);i.done(function(l,j,k){h.set({deleted:true,purged:true})});i.fail(function(n,j,m){var k=c("Unable to purge dataset");var l=("Removal of datasets by users is not allowed in this Galaxy instance");if(n.responseJSON&&n.responseJSON.error){k=n.responseJSON.error}else{if(n.responseText.indexOf(l)!==-1){k=l}}n.responseText=k;h.trigger("error",h,n,g,c(k),{error:k})});return i},searchAttributes:["name","file_ext","genome_build","misc_blurb","misc_info","annotation","tags"],searchAliases:{title:"name",format:"file_ext",database:"genome_build",blurb:"misc_blurb",description:"misc_blurb",info:"misc_info",tag:"tags"},toString:function(){var g=this.get("id")||"";if(this.get("name")){g='"'+this.get("name")+'",'+g}return"Dataset("+g+")"}}));return{DatasetAssociation:e}}); \ No newline at end of file +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}}); \ No newline at end of file diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/scripts/packed/mvc/ui.js --- a/static/scripts/packed/mvc/ui.js +++ b/static/scripts/packed/mvc/ui.js @@ -1,1 +1,1 @@ -var IconButton=Backbone.Model.extend({defaults:{title:"",icon_class:"",on_click:null,menu_options:null,is_menu_button:true,id:null,href:null,target:null,enabled:true,visible:true,tooltip_config:{}}});var IconButtonView=Backbone.View.extend({initialize:function(){this.model.attributes.tooltip_config={placement:"bottom"};this.model.bind("change",this.render,this)},render:function(){this.$el.tooltip("hide");var a=this.template(this.model.toJSON());a.tooltip(this.model.get("tooltip_config"));this.$el.replaceWith(a);this.setElement(a);return this},events:{click:"click"},click:function(a){if(_.isFunction(this.model.get("on_click"))){this.model.get("on_click")(a);return false}return true},template:function(b){var a='title="'+b.title+'" class="icon-button';if(b.is_menu_button){a+=" menu-button"}a+=" "+b.icon_class;if(!b.enabled){a+="_disabled"}a+='"';if(b.id){a+=' id="'+b.id+'"'}a+=' href="'+b.href+'"';if(b.target){a+=' target="'+b.target+'"'}if(!b.visible){a+=' style="display: none;"'}if(b.enabled){a="<a "+a+"/>"}else{a="<span "+a+"/>"}return $(a)}});var IconButtonCollection=Backbone.Collection.extend({model:IconButton});var IconButtonMenuView=Backbone.View.extend({tagName:"div",initialize:function(){this.render()},render:function(){var a=this;this.collection.each(function(d){var b=$("<a/>").attr("href","javascript:void(0)").attr("title",d.attributes.title).addClass("icon-button menu-button").addClass(d.attributes.icon_class).appendTo(a.$el).click(d.attributes.on_click);if(d.attributes.tooltip_config){b.tooltip(d.attributes.tooltip_config)}var c=d.get("options");if(c){make_popupmenu(b,c)}});return this}});var create_icon_buttons_menu=function(b,a){if(!a){a={}}var c=new IconButtonCollection(_.map(b,function(d){return new IconButton(_.extend(d,a))}));return new IconButtonMenuView({collection:c})};var Grid=Backbone.Collection.extend({});var GridView=Backbone.View.extend({});var PopupMenu=Backbone.View.extend({initialize:function(b,a){this.$button=b;if(!this.$button.size()){this.$button=$("<div/>")}this.options=a||[];var c=this;this.$button.click(function(d){$(".popmenu-wrapper").remove();c._renderAndShow(d);return false})},_renderAndShow:function(a){this.render();this.$el.appendTo("body").css(this._getShownPosition(a)).show();this._setUpCloseBehavior()},render:function(){this.$el.addClass("popmenu-wrapper").hide().css({position:"absolute"}).html(this.template(this.$button.attr("id"),this.options));if(this.options.length){var a=this;this.$el.find("li").each(function(c,b){var d=a.options[c];if(d.func){$(this).children("a.popupmenu-option").click(function(e){d.func.call(a,e,d)})}})}return this},template:function(b,a){return['<ul id="',b,'-menu" class="dropdown-menu">',this._templateOptions(a),"</ul>"].join("")},_templateOptions:function(a){if(!a.length){return"<li>(no options)</li>"}return _.map(a,function(d){if(d.divider){return'<li class="divider"></li>'}else{if(d.header){return['<li class="head"><a href="javascript:void(0);">',d.html,"</a></li>"].join("")}}var c=d.href||"javascript:void(0);",e=(d.target)?(' target="'+d.target+'"'):(""),b=(d.checked)?('<span class="fa fa-check"></span>'):("");return['<li><a class="popupmenu-option" href="',c,'"',e,">",b,d.html,"</a></li>"].join("")}).join("")},_getShownPosition:function(b){var c=this.$el.width();var a=b.pageX-c/2;a=Math.min(a,$(document).scrollLeft()+$(window).width()-c-5);a=Math.max(a,$(document).scrollLeft()+5);return{top:b.pageY,left:a}},_setUpCloseBehavior:function(){var c=this;function a(e){$(document).off("click.close_popup");if(window.parent!==window){try{$(window.parent.document).off("click.close_popup")}catch(d){}}else{try{$("iframe#galaxy_main").contents().off("click.close_popup")}catch(d){}}c.remove()}$("html").one("click.close_popup",a);if(window.parent!==window){try{$(window.parent.document).find("html").one("click.close_popup",a)}catch(b){}}else{try{$("iframe#galaxy_main").contents().one("click.close_popup",a)}catch(b){}}},addItem:function(b,a){a=(a>=0)?a:this.options.length;this.options.splice(a,0,b);return this},removeItem:function(a){if(a>=0){this.options.splice(a,1)}return this},findIndexByHtml:function(b){for(var a=0;a<this.options.length;a++){if(_.has(this.options[a],"html")&&(this.options[a].html===b)){return a}}return null},findItemByHtml:function(a){return this.options[(this.findIndexByHtml(a))]},toString:function(){return"PopupMenu"}});PopupMenu.create=function _create(b,a){return new PopupMenu(b,a)};PopupMenu.make_popupmenu=function(b,c){var a=[];_.each(c,function(f,d){var e={html:d};if(f===null){e.header=true}else{if(jQuery.type(f)==="function"){e.func=f}}a.push(e)});return new PopupMenu($(b),a)};PopupMenu.convertLinksToOptions=function(c,a){c=$(c);a=a||"a";var b=[];c.find(a).each(function(g,e){var f={},d=$(g);f.html=d.text();if(d.attr("href")){var j=d.attr("href"),k=d.attr("target"),h=d.attr("confirm");f.func=function(){if((h)&&(!confirm(h))){return}switch(k){case"_parent":window.parent.location=j;break;case"_top":window.top.location=j;break;default:window.location=j}}}b.push(f)});return b};PopupMenu.fromExistingDom=function(d,c,a){d=$(d);c=$(c);var b=PopupMenu.convertLinksToOptions(c,a);c.remove();return new PopupMenu(d,b)};PopupMenu.make_popup_menus=function(c,b,d){c=c||document;b=b||"div[popupmenu]";d=d||function(e,f){return"#"+e.attr("popupmenu")};var a=[];$(c).find(b).each(function(){var e=$(this),f=$(c).find(d(e,c));a.push(PopupMenu.fromDom(f,e));f.addClass("popup")});return a};var faIconButton=function(a){a=a||{};a.tooltipConfig=a.tooltipConfig||{placement:"bottom"};a.classes=["icon-btn"].concat(a.classes||[]);if(a.disabled){a.classes.push("disabled")}var b=['<a class="',a.classes.join(" "),'"',((a.title)?(' title="'+a.title+'"'):("")),((!a.disabled&&a.target)?(' target="'+a.target+'"'):("")),' href="',((!a.disabled&&a.href)?(a.href):("javascript:void(0);")),'">','<span class="fa ',a.faIcon,'"></span>',"</a>"].join("");var c=$(b).tooltip(a.tooltipConfig);if(_.isFunction(a.onclick)){c.click(a.onclick)}return c};function LoadingIndicator(a,c){var b=this;c=jQuery.extend({cover:false},c||{});function d(){var e=['<div class="loading-indicator">','<div class="loading-indicator-text">','<span class="fa fa-spinner fa-spin fa-lg"></span>','<span class="loading-indicator-message">loading...</span>',"</div>","</div>"].join("\n");var g=$(e).hide().css(c.css||{position:"fixed"}),f=g.children(".loading-indicator-text");if(c.cover){g.css({"z-index":2,top:a.css("top"),bottom:a.css("bottom"),left:a.css("left"),right:a.css("right"),opacity:0.5,"background-color":"white","text-align":"center"});f=g.children(".loading-indicator-text").css({"margin-top":"20px"})}else{f=g.children(".loading-indicator-text").css({margin:"12px 0px 0px 10px",opacity:"0.85",color:"grey"});f.children(".loading-indicator-message").css({margin:"0px 8px 0px 0px","font-style":"italic"})}return g}b.show=function(f,e,g){f=f||"loading...";e=e||"fast";b.$indicator=d().insertBefore(a);b.message(f);b.$indicator.fadeIn(e,g);return b};b.message=function(e){b.$indicator.find("i").text(e)};b.hide=function(e,f){e=e||"fast";if(b.$indicator&&b.$indicator.size()){b.$indicator.fadeOut(e,function(){b.$indicator.remove();if(f){f()}})}else{if(f){f()}}return b};return b}(function(){function a(j,p){var d=27,m=13,c=$(j),e=true,g={initialVal:"",name:"search",placeholder:"search",classes:"",onclear:function(){},onfirstsearch:null,onsearch:function(q){},minSearchLen:0,escWillClear:true,oninit:function(){}};function i(q){var r=$(this).parent().children("input");r.val("");r.trigger("clear:searchInput");p.onclear()}function o(r,q){$(this).trigger("search:searchInput",q);if(typeof p.onfirstsearch==="function"&&e){e=false;p.onfirstsearch(q)}else{p.onsearch(q)}}function f(){return['<input type="text" name="',p.name,'" placeholder="',p.placeholder,'" ','class="search-query ',p.classes,'" ',"/>"].join("")}function l(){return $(f()).focus(function(q){$(this).select()}).keyup(function(r){if(r.which===d&&p.escWillClear){i.call(this,r)}else{var q=$(this).val();if((r.which===m)||(p.minSearchLen&&q.length>=p.minSearchLen)){o.call(this,r,q)}else{if(!q.length){i.call(this,r)}}}}).val(p.initialVal)}function k(){return $(['<span class="search-clear fa fa-times-circle" ','title="',_l("clear search (esc)"),'"></span>'].join("")).tooltip({placement:"bottom"}).click(function(q){i.call(this,q)})}function n(){return $(['<span class="search-loading fa fa-spinner fa-spin" ','title="',_l("loading..."),'"></span>'].join("")).hide().tooltip({placement:"bottom"})}function h(){c.find(".search-loading").toggle();c.find(".search-clear").toggle()}if(jQuery.type(p)==="string"){if(p==="toggle-loading"){h()}return c}if(jQuery.type(p)==="object"){p=jQuery.extend(true,{},g,p)}return c.addClass("search-input").prepend([l(),k(),n()])}jQuery.fn.extend({searchInput:function b(c){return this.each(function(){return a(this,c)})}})}());(function(){function c(o,n){this.currModeIndex=0;return this._init(o,n)}c.prototype.DATA_KEY="mode-button";c.prototype.defaults={switchModesOnClick:true};c.prototype._init=function j(o,n){n=n||{};this.$element=$(o);this.options=jQuery.extend(true,{},this.defaults,n);if(!n.modes){throw new Error('ModeButton requires a "modes" array')}var q=this;this.$element.click(function p(r){q.callModeFn();if(q.options.switchModesOnClick){q._incModeIndex()}$(this).html(q.options.modes[q.currModeIndex].html)});return this.reset()};c.prototype._incModeIndex=function l(){this.currModeIndex+=1;if(this.currModeIndex>=this.options.modes.length){this.currModeIndex=0}return this};c.prototype._getModeIndex=function f(n){for(var o=0;o<this.options.modes.length;o+=1){if(this.options.modes[o].mode===n){return o}}throw new Error("mode not found: "+n)};c.prototype._setModeByIndex=function m(n){var o=this.options.modes[n];if(!o){throw new Error("mode index not found: "+n)}this.currModeIndex=n;if(o.html){this.$element.html(o.html)}return this};c.prototype.currentMode=function d(){return this.options.modes[this.currModeIndex]};c.prototype.current=function i(){return this.currentMode().mode};c.prototype.getMode=function g(n){if(!n){return this.currentMode()}return this.options.modes[(this._getModeIndex(n))]};c.prototype.hasMode=function b(n){try{return !!this.getMode(n)}catch(o){}return false};c.prototype.setMode=function a(n){return this._setModeByIndex(this._getModeIndex(n))};c.prototype.reset=function h(){this.currModeIndex=0;if(this.options.initialMode){this.currModeIndex=this._getModeIndex(this.options.initialMode)}return this._setModeByIndex(this.currModeIndex)};c.prototype.callModeFn=function e(n){var o=this.getMode(n).onclick;if(o&&jQuery.type(o==="function")){return o.call(this.$element.get(0))}return undefined};jQuery.fn.extend({modeButton:function k(n){if(!this.size()){return this}if(jQuery.type(n)==="object"){return this.map(function(){var r=$(this);r.data("mode-button",new c(r,n));return this})}var p=$(this[0]),o=p.data("mode-button");if(!o){throw new Error("modeButton needs an options object or string name of a function")}if(o&&jQuery.type(n)==="string"){var q=n;if(o&&jQuery.type(o[q])==="function"){return o[q].apply(o,jQuery.makeArray(arguments).slice(1))}}return o}})}());function dropDownSelect(b,c){c=c||((!_.isEmpty(b))?(b[0]):(""));var a=$(['<div class="dropdown-select btn-group">','<button type="button" class="btn btn-default">','<span class="dropdown-select-selected">'+c+"</span>","</button>","</div>"].join("\n"));if(b&&b.length>1){a.find("button").addClass("dropdown-toggle").attr("data-toggle","dropdown").append(' <span class="caret"></span>');a.append(['<ul class="dropdown-menu" role="menu">',_.map(b,function(e){return['<li><a href="javascript:void(0)">',e,"</a></li>"].join("")}).join("\n"),"</ul>"].join("\n"))}function d(g){var h=$(this),f=h.parents(".dropdown-select"),e=h.text();f.find(".dropdown-select-selected").text(e);f.trigger("change.dropdown-select",e)}a.find("a").click(d);return a}(function(){function e(k,j){return this.init(k,j)}e.prototype.DATA_KEY="filter-control";e.prototype.init=function g(k,j){j=j||{filters:[]};this.$element=$(k).addClass("filter-control btn-group");this.options=jQuery.extend(true,{},this.defaults,j);this.currFilter=this.options.filters[0];return this.render()};e.prototype.render=function d(){this.$element.empty().append([this._renderKeySelect(),this._renderOpSelect(),this._renderValueInput()]);return this};e.prototype._renderKeySelect=function a(){var j=this;var k=this.options.filters.map(function(l){return l.key});this.$keySelect=dropDownSelect(k,this.currFilter.key).addClass("filter-control-key").on("change.dropdown-select",function(m,l){j.currFilter=_.findWhere(j.options.filters,{key:l});j.render()._triggerChange()});return this.$keySelect};e.prototype._renderOpSelect=function i(){var j=this,k=this.currFilter.ops;this.$opSelect=dropDownSelect(k,k[0]).addClass("filter-control-op").on("change.dropdown-select",function(m,l){j._triggerChange()});return this.$opSelect};e.prototype._renderValueInput=function c(){var j=this;if(this.currFilter.values){this.$valueSelect=dropDownSelect(this.currFilter.values,this.currFilter.values[0]).on("change.dropdown-select",function(l,k){j._triggerChange()})}else{this.$valueSelect=$("<input/>").addClass("form-control").on("change",function(k,l){j._triggerChange()})}this.$valueSelect.addClass("filter-control-value");return this.$valueSelect};e.prototype.val=function b(){var k=this.$element.find(".filter-control-key .dropdown-select-selected").text(),m=this.$element.find(".filter-control-op .dropdown-select-selected").text(),j=this.$element.find(".filter-control-value"),l=(j.hasClass("dropdown-select"))?(j.find(".dropdown-select-selected").text()):(j.val());return{key:k,op:m,value:l}};e.prototype._triggerChange=function h(){this.$element.trigger("change.filter-control",this.val())};jQuery.fn.extend({filterControl:function f(k){var j=jQuery.makeArray(arguments).slice(1);return this.map(function(){var n=$(this),m=n.data(e.prototype.DATA_KEY);if(jQuery.type(k)==="object"){m=new e(n,k);n.data(e.prototype.DATA_KEY,m)}if(m&&jQuery.type(k)==="string"){var l=m[k];if(jQuery.type(l)==="function"){return l.apply(m,j)}}return this})}})}());(function(){function i(o,n){this.numPages=null;this.currPage=0;return this.init(o,n)}i.prototype.DATA_KEY="pagination";i.prototype.defaults={startingPage:0,perPage:20,totalDataSize:null,currDataSize:null};i.prototype.init=function g(n,o){o=o||{};this.$element=n;this.options=jQuery.extend(true,{},this.defaults,o);this.currPage=this.options.startingPage;if(this.options.totalDataSize!==null){this.numPages=Math.ceil(this.options.totalDataSize/this.options.perPage);if(this.currPage>=this.numPages){this.currPage=this.numPages-1}}this.$element.data(i.prototype.DATA_KEY,this);this._render();return this};function m(n){return $(['<li><a href="javascript:void(0);">',n,"</a></li>"].join(""))}i.prototype._render=function e(){if(this.options.totalDataSize===0){return this}if(this.numPages===1){return this}if(this.numPages>0){this._renderPages();this._scrollToActivePage()}else{this._renderPrevNext()}return this};i.prototype._renderPrevNext=function b(){var o=this,p=m("Prev"),n=m("Next"),q=$("<ul/>").addClass("pagination pagination-prev-next");if(this.currPage===0){p.addClass("disabled")}else{p.click(function(){o.prevPage()})}if((this.numPages&&this.currPage===(this.numPages-1))||(this.options.currDataSize&&this.options.currDataSize<this.options.perPage)){n.addClass("disabled")}else{n.click(function(){o.nextPage()})}this.$element.html(q.append([p,n]));return this.$element};i.prototype._renderPages=function a(){var n=this,q=$("<div>").addClass("pagination-scroll-container"),s=$("<ul/>").addClass("pagination pagination-page-list"),r=function(t){n.goToPage($(this).data("page"))};for(var o=0;o<this.numPages;o+=1){var p=m(o+1).attr("data-page",o).click(r);if(o===this.currPage){p.addClass("active")}s.append(p)}return this.$element.html(q.html(s))};i.prototype._scrollToActivePage=function l(){var p=this.$element.find(".pagination-scroll-container");if(!p.size()){return this}var o=this.$element.find("li.active"),n=p.width()/2;p.scrollLeft(p.scrollLeft()+o.position().left-n);return this};i.prototype.goToPage=function j(n){if(n<=0){n=0}if(this.numPages&&n>=this.numPages){n=this.numPages-1}if(n===this.currPage){return this}this.currPage=n;this.$element.trigger("pagination.page-change",this.currPage);this._render();return this};i.prototype.prevPage=function c(){return this.goToPage(this.currPage-1)};i.prototype.nextPage=function h(){return this.goToPage(this.currPage+1)};i.prototype.page=function f(){return this.currPage};i.create=function k(n,o){return new i(n,o)};jQuery.fn.extend({pagination:function d(o){var n=jQuery.makeArray(arguments).slice(1);if(jQuery.type(o)==="object"){return this.map(function(){i.create($(this),o);return this})}var q=$(this[0]),r=q.data(i.prototype.DATA_KEY);if(r){if(jQuery.type(o)==="string"){var p=r[o];if(jQuery.type(p)==="function"){return p.apply(r,n)}}else{return r}}return undefined}})}());(function(){var g={renameColumns:false,columnNames:[],commentChar:"#",hideCommentRows:false,includePrompts:true,topLeftContent:"Columns:"},s="peek-control.change",t="peek-control.rename",l="peek-control",v="control",f="control-prompt",c="selected",n="disabled",u="button",q="renamable-header",p="column-index",a="column-name";function i(w){if(w.disabled&&jQuery.type(w.disabled)!=="array"){throw new Error('"disabled" must be defined as an array of indeces: '+JSON.stringify(w))}if(w.multiselect&&w.selected&&jQuery.type(w.selected)!=="array"){throw new Error('Mulitselect rows need an array for "selected": '+JSON.stringify(w))}if(!w.label||!w.id){throw new Error("Peek controls need a label and id for each control row: "+JSON.stringify(w))}if(w.disabled&&w.disabled.indexOf(w.selected)!==-1){throw new Error("Selected column is in the list of disabled columns: "+JSON.stringify(w))}return w}function o(x,w){return $("<div/>").addClass(u).text(x.label)}function k(x,w){var y=$("<td/>").html(o(x,w)).attr("data-"+p,w);if(x.disabled&&x.disabled.indexOf(w)!==-1){y.addClass(n)}return y}function e(y,z,w){var x=y.children("."+u);if(y.hasClass(c)){x.html((z.selectedText!==undefined)?(z.selectedText):(z.label))}else{x.html((z.unselectedText!==undefined)?(z.unselectedText):(z.label))}}function h(z,x){var y=k(z,x);if(z.selected===x){y.addClass(c)}e(y,z,x);if(!y.hasClass(n)){y.click(function w(D){var E=$(this);if(!E.hasClass(c)){var A=E.parent().children("."+c).removeClass(c);A.each(function(){e($(this),z,x)});E.addClass(c);e(E,z,x);var C={},B=E.parent().attr("id"),F=E.data(p);C[B]=F;E.parents(".peek").trigger(s,C)}})}return y}function m(z,x){var y=k(z,x);if(z.selected&&z.selected.indexOf(x)!==-1){y.addClass(c)}e(y,z,x);if(!y.hasClass(n)){y.click(function w(D){var E=$(this);E.toggleClass(c);e(E,z,x);var C=E.parent().find("."+c).map(function(G,H){return $(H).data(p)});var B={},A=E.parent().attr("id"),F=jQuery.makeArray(C);B[A]=F;E.parents(".peek").trigger(s,B)})}return y}function j(y,z){var w=[];for(var x=0;x<y;x+=1){w.push(z.multiselect?m(z,x):h(z,x))}return w}function r(y,z,x){var A=$("<tr/>").attr("id",z.id).addClass(v);if(x){var w=$("<td/>").addClass(f).text(z.label+":");A.append(w)}A.append(j(y,z));return A}function b(E){E=jQuery.extend(true,{},g,E);var D=$(this).addClass(l),A=D.find("table"),z=A.find("th").size(),C=A.find("tr").size(),w=A.find("td[colspan]").map(function(H,F){var G=$(this);if(G.text()&&G.text().match(new RegExp("^"+E.commentChar))){return $(this).css("color","grey").parent().get(0)}return null});if(E.hideCommentRows){w.hide();C-=w.size()}if(E.includePrompts){var y=$("<th/>").addClass("top-left").text(E.topLeftContent).attr("rowspan",C);A.find("tr").first().prepend(y)}var B=A.find("th:not(.top-left)").each(function(G,I){var H=$(this),J=H.text().replace(/^\d+\.*/,""),F=E.columnNames[G]||J;H.attr("data-"+a,F).text((G+1)+((F)?("."+F):("")))});if(E.renameColumns){B.addClass(q).click(function x(){var G=$(this),F=G.index()+(E.includePrompts?0:1),I=G.data(a),H=prompt("New column name:",I);if(H!==null&&H!==I){G.text(F+(H?("."+H):"")).data(a,H).attr("data-",a,H);var J=jQuery.makeArray(G.parent().children("th:not(.top-left)").map(function(){return $(this).data(a)}));G.parents(".peek").trigger(t,J)}})}E.controls.forEach(function(G,F){i(G);var H=r(z,G,E.includePrompts);A.find("tbody").append(H)});return this}jQuery.fn.extend({peekControl:function d(w){return this.map(function(){return b.call(this,w)})}})}()); \ No newline at end of file +var IconButton=Backbone.Model.extend({defaults:{title:"",icon_class:"",on_click:null,menu_options:null,is_menu_button:true,id:null,href:null,target:null,enabled:true,visible:true,tooltip_config:{}}});var IconButtonView=Backbone.View.extend({initialize:function(){this.model.attributes.tooltip_config={placement:"bottom"};this.model.bind("change",this.render,this)},render:function(){this.$el.tooltip("hide");var a=this.template(this.model.toJSON());a.tooltip(this.model.get("tooltip_config"));this.$el.replaceWith(a);this.setElement(a);return this},events:{click:"click"},click:function(a){if(_.isFunction(this.model.get("on_click"))){this.model.get("on_click")(a);return false}return true},template:function(b){var a='title="'+b.title+'" class="icon-button';if(b.is_menu_button){a+=" menu-button"}a+=" "+b.icon_class;if(!b.enabled){a+="_disabled"}a+='"';if(b.id){a+=' id="'+b.id+'"'}a+=' href="'+b.href+'"';if(b.target){a+=' target="'+b.target+'"'}if(!b.visible){a+=' style="display: none;"'}if(b.enabled){a="<a "+a+"/>"}else{a="<span "+a+"/>"}return $(a)}});var IconButtonCollection=Backbone.Collection.extend({model:IconButton});var IconButtonMenuView=Backbone.View.extend({tagName:"div",initialize:function(){this.render()},render:function(){var a=this;this.collection.each(function(d){var b=$("<a/>").attr("href","javascript:void(0)").attr("title",d.attributes.title).addClass("icon-button menu-button").addClass(d.attributes.icon_class).appendTo(a.$el).click(d.attributes.on_click);if(d.attributes.tooltip_config){b.tooltip(d.attributes.tooltip_config)}var c=d.get("options");if(c){make_popupmenu(b,c)}});return this}});var create_icon_buttons_menu=function(b,a){if(!a){a={}}var c=new IconButtonCollection(_.map(b,function(d){return new IconButton(_.extend(d,a))}));return new IconButtonMenuView({collection:c})};var Grid=Backbone.Collection.extend({});var GridView=Backbone.View.extend({});var PopupMenu=Backbone.View.extend({initialize:function(b,a){this.$button=b;if(!this.$button.size()){this.$button=$("<div/>")}this.options=a||[];var c=this;this.$button.click(function(d){$(".popmenu-wrapper").remove();c._renderAndShow(d);return false})},_renderAndShow:function(a){this.render();this.$el.appendTo("body").css(this._getShownPosition(a)).show();this._setUpCloseBehavior()},render:function(){this.$el.addClass("popmenu-wrapper").hide().css({position:"absolute"}).html(this.template(this.$button.attr("id"),this.options));if(this.options.length){var a=this;this.$el.find("li").each(function(c,b){var d=a.options[c];if(d.func){$(this).children("a.popupmenu-option").click(function(e){d.func.call(a,e,d)})}})}return this},template:function(b,a){return['<ul id="',b,'-menu" class="dropdown-menu">',this._templateOptions(a),"</ul>"].join("")},_templateOptions:function(a){if(!a.length){return"<li>(no options)</li>"}return _.map(a,function(d){if(d.divider){return'<li class="divider"></li>'}else{if(d.header){return['<li class="head"><a href="javascript:void(0);">',d.html,"</a></li>"].join("")}}var c=d.href||"javascript:void(0);",e=(d.target)?(' target="'+d.target+'"'):(""),b=(d.checked)?('<span class="fa fa-check"></span>'):("");return['<li><a class="popupmenu-option" href="',c,'"',e,">",b,d.html,"</a></li>"].join("")}).join("")},_getShownPosition:function(b){var c=this.$el.width();var a=b.pageX-c/2;a=Math.min(a,$(document).scrollLeft()+$(window).width()-c-5);a=Math.max(a,$(document).scrollLeft()+5);return{top:b.pageY,left:a}},_setUpCloseBehavior:function(){var c=this;function a(e){$(document).off("click.close_popup");if(window.parent!==window){try{$(window.parent.document).off("click.close_popup")}catch(d){}}else{try{$("iframe#galaxy_main").contents().off("click.close_popup")}catch(d){}}c.remove()}$("html").one("click.close_popup",a);if(window.parent!==window){try{$(window.parent.document).find("html").one("click.close_popup",a)}catch(b){}}else{try{$("iframe#galaxy_main").contents().one("click.close_popup",a)}catch(b){}}},addItem:function(b,a){a=(a>=0)?a:this.options.length;this.options.splice(a,0,b);return this},removeItem:function(a){if(a>=0){this.options.splice(a,1)}return this},findIndexByHtml:function(b){for(var a=0;a<this.options.length;a++){if(_.has(this.options[a],"html")&&(this.options[a].html===b)){return a}}return null},findItemByHtml:function(a){return this.options[(this.findIndexByHtml(a))]},toString:function(){return"PopupMenu"}});PopupMenu.create=function _create(b,a){return new PopupMenu(b,a)};PopupMenu.make_popupmenu=function(b,c){var a=[];_.each(c,function(f,d){var e={html:d};if(f===null){e.header=true}else{if(jQuery.type(f)==="function"){e.func=f}}a.push(e)});return new PopupMenu($(b),a)};PopupMenu.convertLinksToOptions=function(c,a){c=$(c);a=a||"a";var b=[];c.find(a).each(function(g,e){var f={},d=$(g);f.html=d.text();if(d.attr("href")){var j=d.attr("href"),k=d.attr("target"),h=d.attr("confirm");f.func=function(){if((h)&&(!confirm(h))){return}switch(k){case"_parent":window.parent.location=j;break;case"_top":window.top.location=j;break;default:window.location=j}}}b.push(f)});return b};PopupMenu.fromExistingDom=function(d,c,a){d=$(d);c=$(c);var b=PopupMenu.convertLinksToOptions(c,a);c.remove();return new PopupMenu(d,b)};PopupMenu.make_popup_menus=function(c,b,d){c=c||document;b=b||"div[popupmenu]";d=d||function(e,f){return"#"+e.attr("popupmenu")};var a=[];$(c).find(b).each(function(){var e=$(this),f=$(c).find(d(e,c));a.push(PopupMenu.fromDom(f,e));f.addClass("popup")});return a};var faIconButton=function(a){a=a||{};a.tooltipConfig=a.tooltipConfig||{placement:"bottom"};a.classes=["icon-btn"].concat(a.classes||[]);if(a.disabled){a.classes.push("disabled")}var b=['<a class="',a.classes.join(" "),'"',((a.title)?(' title="'+a.title+'"'):("")),((!a.disabled&&a.target)?(' target="'+a.target+'"'):("")),' href="',((!a.disabled&&a.href)?(a.href):("javascript:void(0);")),'">','<span class="fa ',a.faIcon,'"></span>',"</a>"].join("");var c=$(b).tooltip(a.tooltipConfig);if(_.isFunction(a.onclick)){c.click(a.onclick)}return c};function LoadingIndicator(a,c){var b=this;c=jQuery.extend({cover:false},c||{});function d(){var e=['<div class="loading-indicator">','<div class="loading-indicator-text">','<span class="fa fa-spinner fa-spin fa-lg"></span>','<span class="loading-indicator-message">loading...</span>',"</div>","</div>"].join("\n");var g=$(e).hide().css(c.css||{position:"fixed"}),f=g.children(".loading-indicator-text");if(c.cover){g.css({"z-index":2,top:a.css("top"),bottom:a.css("bottom"),left:a.css("left"),right:a.css("right"),opacity:0.5,"background-color":"white","text-align":"center"});f=g.children(".loading-indicator-text").css({"margin-top":"20px"})}else{f=g.children(".loading-indicator-text").css({margin:"12px 0px 0px 10px",opacity:"0.85",color:"grey"});f.children(".loading-indicator-message").css({margin:"0px 8px 0px 0px","font-style":"italic"})}return g}b.show=function(f,e,g){f=f||"loading...";e=e||"fast";b.$indicator=d().insertBefore(a);b.message(f);b.$indicator.fadeIn(e,g);return b};b.message=function(e){b.$indicator.find("i").text(e)};b.hide=function(e,f){e=e||"fast";if(b.$indicator&&b.$indicator.size()){b.$indicator.fadeOut(e,function(){b.$indicator.remove();if(f){f()}})}else{if(f){f()}}return b};return b}(function(){var b=window._l||function(d){return d};function a(k,q){var e=27,n=13,d=$(k),f=true,h={initialVal:"",name:"search",placeholder:"search",classes:"",onclear:function(){},onfirstsearch:null,onsearch:function(r){},minSearchLen:0,escWillClear:true,oninit:function(){}};function j(r){var s=$(this).parent().children("input");s.val("");s.trigger("clear:searchInput");q.onclear()}function p(s,r){$(this).trigger("search:searchInput",r);if(typeof q.onfirstsearch==="function"&&f){f=false;q.onfirstsearch(r)}else{q.onsearch(r)}}function g(){return['<input type="text" name="',q.name,'" placeholder="',q.placeholder,'" ','class="search-query ',q.classes,'" ',"/>"].join("")}function m(){return $(g()).focus(function(r){$(this).select()}).keyup(function(s){s.preventDefault();s.stopPropagation();if(!$(this).val()){$(this).blur()}if(s.which===e&&q.escWillClear){j.call(this,s)}else{var r=$(this).val();if((s.which===n)||(q.minSearchLen&&r.length>=q.minSearchLen)){p.call(this,s,r)}else{if(!r.length){j.call(this,s)}}}}).val(q.initialVal)}function l(){return $(['<span class="search-clear fa fa-times-circle" ','title="',b("clear search (esc)"),'"></span>'].join("")).tooltip({placement:"bottom"}).click(function(r){j.call(this,r)})}function o(){return $(['<span class="search-loading fa fa-spinner fa-spin" ','title="',b("loading..."),'"></span>'].join("")).hide().tooltip({placement:"bottom"})}function i(){d.find(".search-loading").toggle();d.find(".search-clear").toggle()}if(jQuery.type(q)==="string"){if(q==="toggle-loading"){i()}return d}if(jQuery.type(q)==="object"){q=jQuery.extend(true,{},h,q)}return d.addClass("search-input").prepend([m(),l(),o()])}jQuery.fn.extend({searchInput:function c(d){return this.each(function(){return a(this,d)})}})}());(function(){function c(o,n){this.currModeIndex=0;return this._init(o,n)}c.prototype.DATA_KEY="mode-button";c.prototype.defaults={switchModesOnClick:true};c.prototype._init=function j(o,n){n=n||{};this.$element=$(o);this.options=jQuery.extend(true,{},this.defaults,n);if(!n.modes){throw new Error('ModeButton requires a "modes" array')}var q=this;this.$element.click(function p(r){q.callModeFn();if(q.options.switchModesOnClick){q._incModeIndex()}$(this).html(q.options.modes[q.currModeIndex].html)});return this.reset()};c.prototype._incModeIndex=function l(){this.currModeIndex+=1;if(this.currModeIndex>=this.options.modes.length){this.currModeIndex=0}return this};c.prototype._getModeIndex=function f(n){for(var o=0;o<this.options.modes.length;o+=1){if(this.options.modes[o].mode===n){return o}}throw new Error("mode not found: "+n)};c.prototype._setModeByIndex=function m(n){var o=this.options.modes[n];if(!o){throw new Error("mode index not found: "+n)}this.currModeIndex=n;if(o.html){this.$element.html(o.html)}return this};c.prototype.currentMode=function d(){return this.options.modes[this.currModeIndex]};c.prototype.current=function i(){return this.currentMode().mode};c.prototype.getMode=function g(n){if(!n){return this.currentMode()}return this.options.modes[(this._getModeIndex(n))]};c.prototype.hasMode=function b(n){try{return !!this.getMode(n)}catch(o){}return false};c.prototype.setMode=function a(n){return this._setModeByIndex(this._getModeIndex(n))};c.prototype.reset=function h(){this.currModeIndex=0;if(this.options.initialMode){this.currModeIndex=this._getModeIndex(this.options.initialMode)}return this._setModeByIndex(this.currModeIndex)};c.prototype.callModeFn=function e(n){var o=this.getMode(n).onclick;if(o&&jQuery.type(o==="function")){return o.call(this.$element.get(0))}return undefined};jQuery.fn.extend({modeButton:function k(n){if(!this.size()){return this}if(jQuery.type(n)==="object"){return this.map(function(){var r=$(this);r.data("mode-button",new c(r,n));return this})}var p=$(this[0]),o=p.data("mode-button");if(!o){throw new Error("modeButton needs an options object or string name of a function")}if(o&&jQuery.type(n)==="string"){var q=n;if(o&&jQuery.type(o[q])==="function"){return o[q].apply(o,jQuery.makeArray(arguments).slice(1))}}return o}})}());function dropDownSelect(b,c){c=c||((!_.isEmpty(b))?(b[0]):(""));var a=$(['<div class="dropdown-select btn-group">','<button type="button" class="btn btn-default">','<span class="dropdown-select-selected">'+c+"</span>","</button>","</div>"].join("\n"));if(b&&b.length>1){a.find("button").addClass("dropdown-toggle").attr("data-toggle","dropdown").append(' <span class="caret"></span>');a.append(['<ul class="dropdown-menu" role="menu">',_.map(b,function(e){return['<li><a href="javascript:void(0)">',e,"</a></li>"].join("")}).join("\n"),"</ul>"].join("\n"))}function d(g){var h=$(this),f=h.parents(".dropdown-select"),e=h.text();f.find(".dropdown-select-selected").text(e);f.trigger("change.dropdown-select",e)}a.find("a").click(d);return a}(function(){function e(k,j){return this.init(k,j)}e.prototype.DATA_KEY="filter-control";e.prototype.init=function g(k,j){j=j||{filters:[]};this.$element=$(k).addClass("filter-control btn-group");this.options=jQuery.extend(true,{},this.defaults,j);this.currFilter=this.options.filters[0];return this.render()};e.prototype.render=function d(){this.$element.empty().append([this._renderKeySelect(),this._renderOpSelect(),this._renderValueInput()]);return this};e.prototype._renderKeySelect=function a(){var j=this;var k=this.options.filters.map(function(l){return l.key});this.$keySelect=dropDownSelect(k,this.currFilter.key).addClass("filter-control-key").on("change.dropdown-select",function(m,l){j.currFilter=_.findWhere(j.options.filters,{key:l});j.render()._triggerChange()});return this.$keySelect};e.prototype._renderOpSelect=function i(){var j=this,k=this.currFilter.ops;this.$opSelect=dropDownSelect(k,k[0]).addClass("filter-control-op").on("change.dropdown-select",function(m,l){j._triggerChange()});return this.$opSelect};e.prototype._renderValueInput=function c(){var j=this;if(this.currFilter.values){this.$valueSelect=dropDownSelect(this.currFilter.values,this.currFilter.values[0]).on("change.dropdown-select",function(l,k){j._triggerChange()})}else{this.$valueSelect=$("<input/>").addClass("form-control").on("change",function(k,l){j._triggerChange()})}this.$valueSelect.addClass("filter-control-value");return this.$valueSelect};e.prototype.val=function b(){var k=this.$element.find(".filter-control-key .dropdown-select-selected").text(),m=this.$element.find(".filter-control-op .dropdown-select-selected").text(),j=this.$element.find(".filter-control-value"),l=(j.hasClass("dropdown-select"))?(j.find(".dropdown-select-selected").text()):(j.val());return{key:k,op:m,value:l}};e.prototype._triggerChange=function h(){this.$element.trigger("change.filter-control",this.val())};jQuery.fn.extend({filterControl:function f(k){var j=jQuery.makeArray(arguments).slice(1);return this.map(function(){var n=$(this),m=n.data(e.prototype.DATA_KEY);if(jQuery.type(k)==="object"){m=new e(n,k);n.data(e.prototype.DATA_KEY,m)}if(m&&jQuery.type(k)==="string"){var l=m[k];if(jQuery.type(l)==="function"){return l.apply(m,j)}}return this})}})}());(function(){function i(o,n){this.numPages=null;this.currPage=0;return this.init(o,n)}i.prototype.DATA_KEY="pagination";i.prototype.defaults={startingPage:0,perPage:20,totalDataSize:null,currDataSize:null};i.prototype.init=function g(n,o){o=o||{};this.$element=n;this.options=jQuery.extend(true,{},this.defaults,o);this.currPage=this.options.startingPage;if(this.options.totalDataSize!==null){this.numPages=Math.ceil(this.options.totalDataSize/this.options.perPage);if(this.currPage>=this.numPages){this.currPage=this.numPages-1}}this.$element.data(i.prototype.DATA_KEY,this);this._render();return this};function m(n){return $(['<li><a href="javascript:void(0);">',n,"</a></li>"].join(""))}i.prototype._render=function e(){if(this.options.totalDataSize===0){return this}if(this.numPages===1){return this}if(this.numPages>0){this._renderPages();this._scrollToActivePage()}else{this._renderPrevNext()}return this};i.prototype._renderPrevNext=function b(){var o=this,p=m("Prev"),n=m("Next"),q=$("<ul/>").addClass("pagination pagination-prev-next");if(this.currPage===0){p.addClass("disabled")}else{p.click(function(){o.prevPage()})}if((this.numPages&&this.currPage===(this.numPages-1))||(this.options.currDataSize&&this.options.currDataSize<this.options.perPage)){n.addClass("disabled")}else{n.click(function(){o.nextPage()})}this.$element.html(q.append([p,n]));return this.$element};i.prototype._renderPages=function a(){var n=this,q=$("<div>").addClass("pagination-scroll-container"),s=$("<ul/>").addClass("pagination pagination-page-list"),r=function(t){n.goToPage($(this).data("page"))};for(var o=0;o<this.numPages;o+=1){var p=m(o+1).attr("data-page",o).click(r);if(o===this.currPage){p.addClass("active")}s.append(p)}return this.$element.html(q.html(s))};i.prototype._scrollToActivePage=function l(){var p=this.$element.find(".pagination-scroll-container");if(!p.size()){return this}var o=this.$element.find("li.active"),n=p.width()/2;p.scrollLeft(p.scrollLeft()+o.position().left-n);return this};i.prototype.goToPage=function j(n){if(n<=0){n=0}if(this.numPages&&n>=this.numPages){n=this.numPages-1}if(n===this.currPage){return this}this.currPage=n;this.$element.trigger("pagination.page-change",this.currPage);this._render();return this};i.prototype.prevPage=function c(){return this.goToPage(this.currPage-1)};i.prototype.nextPage=function h(){return this.goToPage(this.currPage+1)};i.prototype.page=function f(){return this.currPage};i.create=function k(n,o){return new i(n,o)};jQuery.fn.extend({pagination:function d(o){var n=jQuery.makeArray(arguments).slice(1);if(jQuery.type(o)==="object"){return this.map(function(){i.create($(this),o);return this})}var q=$(this[0]),r=q.data(i.prototype.DATA_KEY);if(r){if(jQuery.type(o)==="string"){var p=r[o];if(jQuery.type(p)==="function"){return p.apply(r,n)}}else{return r}}return undefined}})}());(function(){var g={renameColumns:false,columnNames:[],commentChar:"#",hideCommentRows:false,includePrompts:true,topLeftContent:"Columns:"},s="peek-control.change",t="peek-control.rename",l="peek-control",v="control",f="control-prompt",c="selected",n="disabled",u="button",q="renamable-header",p="column-index",a="column-name";function i(w){if(w.disabled&&jQuery.type(w.disabled)!=="array"){throw new Error('"disabled" must be defined as an array of indeces: '+JSON.stringify(w))}if(w.multiselect&&w.selected&&jQuery.type(w.selected)!=="array"){throw new Error('Mulitselect rows need an array for "selected": '+JSON.stringify(w))}if(!w.label||!w.id){throw new Error("Peek controls need a label and id for each control row: "+JSON.stringify(w))}if(w.disabled&&w.disabled.indexOf(w.selected)!==-1){throw new Error("Selected column is in the list of disabled columns: "+JSON.stringify(w))}return w}function o(x,w){return $("<div/>").addClass(u).text(x.label)}function k(x,w){var y=$("<td/>").html(o(x,w)).attr("data-"+p,w);if(x.disabled&&x.disabled.indexOf(w)!==-1){y.addClass(n)}return y}function e(y,z,w){var x=y.children("."+u);if(y.hasClass(c)){x.html((z.selectedText!==undefined)?(z.selectedText):(z.label))}else{x.html((z.unselectedText!==undefined)?(z.unselectedText):(z.label))}}function h(z,x){var y=k(z,x);if(z.selected===x){y.addClass(c)}e(y,z,x);if(!y.hasClass(n)){y.click(function w(D){var E=$(this);if(!E.hasClass(c)){var A=E.parent().children("."+c).removeClass(c);A.each(function(){e($(this),z,x)});E.addClass(c);e(E,z,x);var C={},B=E.parent().attr("id"),F=E.data(p);C[B]=F;E.parents(".peek").trigger(s,C)}})}return y}function m(z,x){var y=k(z,x);if(z.selected&&z.selected.indexOf(x)!==-1){y.addClass(c)}e(y,z,x);if(!y.hasClass(n)){y.click(function w(D){var E=$(this);E.toggleClass(c);e(E,z,x);var C=E.parent().find("."+c).map(function(G,H){return $(H).data(p)});var B={},A=E.parent().attr("id"),F=jQuery.makeArray(C);B[A]=F;E.parents(".peek").trigger(s,B)})}return y}function j(y,z){var w=[];for(var x=0;x<y;x+=1){w.push(z.multiselect?m(z,x):h(z,x))}return w}function r(y,z,x){var A=$("<tr/>").attr("id",z.id).addClass(v);if(x){var w=$("<td/>").addClass(f).text(z.label+":");A.append(w)}A.append(j(y,z));return A}function b(E){E=jQuery.extend(true,{},g,E);var D=$(this).addClass(l),A=D.find("table"),z=A.find("th").size(),C=A.find("tr").size(),w=A.find("td[colspan]").map(function(H,F){var G=$(this);if(G.text()&&G.text().match(new RegExp("^"+E.commentChar))){return $(this).css("color","grey").parent().get(0)}return null});if(E.hideCommentRows){w.hide();C-=w.size()}if(E.includePrompts){var y=$("<th/>").addClass("top-left").text(E.topLeftContent).attr("rowspan",C);A.find("tr").first().prepend(y)}var B=A.find("th:not(.top-left)").each(function(G,I){var H=$(this),J=H.text().replace(/^\d+\.*/,""),F=E.columnNames[G]||J;H.attr("data-"+a,F).text((G+1)+((F)?("."+F):("")))});if(E.renameColumns){B.addClass(q).click(function x(){var G=$(this),F=G.index()+(E.includePrompts?0:1),I=G.data(a),H=prompt("New column name:",I);if(H!==null&&H!==I){G.text(F+(H?("."+H):"")).data(a,H).attr("data-",a,H);var J=jQuery.makeArray(G.parent().children("th:not(.top-left)").map(function(){return $(this).data(a)}));G.parents(".peek").trigger(t,J)}})}E.controls.forEach(function(G,F){i(G);var H=r(z,G,E.includePrompts);A.find("tbody").append(H)});return this}jQuery.fn.extend({peekControl:function d(w){return this.map(function(){return b.call(this,w)})}})}()); \ No newline at end of file diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/style/blue/base.css --- a/static/style/blue/base.css +++ b/static/style/blue/base.css @@ -1428,7 +1428,7 @@ .pagination-scroll-container .pagination-page-list>li:last-child>a,.pagination-scroll-container .pagination-page-list>li:last-child>span{border-radius:0px} .pagination-scroll-container .pagination-page-list>li>a{float:none;position:static;border:1px solid #BFBFBF;border-width:0px 0px 0px 1px} .peek-control{border-radius:3px;border:1px solid #5f6990} -.peek-control td,th{padding:4px 10px 4px 4px} +.peek-control td,.peek-control th{padding:4px 10px 4px 4px} .peek-control th:last-child{width:100%} .peek-control .top-left{width:10%;white-space:normal;vertical-align:top;text-align:right;font-family:"Lucida Grande",verdana,arial,helvetica,sans-serif;font-weight:normal} .peek-control .renamable-header:hover{background-color:black} @@ -1625,6 +1625,13 @@ .icon-button.link{background:url(../images/silk/link.png) no-repeat;cursor:pointer;float:none;display:inline-block;margin-left:10px} .icon-button.link-broken{background:url(../images/silk/link_break.png) no-repeat;cursor:pointer;float:none;display:inline-block;margin-left:10px} .workflow-invocation-complete{border:solid 1px #6A6;border-left-width:5px;margin:10px 0;padding-left:5px} +.icon-btn{display:inline-block;height:22px;width:22px;text-align:center;line-height:19px;font-size:1.2em;border-radius:3px;border:1px solid #bfbfbf;background-color:#f2f2f2;color:#333;cursor:pointer} +.icon-btn:hover{background-color:white;color:maroon} +.icon-btn.disabled{background-color:transparent;color:#BBB;border-color:#BBB} +.icon-btn-group{display:inline-block}.icon-btn-group .icon-btn:not(:last-child){margin:0px;border-radius:0px;border-right:none} +.icon-btn-group .icon-btn:first-child{margin-right:0px;border-top-left-radius:3px;border-bottom-left-radius:3px} +.icon-btn-group .icon-btn:last-child{margin-left:0px;border-radius:0px 3px 3px 0px} +.icon-btn-group .icon-btn:only-child{margin:0px;border-radius:3px} .list-item{border:1px solid #bfbfbf}.list-item .vertical-spacing{margin-bottom:8px} .list-item .info-section{border-radius:3px;border:1px solid rgba(153,153,153,0.30000000000000004);padding:4px} .list-item .padded{padding:6px 10px 6px 8px} @@ -1642,13 +1649,22 @@ .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} -.icon-btn{display:inline-block;height:22px;width:22px;text-align:center;line-height:19px;font-size:1.2em;border-radius:3px;border:1px solid #bfbfbf;background-color:#f2f2f2;color:#333;cursor:pointer} -.icon-btn:hover{background-color:white;color:maroon} -.icon-btn.disabled{background-color:transparent;color:#BBB;border-color:#BBB} -.icon-btn-group{display:inline-block}.icon-btn-group .icon-btn:not(:last-child){margin:0px;border-radius:0px;border-right:none} -.icon-btn-group .icon-btn:first-child{margin-right:0px;border-top-left-radius:3px;border-bottom-left-radius:3px} -.icon-btn-group .icon-btn:last-child{margin-left:0px;border-radius:0px 3px 3px 0px} -.icon-btn-group .icon-btn:only-child{margin:0px;border-radius:3px} +.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 .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 .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;} +.list-panel .controls .list-actions:after{clear:both} +.list-panel .controls .list-actions .btn{padding-top:2px;padding-bottom:2px;font-size:90%} +.list-panel .list-items .list-item:not(:last-child){border-bottom-width:0px} +.list-panel .empty-message{display:none;margin:0px} .search-input .search-query{width:100%;padding-right:24px} .search-input .search-clear,.search-input .search-loading{position:relative;display:inline-block;float:right;margin-top:-24px;margin-right:4px;font-size:1.4em;line-height:23px;color:grey} .search-input .search-clear:hover{color:#303030} @@ -1857,6 +1873,20 @@ .collection-creator .footer .attributes .collection-name-prompt.validation-warning:before{content:'(required)';margin-right:4px;color:red} .collection-creator .footer .attributes .collection-name{width:50%}.collection-creator .footer .attributes .collection-name.validation-warning{border-color:red} .collection-creator .footer .actions .other-options>*{display:none;margin-left:4px} +.dataset-choice{border:1px solid lightgrey;border-radius:3px;overflow:hidden;padding:10px 8px 8px 8px}.dataset-choice:hover{border-color:black;cursor:pointer}.dataset-choice:hover>*{cursor:pointer} +.dataset-choice .prompt{margin-right:8px}.dataset-choice .prompt:after{content:':'} +.dataset-choice .prompt:empty{display:none} +.dataset-choice .none-selected-msg{color:grey} +.dataset-choice .selected{display:inline-block}.dataset-choice .selected .title{font-weight:bold} +.dataset-choice .selected .subtitle{color:grey}.dataset-choice .selected .subtitle:before{content:'-';margin:0px 4px 0px 4px} +.dataset-choice .selected .subtitle i{font-style:normal}.dataset-choice .selected .subtitle i:not(:last-child):after{content:', '} +.dataset-choice.multi .selected{display:block;font-weight:normal} +.dataset-choice.multi table{width:100%;margin-top:8px;cursor:pointer}.dataset-choice.multi table:hover{border-color:black} +.dataset-choice.multi table tr:nth-child(even){background-color:aliceblue} +.dataset-choice.multi table th{padding:0px;font-weight:normal;font-size:80%;color:grey} +.dataset-choice.multi table th:not(:last-child),.dataset-choice.multi table td:not(:last-child){padding-right:8px} +.dataset-choice.multi table td.cell-name{font-weight:bold} +.dataset-choice-modal .list-panel .controls .title .name{font-size:120%} .toolMenuContainer{color:#000;background:#dfe5f9;min-height:100%;padding:5px 10px} div.toolSectionPad{margin:0;padding:0;height:5px;font-size:0px} div.toolSectionWrapper{margin-bottom:5px} diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/style/src/less/base.less --- a/static/style/src/less/base.less +++ b/static/style/src/less/base.less @@ -551,7 +551,8 @@ border: 1px solid rgb(95, 105, 144); } -.peek-control td, th { +.peek-control td, +.peek-control th { padding: 4px 10px 4px 4px; } @@ -1551,16 +1552,18 @@ padding-left:5px; } -// ==== History styles ==== +// ============================================================================ History @import "sprite-history-states.less"; @import "sprite-history-buttons.less"; +@import "ui/icon-btn.less"; @import "list-item.less"; @import "history.less"; @import "collections.less"; @import "ui/paired-collection-creator.less"; +@import "ui/dataset-choice.less"; // ==== Tool menu styles diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/style/src/less/history.less --- a/static/style/src/less/history.less +++ b/static/style/src/less/history.less @@ -1,89 +1,3 @@ -// trello-ish style -//@icon-btn-size: 18px; -//@icon-btn-margin: 2px; -//@icon-btn-color: #AAA; -//@icon-btn-bg: @btn-default-bg; -//@icon-btn-border: lightgrey; - -// no bg -//@icon-btn-size: 16px; -//@icon-btn-margin: 0px; -//@icon-btn-color: #444; -//@icon-btn-bg: transparent; -//@icon-btn-border: transparent; - -// dark bg -//@icon-btn-size: 16px; -//@icon-btn-margin: 1px; -//@icon-btn-color: @link-color; -//@icon-btn-bg: rgba( 0, 0, 0, 0.1 ); -//@icon-btn-border: transparent; - -// big & dark style -@icon-btn-size: 22px; -@icon-btn-margin: 2px; -@icon-btn-color: @btn-default-color; -//@icon-btn-bg: transparent; -@icon-btn-bg: @btn-default-bg; -@icon-btn-border: @btn-default-border; - -.icon-btn { - display : inline-block; - height : @icon-btn-size; - width : @icon-btn-size; - // center the icon - text-align: center; - line-height: @icon-btn-size - 3; - font-size: 1.2em; - - // colors and borders - border-radius: 3px; - border: 1px solid @icon-btn-border; - background-color: @icon-btn-bg; - color : @icon-btn-color; - - cursor: pointer; - - // tweaks - //TODO: not working - span - //.fa-comment { - // display: inline-block; - // margin-bottom: 4px; - //} -} -.icon-btn:hover { - background-color: white; - color: maroon; -} -.icon-btn.disabled { - background-color: transparent; - color: #BBB; - border-color: #BBB; - //color: @icon-btn-border; -} -.icon-btn-group { - display: inline-block; - .icon-btn:not(:last-child) { - margin: 0px; - border-radius: 0px; - border-right: none; - } - .icon-btn:first-child { - margin-right: 0px; - border-top-left-radius: 3px; - border-bottom-left-radius: 3px; - } - .icon-btn:last-child { - margin-left: 0px; - border-radius: 0px 3px 3px 0px; - } - .icon-btn:only-child { - margin: 0px; - border-radius: 3px; - } -} - - // ---------------------------------------------------------------------------- search bar .search-input { .search-query { diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/style/src/less/list-item.less --- a/static/style/src/less/list-item.less +++ b/static/style/src/less/list-item.less @@ -98,3 +98,69 @@ } } +// ---------------------------------------------------------------------------- generic panel list (of list-items) +.list-panel { + + .controls { + & > *:not(:empty) { + margin-bottom: 8px; + } + .title { + } + .name { + word-wrap: break-word; + font-weight: bold; + } + + .subtitle { + color: grey; + &:not(:empty) { + margin-top: -8px; + } + } + + .actions { + .icon-btn-group(); + float: right; + .icon-btn { + margin-left: @icon-btn-margin; + } + } + + .messages { + [class$=message] { + margin: 0px; + &:not(:last-child) { + margin-bottom: 8px; + } + } + } + + .search { + } + + .list-actions { + display: none; + .clear; + .btn { + padding-top: 2px; + padding-bottom: 2px; + font-size: 90%; + } + } + } + + // display only a top border on all + .list-items { + .list-item { + &:not(:last-child) { + border-bottom-width: 0px; + } + } + } + + .empty-message { + display: none; + margin: 0px; + } +} diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/style/src/less/ui/dataset-choice.less --- /dev/null +++ b/static/style/src/less/ui/dataset-choice.less @@ -0,0 +1,88 @@ +// component to display a dataset choice and activate a modal chooser (single *and* multiple datasets) +.dataset-choice { + border: 1px solid lightgrey; + border-radius: 3px; + overflow: hidden; + padding: 10px 8px 8px 8px; + + &:hover { + border-color: black; + cursor: pointer; + & > * { + cursor: pointer; + } + } + .prompt { + margin-right: 8px; + &:after { + content: ':'; + } + &:empty { + display: none; + } + } + .none-selected-msg { + color: grey; + } + + .selected { + display: inline-block; + + .title { + font-weight: bold; + } + .subtitle { + color: grey; + &:before { + content: '-'; + margin: 0px 4px 0px 4px; + } + i { + font-style: normal; + &:not(:last-child):after { + content: ', '; + } + } + } + } +} + +// component to display a dataset choice and activate a modal chooser (multiple datasets) +.dataset-choice.multi { + .selected { + display: block; + font-weight: normal; + } + + table { + width: 100%; + margin-top: 8px; + cursor: pointer; + + &:hover { + border-color: black; + } + tr:nth-child(even) { + background-color: aliceblue; + } + th { + padding: 0px; + font-weight: normal; + font-size: 80%; + color: grey; + } + th:not(:last-child), + td:not(:last-child) { + padding-right: 8px; + } + td.cell-name { + font-weight: bold; + } + } +} + +// modal allowing single or multiple dataset selection - often activated by .dataset-choice above +.dataset-choice-modal .list-panel .controls .title .name { + font-size: 120%; +} + diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/style/src/less/ui/icon-btn.less --- /dev/null +++ b/static/style/src/less/ui/icon-btn.less @@ -0,0 +1,84 @@ +// trello-ish style +//@icon-btn-size: 18px; +//@icon-btn-margin: 2px; +//@icon-btn-color: #AAA; +//@icon-btn-bg: @btn-default-bg; +//@icon-btn-border: lightgrey; + +// no bg +//@icon-btn-size: 16px; +//@icon-btn-margin: 0px; +//@icon-btn-color: #444; +//@icon-btn-bg: transparent; +//@icon-btn-border: transparent; + +// dark bg +//@icon-btn-size: 16px; +//@icon-btn-margin: 1px; +//@icon-btn-color: @link-color; +//@icon-btn-bg: rgba( 0, 0, 0, 0.1 ); +//@icon-btn-border: transparent; + +// big & dark style +@icon-btn-size: 22px; +@icon-btn-margin: 2px; +@icon-btn-color: @btn-default-color; +//@icon-btn-bg: transparent; +@icon-btn-bg: @btn-default-bg; +@icon-btn-border: @btn-default-border; + +.icon-btn { + display : inline-block; + height : @icon-btn-size; + width : @icon-btn-size; + // center the icon + text-align: center; + line-height: @icon-btn-size - 3; + font-size: 1.2em; + + // colors and borders + border-radius: 3px; + border: 1px solid @icon-btn-border; + background-color: @icon-btn-bg; + color : @icon-btn-color; + + cursor: pointer; + + // tweaks + //TODO: not working - span + //.fa-comment { + // display: inline-block; + // margin-bottom: 4px; + //} +} +.icon-btn:hover { + background-color: white; + color: maroon; +} +.icon-btn.disabled { + background-color: transparent; + color: #BBB; + border-color: #BBB; + //color: @icon-btn-border; +} +.icon-btn-group { + display: inline-block; + .icon-btn:not(:last-child) { + margin: 0px; + border-radius: 0px; + border-right: none; + } + .icon-btn:first-child { + margin-right: 0px; + border-top-left-radius: 3px; + border-bottom-left-radius: 3px; + } + .icon-btn:last-child { + margin-left: 0px; + border-radius: 0px 3px 3px 0px; + } + .icon-btn:only-child { + margin: 0px; + border-radius: 3px; + } +} https://bitbucket.org/galaxy/galaxy-central/commits/ece8ef90a828/ Changeset: ece8ef90a828 User: carlfeberhard Date: 2014-08-26 18:59:59 Summary: (add packed scripts) Affected #: 3 files diff -r 737f78bb4a4581630734a693d6675daaae35b641 -r ece8ef90a8289399bf9faca6a3265696da7e0beb static/scripts/packed/mvc/dataset/dataset-choice.js --- /dev/null +++ b/static/scripts/packed/mvc/dataset/dataset-choice.js @@ -0,0 +1,1 @@ +define(["mvc/dataset/dataset-model","mvc/dataset/dataset-list","mvc/ui/ui-modal","mvc/base-mvc","utils/localization"],function(a,d,f,i,c){function g(k,j,m){function l(p,o){for(var n in o){if(o.hasOwnProperty(n)){if(p[n]!==o[n]){return false}}}return true}return k.filter(function(n){return(!n.deleted&&n.visible)&&(!m||n.collection_type===undefined)&&(l(n,j))})}var b=function(n,j){j=_.defaults(j||{},{datasetsOnly:true,where:{state:"ok"},multiselect:false,selected:[]});j.title=j.title||(j.multiselect?c("Choose datasets:"):c("Choose a dataset:"));var m,o,l,q=jQuery.Deferred(),p=j.filter||g;n=p(n,j.where,j.datasetsOnly);if(!n.length){return q.reject("No matches found")}function k(){q.resolve(o.getSelectedModels().map(function(r){return r.toJSON()}))}if(j.multiselect){l={};l[c("Ok")]=k}m=new f.View({height:"auto",buttons:l,closing_events:true,closing_callback:function(){q.resolve(null)},body:['<div class="list-panel"></div>'].join("")});m.$(".modal-header").remove();m.$(".modal-footer").css("margin-top","0px");o=new d.DatasetList({title:j.title,subtitle:j.subtitle||c(["Click the checkboxes on the right to select datasets. ","Click the datasets names to see their details. "].join("")),el:m.$body.find(".list-panel"),selecting:true,selected:j.selected,collection:new a.DatasetAssociationCollection(n)});o.once("rendered:initial",function(){m.show();m.$el.addClass("dataset-choice-modal")});if(!j.multiselect){o.on("rendered",function(){o.$(".list-actions").hide()});o.on("view:selected",function(r){q.resolve([r.model.toJSON()])})}o.render(0);return q.always(function(){m.hide()})};var e=Backbone.View.extend(i.LoggableMixin).extend({className:"dataset-choice",initialize:function(j){this.debug(this+"(DatasetChoice).initialize:",j);this.label=j.label!==undefined?c(j.label):"";this.where=j.where;this.datasetsOnly=j.datasetsOnly!==undefined?j.datasetsOnly:true;this.datasetJSON=j.datasetJSON||[];this.selected=j.selected||[];this._setUpListeners()},_setUpListeners:function(){},render:function(){var j=this.toJSON();this.$el.html(this._template(j));this.$(".selected").replaceWith(this._renderSelected(j));return this},_template:function(j){return _.template(["<label>",'<span class="prompt"><%= json.label %></span>','<div class="selected"></div>',"</label>"].join(""),{json:j})},_renderSelected:function(j){if(j.selected.length){return $(_.template(['<div class="selected">','<span class="title"><%= selected.hid %>: <%= selected.name %></span>','<span class="subtitle">',"<i><%= selected.misc_blurb %></i>","<i>",c("format")+": ","<%= selected.data_type %></i>","<i><%= selected.misc_info %></i>","</span>","</div>"].join(""),{selected:j.selected[0]}))}return $(['<span class="none-selected-msg">(',c("click to select a dataset"),")</span>"].join(""))},toJSON:function(){var j=this;return{label:j.label,datasets:j.datasetJSON,selected:_.compact(_.map(j.selected,function(k){return _.findWhere(j.datasetJSON,{id:k})}))}},events:{click:"chooseWithModal"},chooseWithModal:function(){var j=this;return this._createModal().done(function(k){if(k){j.selected=_.pluck(k,"id");j.trigger("selected",j,k);j.render()}else{j.trigger("cancelled",j)}}).fail(function(){j.trigger("error",j,arguments)})},_createModal:function(){return new b(this.datasetJSON,this._getModalOptions())},_getModalOptions:function(){return{title:this.label,multiselect:false,selected:this.selected,where:this.where,datasetsOnly:this.datasetsOnly}},toString:function(){return"DatasetChoice("+this.selected+")"}});var h=e.extend({className:e.prototype.className+" multi",cells:{hid:c("History #"),name:c("Name"),misc_blurb:c("Summary"),data_type:c("Format"),genome_build:c("Genome"),tags:c("Tags"),annotation:c("Annotation")},initialize:function(j){this.showHeaders=j.showHeaders!==undefined?j.showHeaders:true;this.cells=j.cells||this.cells;e.prototype.initialize.call(this,j)},_renderSelected:function(j){if(j.selected.length){return $(_.template(['<table class="selected">',"<% if( json.showHeaders ){ %>","<thead><tr>","<% _.map( json.cells, function( val, key ){ %>","<th><%= val %></th>","<% }); %>","</tr></thead>","<% } %>","<tbody>","<% _.map( json.selected, function( selected ){ %>","<tr>","<% _.map( json.cells, function( val, key ){ %>",'<td class="cell-<%= key %>"><%= selected[ key ] %></td>',"<% }) %>","</tr>","<% }); %>","</tbody>","</table>"].join(""),{json:j}))}return $(['<span class="none-selected-msg">(',c("click to select a dataset"),")</span>"].join(""))},toJSON:function(){return _.extend(e.prototype.toJSON.call(this),{showHeaders:this.showHeaders,cells:this.cells})},_getModalOptions:function(){return _.extend(e.prototype._getModalOptions.call(this),{multiselect:true})},toString:function(){return"DatasetChoice("+this.selected+")"}});return{DatasetChoiceModal:b,DatasetChoice:e,MultiDatasetChoice:h}}); \ No newline at end of file diff -r 737f78bb4a4581630734a693d6675daaae35b641 -r ece8ef90a8289399bf9faca6a3265696da7e0beb static/scripts/packed/mvc/dataset/dataset-list.js --- /dev/null +++ b/static/scripts/packed/mvc/dataset/dataset-list.js @@ -0,0 +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}}); \ No newline at end of file diff -r 737f78bb4a4581630734a693d6675daaae35b641 -r ece8ef90a8289399bf9faca6a3265696da7e0beb static/scripts/packed/mvc/dataset/list-panel.js --- /dev/null +++ b/static/scripts/packed/mvc/dataset/list-panel.js @@ -0,0 +1,1 @@ +define(["mvc/base-mvc","utils/localization"],function(a,b){var c=Backbone.View.extend(a.LoggableMixin).extend({viewClass:a.ListItemView,tagName:"div",className:"list-panel",fxSpeed:"fast",emptyMsg:b("This list is empty"),noneFoundMsg:b("No matching items found"),initialize:function(d,e){d=d||{};if(d.logger){this.logger=d.logger}this.log(this+".initialize:",d);this.fxSpeed=_.has(d,"fxSpeed")?(d.fxSpeed):(this.fxSpeed);this.filters=[];this.searchFor=d.searchFor||"";this.indicator=new LoadingIndicator(this.$el);this.selecting=(d.selecting!==undefined)?d.selecting:true;this.selected=d.selected||[];this.lastSelected=null;this.viewClass=d.viewClass||this.viewClass;this.views=[];this.collection=d.collection||(new Backbone.Collection([]));this.filters=d.filters||[];this.title=d.title||"";this.subtitle=d.subtitle||"";this._setUpListeners()},_setUpListeners:function(){this.on("error",function(e,h,d,g,f){console.error(e,h,d,g,f)},this);this.on("loading",function(){this._showLoadingIndicator("loading...",40)},this);this.on("loading-done",function(){this._hideLoadingIndicator(40)},this);this.once("rendered",function(){this.trigger("rendered:initial",this)},this);if(this.logger){this.on("all",function(d){this.log(this+"",arguments)},this)}this._setUpCollectionListeners();this._setUpViewListeners();return this},freeViews:function(){this.views=[];return this},_setUpCollectionListeners:function(){this.collection.on("reset",function(){this.renderItems()},this);this.collection.on("add",this.addItemView,this);this.collection.on("remove",this.removeItemView,this);if(this.logger){this.collection.on("all",function(d){this.info(this+"(collection)",arguments)},this)}return this},_setUpViewListeners:function(){this.on("view:selected",function(d,e){if(e&&e.shiftKey&&this.lastSelected){var f=_.find(this.views,function(g){return g.model.id===this.lastSelected});if(f){this.selectRange(d,f)}}this.selected.push(d.model.id);this.lastSelected=d.model.id},this)},render:function(e){var d=this._buildNewRender();this._setUpBehaviors(d);this._queueNewRender(d,e);return this},_buildNewRender:function(){var e=this.model?this.model.toJSON():{},d=$(this.templates.el(e,this));this._renderTitle(d);this._renderSubtitle(d);this._renderSearch(d);this.renderItems(d);return d},_renderTitle:function(d){},_renderSubtitle:function(d){},_queueNewRender:function(e,f){f=(f===undefined)?(this.fxSpeed):(f);var d=this;$(d).queue("fx",[function(g){this.$el.fadeOut(f,g)},function(g){d._swapNewRender(e);g()},function(g){this.$el.fadeIn(f,g)},function(g){d.trigger("rendered",d);g()}])},_swapNewRender:function(d){this.$el.empty().attr("class",this.className).append(d.children());if(this.selecting){this.showSelectors(0)}return this},_setUpBehaviors:function(d){d=d||this.$el;d.find(".controls [title]").tooltip({placement:"bottom"});return this},$scrollContainer:function(){return this.$el.parent().parent()},$list:function(d){return(d||this.$el).find(".list-items")},$messages:function(d){return(d||this.$el).find(".message-container")},$emptyMessage:function(d){return(d||this.$el).find(".empty-message")},renderItems:function(g){g=g||this.$el;var h=this,e=[];var f=this.$list(g),d=this._filterCollection().map(function(j){var i=h._createItemView(j);e.push(i);return i.render(0).$el});this.debug(d);this.debug(e);f.empty();if(d.length){f.append(d);this.$emptyMessage(g).hide()}else{this._renderEmptyMessage(g).show()}this.views=e;return e},_filterCollection:function(){var d=this;return d.collection.filter(_.bind(d._filterItem,d))},_filterItem:function(d){var e=this;return(_.every(e.filters.map(function(f){return f.call(d)})))&&(!e.searchFor||d.matchesAll(e.searchFor))},_createItemView:function(f){var g=this._getItemViewClass(f),e=_.extend(this._getItemViewOptions(f),{model:f}),d=new g(e);this._setUpItemViewListeners(d);return d},_getItemViewClass:function(d){return this.viewClass},_getItemViewOptions:function(d){return{fxSpeed:this.fxSpeed,expanded:false,selectable:this.selecting,selected:_.contains(this.selected,d.id),draggable:this.dragging}},_setUpItemViewListeners:function(d){var e=this;d.on("all",function(){var f=Array.prototype.slice.call(arguments,0);f[0]="view:"+f[0];e.trigger.apply(e,f)});return this},_renderEmptyMessage:function(d){var e=this.searchFor?this.noneFoundMsg:this.emptyMsg;return this.$emptyMessage(d).text(e)},expandAll:function(){_.each(this.views,function(d){d.expand()})},collapseAll:function(){_.each(this.views,function(d){d.collapse()})},addItemView:function(f,h,e){this.log(this+".addItemView:",f);var g=this;if(!this._filterItem(f)){return undefined}var d=g._createItemView(f);this.views.push(d);$(d).queue("fx",[function(i){g.$emptyMessage().fadeOut(g.fxSpeed,i)},function(i){g.$list().append(d.render().$el);i()}]);return d},removeItemView:function(f,h,e){this.log(this+".removeItemView:",f);var g=this,d=g.viewFromModel(f);if(!d){return undefined}this.views=_.without(this.views,d);d.remove();if(!this.views.length){g._renderEmptyMessage().fadeIn(g.fxSpeed)}return d},viewFromModel:function(e){for(var f=0;f<this.views.length;f++){var d=this.views[f];if(d.model===e){return d}}return undefined},viewsWhereModel:function(d){return this.views.filter(function(e){var g=e.model.toJSON();for(var f in d){if(d.hasOwnPropery(f)){if(g[f]!==e.model.properties[f]){return false}}}return true})},viewRange:function(g,f){if(g===f){return(g)?([g]):([])}var e=this.views.indexOf(g),d=this.views.indexOf(f);if(e===-1||d===-1){if(e===d){return[]}return(e===-1)?([f]):([g])}return(e<d)?this.views.slice(e,d+1):this.views.slice(d,e+1)},_renderSearch:function(d){d.find(".controls .search-input").searchInput({placeholder:"search",initialVal:this.searchFor,onfirstsearch:_.bind(this._firstSearch,this),onsearch:_.bind(this.searchItems,this),onclear:_.bind(this.clearSearch,this)});return d},_firstSearch:function(d){this.log("onFirstSearch",d);return this.searchItems(d)},searchItems:function(d){this.searchFor=d;this.trigger("search:searching",d,this);this.renderItems();return this},clearSearch:function(d){this.searchFor="";this.trigger("search:clear",this);this.renderItems();return this},showSelectors:function(d){d=(d!==undefined)?(d):(this.fxSpeed);this.selecting=true;this.$(".list-actions").slideDown(d);_.each(this.views,function(e){e.showSelector(d)});this.selected=[];this.lastSelected=null},hideSelectors:function(d){d=(d!==undefined)?(d):(this.fxSpeed);this.selecting=false;this.$(".list-actions").slideUp(d);_.each(this.views,function(e){e.hideSelector(d)});this.selected=[];this.lastSelected=null},toggleSelectors:function(){if(!this.selecting){this.showSelectors()}else{this.hideSelectors()}},selectAll:function(d){_.each(this.views,function(e){e.select(d)})},deselectAll:function(d){this.lastSelected=null;_.each(this.views,function(e){e.deselect(d)})},selectRange:function(f,e){var d=this.viewRange(f,e);_.each(d,function(g){g.select()});return d},getSelectedViews:function(){return _.filter(this.views,function(d){return d.selected})},getSelectedModels:function(){return new this.collection.constructor(_.map(this.getSelectedViews(),function(d){return d.model}))},_showLoadingIndicator:function(e,d,f){d=(d!==undefined)?(d):(this.fxSpeed);if(!this.indicator){this.indicator=new LoadingIndicator(this.$el,this.$el.parent())}if(!this.$el.is(":visible")){this.indicator.show(0,f)}else{this.$el.fadeOut(d);this.indicator.show(e,d,f)}},_hideLoadingIndicator:function(d,e){d=(d!==undefined)?(d):(this.fxSpeed);if(this.indicator){this.indicator.hide(d,e)}},scrollPosition:function(){return this.$scrollContainer().scrollTop()},scrollTo:function(d){this.$scrollContainer().scrollTop(d);return this},scrollToTop:function(){this.$scrollContainer().scrollTop(0);return this},scrollToItem:function(d){if(!d){return}var e=d.$el.offset().top;this.$scrollContainer().scrollTop(e)},events:{"click .select-all":"selectAll","click .deselect-all":"deselectAll"},toString:function(){return"ListPanel("+this.collection+")"}});c.prototype.templates=(function(){var d=a.wrapTemplate(["<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">',b("All"),"</button>",'<button class="deselect-all btn btn-default"','data-mode="select">',b("None"),"</button>","</div>","</div>","</div>",'<div class="list-items"></div>','<div class="empty-message infomessagesmall"></div>',"</div>"]);return{el:d}}());return{ListPanel:c}}); \ No newline at end of file Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.
participants (1)
-
commits-noreply@bitbucket.org